aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/doc/src/asn1_getting_started.xml2
-rw-r--r--lib/asn1/doc/src/asn1_introduction.xml2
-rw-r--r--lib/asn1/doc/src/notes.xml20
-rw-r--r--lib/asn1/src/asn1_db.erl4
-rw-r--r--lib/asn1/src/asn1ct.erl3
-rw-r--r--lib/asn1/test/asn1_test_lib.erl53
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/Makefile3
-rw-r--r--lib/common_test/doc/src/common_test_app.xml30
-rw-r--r--lib/common_test/doc/src/ct.xml122
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml94
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml84
-rw-r--r--lib/common_test/doc/src/ct_ssh.xml106
-rw-r--r--lib/common_test/doc/src/ct_telnet.xml4
-rw-r--r--lib/common_test/doc/src/ct_testspec.xml84
-rw-r--r--lib/common_test/doc/src/event_handler_chapter.xml6
-rw-r--r--lib/common_test/doc/src/introduction.xml2
-rw-r--r--lib/common_test/doc/src/notes.xml212
-rw-r--r--lib/common_test/doc/src/ref_man.xml1
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml6
-rw-r--r--lib/common_test/doc/src/write_test_chapter.xml60
-rw-r--r--lib/common_test/src/Makefile1
-rw-r--r--lib/common_test/src/common_test.app.src3
-rw-r--r--lib/common_test/src/ct.erl115
-rw-r--r--lib/common_test/src/ct_default_gl.erl83
-rw-r--r--lib/common_test/src/ct_framework.erl177
-rw-r--r--lib/common_test/src/ct_gen_conn.erl10
-rw-r--r--lib/common_test/src/ct_groups.erl16
-rw-r--r--lib/common_test/src/ct_hooks.erl143
-rw-r--r--lib/common_test/src/ct_logs.erl108
-rw-r--r--lib/common_test/src/ct_make.erl2
-rw-r--r--lib/common_test/src/ct_run.erl44
-rw-r--r--lib/common_test/src/ct_snmp.erl2
-rw-r--r--lib/common_test/src/ct_telnet.erl90
-rw-r--r--lib/common_test/src/ct_testspec.erl37
-rw-r--r--lib/common_test/src/ct_util.erl18
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/src/cth_conn_log.erl10
-rw-r--r--lib/common_test/src/cth_log_redirect.erl30
-rw-r--r--lib/common_test/src/cth_surefire.erl56
-rw-r--r--lib/common_test/src/erl2html2.erl2
-rw-r--r--lib/common_test/src/test_server.erl12
-rw-r--r--lib/common_test/src/test_server_ctrl.erl118
-rw-r--r--lib/common_test/src/test_server_gl.erl14
-rw-r--r--lib/common_test/src/test_server_io.erl6
-rw-r--r--lib/common_test/test/Makefile3
-rw-r--r--lib/common_test/test/ct_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_auto_compile_SUITE.erl1
-rw-r--r--lib/common_test/test/ct_config_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_error_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl1203
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_hook_callbacks_SUITE.erl62
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/config_clash_SUITE.erl43
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_end_config_SUITE.erl51
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_config_SUITE.erl54
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_suite_config_SUITE.erl39
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl124
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_suite_cth.erl34
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fallback_cth.erl81
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl8
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/repeat_SUITE.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/seq_SUITE.erl45
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip.spec8
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_case_SUITE.erl106
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_cth.erl182
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_fail_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_group_SUITE.erl64
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_init_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_init_tc_cth.erl79
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_req_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl42
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl42
-rw-r--r--lib/common_test/test/ct_log_SUITE.erl134
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/ns.erl6
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE.erl7
-rw-r--r--lib/common_test/test/ct_surefire_SUITE.erl131
-rw-r--r--lib/common_test/test/ct_surefire_SUITE_data/skip_one_case.spec2
-rw-r--r--lib/common_test/test/ct_surefire_SUITE_data/skip_one_suite.spec2
-rw-r--r--lib/common_test/test/ct_test_server_if_1_SUITE.erl3
-rw-r--r--lib/common_test/test/ct_test_support.erl26
-rw-r--r--lib/common_test/test/ct_testspec_2_SUITE.erl82
-rw-r--r--lib/common_test/test_server/ts_run.erl2
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/compile.xml10
-rw-r--r--lib/compiler/doc/src/notes.xml126
-rw-r--r--lib/compiler/doc/src/ref_man.xml2
-rw-r--r--lib/compiler/src/beam_block.erl108
-rw-r--r--lib/compiler/src/beam_bsm.erl31
-rw-r--r--lib/compiler/src/beam_dead.erl7
-rw-r--r--lib/compiler/src/beam_flatten.erl1
-rw-r--r--lib/compiler/src/beam_jump.erl22
-rw-r--r--lib/compiler/src/beam_split.erl3
-rw-r--r--lib/compiler/src/beam_utils.erl73
-rw-r--r--lib/compiler/src/beam_validator.erl8
-rw-r--r--lib/compiler/src/compile.erl65
-rw-r--r--lib/compiler/src/sys_core_fold.erl13
-rw-r--r--lib/compiler/test/beam_block_SUITE.erl49
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl19
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl19
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl25
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl26
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl16
-rw-r--r--lib/compiler/test/guard_SUITE.erl13
-rw-r--r--lib/compiler/test/lc_SUITE.erl9
-rw-r--r--lib/compiler/test/match_SUITE.erl13
-rw-r--r--lib/compiler/test/warnings_SUITE.erl28
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/c_src/crypto.c171
-rw-r--r--lib/crypto/doc/src/crypto.xml8
-rw-r--r--lib/crypto/doc/src/notes.xml102
-rw-r--r--lib/crypto/src/crypto.erl45
-rw-r--r--lib/crypto/test/crypto_SUITE.erl35
-rw-r--r--lib/crypto/test/old_crypto_SUITE.erl47
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/doc/src/Makefile2
-rw-r--r--lib/debugger/doc/src/i.xml4
-rw-r--r--lib/debugger/doc/src/notes.xml16
-rw-r--r--lib/debugger/src/dbg_iserver.erl40
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl13
-rw-r--r--lib/debugger/src/dbg_wx_view.erl12
-rw-r--r--lib/debugger/src/dbg_wx_win.erl2
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/RELEASE_NOTES2
-rw-r--r--lib/dialyzer/doc/manual.txt2
-rw-r--r--lib/dialyzer/doc/src/book.xml2
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml828
-rw-r--r--lib/dialyzer/doc/src/dialyzer_chapter.xml303
-rw-r--r--lib/dialyzer/doc/src/notes.xml130
-rw-r--r--lib/dialyzer/doc/src/part.xml3
-rw-r--r--lib/dialyzer/doc/src/ref_man.xml3
-rw-r--r--lib/dialyzer/src/dialyzer.app.src4
-rw-r--r--lib/dialyzer/src/dialyzer.erl18
-rw-r--r--lib/dialyzer/src/dialyzer.hrl2
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl161
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl15
-rw-r--r--lib/dialyzer/src/dialyzer_callgraph.erl96
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl14
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl4
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl206
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl101
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl159
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl7
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl140
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl35
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl99
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl141
-rw-r--r--lib/dialyzer/test/Makefile1
-rw-r--r--lib/dialyzer/test/abstract_SUITE.erl106
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/dialyzer_common.erl11
-rw-r--r--lib/dialyzer/test/map_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/map_in_guard24
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/opaque_key8
-rw-r--r--lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/a.erl9
-rw-r--r--lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/b.erl3
-rw-r--r--lib/dialyzer/test/map_SUITE_data/src/opaque_bif.erl13
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/array4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/dict18
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/ets6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/my_queue2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/opaque2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/para10
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/queue6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/rec4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/simple46
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/timer4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/union8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/weird6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/wings8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_ig_moves.erl83
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_vectors.erl136
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/cerl.erl4602
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/core_parse.hrl122
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl180
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_dataflow.erl3802
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl2494
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl5741
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl26
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl18
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl14
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl19
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl4
-rw-r--r--lib/dialyzer/test/options2_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/options2_SUITE_data/results/unknown_type2
-rw-r--r--lib/dialyzer/test/options2_SUITE_data/src/unknown_type.erl7
-rw-r--r--lib/dialyzer/test/plt_SUITE.erl47
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/chars4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/guards2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/anno.erl18
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/chars.erl32
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ms.erl8
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/diameter/doc/src/diameter.xml155
-rw-r--r--lib/diameter/doc/src/diameter_app.xml39
-rw-r--r--lib/diameter/doc/src/diameter_codec.xml56
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml69
-rw-r--r--lib/diameter/doc/src/diameter_examples.xml1
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml2
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml9
-rw-r--r--lib/diameter/doc/src/diameterc.xml6
-rw-r--r--lib/diameter/doc/src/notes.xml74
-rw-r--r--lib/diameter/examples/code/relay.erl4
-rw-r--r--lib/diameter/src/Makefile2
-rw-r--r--lib/diameter/src/base/diameter.erl3
-rw-r--r--lib/diameter/src/base/diameter_config.erl5
-rw-r--r--lib/diameter/src/base/diameter_lib.erl24
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl71
-rw-r--r--lib/diameter/src/base/diameter_service.erl18
-rw-r--r--lib/diameter/src/base/diameter_sup.erl4
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl283
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl28
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl17
-rw-r--r--lib/diameter/src/diameter.appup.src10
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl76
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl104
-rw-r--r--lib/diameter/test/diameter_codec_test.erl2
-rw-r--r--lib/diameter/test/diameter_relay_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl7
-rw-r--r--lib/diameter/test/diameter_util.erl22
-rw-r--r--lib/diameter/vsn.mk4
-rw-r--r--lib/edoc/doc/overview.edoc10
-rw-r--r--lib/edoc/doc/src/notes.xml30
-rw-r--r--lib/edoc/include/edoc_doclet.hrl2
-rw-r--r--lib/edoc/src/edoc.erl2
-rw-r--r--lib/edoc/src/edoc.hrl2
-rw-r--r--lib/edoc/src/edoc_data.erl2
-rw-r--r--lib/edoc/src/edoc_doclet.erl2
-rw-r--r--lib/edoc/src/edoc_extract.erl16
-rw-r--r--lib/edoc/src/edoc_layout.erl2
-rw-r--r--lib/edoc/src/edoc_lib.erl4
-rw-r--r--lib/edoc/src/edoc_macros.erl2
-rw-r--r--lib/edoc/src/edoc_refs.erl2
-rw-r--r--lib/edoc/src/edoc_report.erl2
-rw-r--r--lib/edoc/src/edoc_run.erl2
-rw-r--r--lib/edoc/src/edoc_tags.erl13
-rw-r--r--lib/edoc/src/edoc_types.erl2
-rw-r--r--lib/edoc/src/edoc_types.hrl2
-rw-r--r--lib/edoc/src/edoc_wiki.erl2
-rw-r--r--lib/edoc/src/otpsgml_layout.erl2
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/doc/src/eldap.xml22
-rw-r--r--lib/eldap/test/Makefile2
-rw-r--r--lib/eldap/test/eldap.cover3
-rw-r--r--lib/erl_docgen/doc/src/notes.xml34
-rwxr-xr-xlib/erl_docgen/priv/bin/xref_mod_app.escript2
-rw-r--r--lib/erl_docgen/priv/dtd/erlref.dtd2
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl4
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl153
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/doc/src/book.xml11
-rw-r--r--lib/erl_interface/doc/src/ei.xml1181
-rw-r--r--lib/erl_interface/doc/src/ei_connect.xml1057
-rw-r--r--lib/erl_interface/doc/src/ei_users_guide.xml715
-rw-r--r--lib/erl_interface/doc/src/erl_call.xml221
-rw-r--r--lib/erl_interface/doc/src/erl_connect.xml803
-rw-r--r--lib/erl_interface/doc/src/erl_error.xml94
-rw-r--r--lib/erl_interface/doc/src/erl_eterm.xml795
-rw-r--r--lib/erl_interface/doc/src/erl_format.xml102
-rw-r--r--lib/erl_interface/doc/src/erl_global.xml132
-rw-r--r--lib/erl_interface/doc/src/erl_interface.xml209
-rw-r--r--lib/erl_interface/doc/src/erl_malloc.xml181
-rw-r--r--lib/erl_interface/doc/src/erl_marshal.xml287
-rw-r--r--lib/erl_interface/doc/src/fascicules.xml24
-rw-r--r--lib/erl_interface/doc/src/notes.xml61
-rw-r--r--lib/erl_interface/doc/src/part.xml2
-rw-r--r--lib/erl_interface/doc/src/part_erl_interface.xml5
-rw-r--r--lib/erl_interface/doc/src/ref_man.xml18
-rw-r--r--lib/erl_interface/doc/src/ref_man_ei.xml13
-rw-r--r--lib/erl_interface/doc/src/ref_man_erl_interface.xml5
-rw-r--r--lib/erl_interface/doc/src/registry.xml869
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c44
-rw-r--r--lib/erl_interface/src/misc/ei_portio.h2
-rw-r--r--lib/erl_interface/src/prog/erl_start.c73
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/eunit/doc/src/notes.xml33
-rw-r--r--lib/eunit/include/eunit.hrl6
-rw-r--r--lib/eunit/src/eunit.erl2
-rw-r--r--lib/eunit/src/eunit_autoexport.erl2
-rw-r--r--lib/eunit/src/eunit_data.erl2
-rw-r--r--lib/eunit/src/eunit_lib.erl2
-rw-r--r--lib/eunit/src/eunit_proc.erl2
-rw-r--r--lib/eunit/src/eunit_serial.erl2
-rw-r--r--lib/eunit/src/eunit_server.erl2
-rw-r--r--lib/eunit/src/eunit_striptests.erl2
-rw-r--r--lib/eunit/src/eunit_surefire.erl2
-rw-r--r--lib/eunit/src/eunit_test.erl2
-rw-r--r--lib/eunit/src/eunit_tests.erl2
-rw-r--r--lib/eunit/src/eunit_tty.erl2
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/gs/doc/src/Makefile2
-rw-r--r--lib/gs/doc/src/notes.xml18
-rw-r--r--lib/gs/vsn.mk2
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl16
-rw-r--r--lib/hipe/arm/hipe_arm_registers.erl8
-rw-r--r--lib/hipe/arm/hipe_rtl_to_arm.erl9
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl6
-rw-r--r--lib/hipe/cerl/erl_types.erl403
-rw-r--r--lib/hipe/doc/src/notes.xml113
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl28
-rw-r--r--lib/hipe/icode/hipe_icode.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_call_elim.erl3
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl8
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl14
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl103
-rw-r--r--lib/hipe/main/hipe.erl91
-rw-r--r--lib/hipe/main/hipe.hrl.src12
-rw-r--r--lib/hipe/main/hipe_main.erl2
-rw-r--r--lib/hipe/ppc/hipe_ppc.erl12
-rw-r--r--lib/hipe/ppc/hipe_ppc_assemble.erl7
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl37
-rw-r--r--lib/hipe/sparc/hipe_rtl_to_sparc.erl40
-rw-r--r--lib/hipe/sparc/hipe_sparc_registers.erl8
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_num_bif.erl217
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl48
-rw-r--r--lib/hipe/test/hipe_SUITE.erl6
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl2
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl14
-rw-r--r--lib/hipe/test/opt_verify_SUITE.erl39
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_x86_postpass.erl3
-rw-r--r--lib/ic/doc/src/Makefile2
-rw-r--r--lib/ic/doc/src/notes.xml24
-rw-r--r--lib/ic/src/ic_codegen.erl8
-rw-r--r--lib/ic/vsn.mk2
-rw-r--r--lib/inets/doc/src/http_server.xml36
-rw-r--r--lib/inets/doc/src/http_uri.xml4
-rw-r--r--lib/inets/doc/src/httpc.xml8
-rw-r--r--lib/inets/doc/src/httpd.xml18
-rw-r--r--lib/inets/doc/src/mod_auth.xml2
-rw-r--r--lib/inets/doc/src/mod_esi.xml4
-rw-r--r--lib/inets/doc/src/notes.xml218
-rw-r--r--lib/inets/src/ftp/ftp.erl181
-rw-r--r--lib/inets/src/ftp/ftp_progress.erl26
-rw-r--r--lib/inets/src/ftp/ftp_response.erl18
-rw-r--r--lib/inets/src/http_client/httpc.erl102
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl768
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl51
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl4
-rw-r--r--lib/inets/src/http_client/httpc_request.erl6
-rw-r--r--lib/inets/src/http_client/httpc_response.erl38
-rw-r--r--lib/inets/src/http_lib/http_internal.hrl5
-rw-r--r--lib/inets/src/http_lib/http_request.erl18
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl12
-rw-r--r--lib/inets/src/http_server/httpd_example.erl11
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl17
-rw-r--r--lib/inets/src/http_server/httpd_response.erl2
-rw-r--r--lib/inets/src/http_server/mod_auth_server.erl2
-rw-r--r--lib/inets/src/http_server/mod_esi.erl66
-rw-r--r--lib/inets/src/inets_app/inets.appup.src6
-rw-r--r--lib/inets/src/inets_app/inets_lib.erl2
-rw-r--r--lib/inets/test/ftp_SUITE.erl105
-rw-r--r--lib/inets/test/ftp_format_SUITE.erl13
-rw-r--r--lib/inets/test/http_format_SUITE.erl2
-rw-r--r--lib/inets/test/httpc_SUITE.erl108
-rw-r--r--lib/inets/test/httpd_SUITE.erl67
-rw-r--r--lib/inets/test/inets_SUITE.erl14
-rw-r--r--lib/inets/test/inets_socketwrap_SUITE.erl2
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl38
-rw-r--r--lib/inets/vsn.mk4
-rw-r--r--lib/jinterface/doc/src/Makefile2
-rw-r--r--lib/jinterface/doc/src/notes.xml16
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/app.xml6
-rw-r--r--lib/kernel/doc/src/application.xml6
-rw-r--r--lib/kernel/doc/src/auth.xml4
-rw-r--r--lib/kernel/doc/src/code.xml33
-rw-r--r--lib/kernel/doc/src/erl_boot_server.xml4
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml6
-rw-r--r--lib/kernel/doc/src/error_logger.xml30
-rw-r--r--lib/kernel/doc/src/file.xml36
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml12
-rw-r--r--lib/kernel/doc/src/gen_udp.xml6
-rw-r--r--lib/kernel/doc/src/heart.xml19
-rw-r--r--lib/kernel/doc/src/inet.xml45
-rw-r--r--lib/kernel/doc/src/init_stub.xml2
-rw-r--r--lib/kernel/doc/src/kernel_app.xml22
-rw-r--r--lib/kernel/doc/src/net_kernel.xml48
-rw-r--r--lib/kernel/doc/src/notes.xml197
-rw-r--r--lib/kernel/doc/src/os.xml43
-rw-r--r--lib/kernel/doc/src/rpc.xml20
-rw-r--r--lib/kernel/doc/src/zlib_stub.xml2
-rw-r--r--lib/kernel/include/dist_util.hrl8
-rw-r--r--lib/kernel/src/code_server.erl41
-rw-r--r--lib/kernel/src/dist_util.erl71
-rw-r--r--lib/kernel/src/erl_epmd.erl6
-rw-r--r--lib/kernel/src/error_logger.erl10
-rw-r--r--lib/kernel/src/file.erl2
-rw-r--r--lib/kernel/src/gen_sctp.erl2
-rw-r--r--lib/kernel/src/gen_tcp.erl2
-rw-r--r--lib/kernel/src/gen_udp.erl2
-rw-r--r--lib/kernel/src/global_group.erl2
-rw-r--r--lib/kernel/src/heart.erl15
-rw-r--r--lib/kernel/src/inet.erl11
-rw-r--r--lib/kernel/src/inet6_tcp_dist.erl7
-rw-r--r--lib/kernel/src/inet_int.hrl1
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl31
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/src/kernel.appup.src6
-rw-r--r--lib/kernel/src/net_kernel.erl128
-rw-r--r--lib/kernel/src/os.erl103
-rw-r--r--lib/kernel/src/rpc.erl16
-rw-r--r--lib/kernel/test/code_SUITE.erl182
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl163
-rw-r--r--lib/kernel/test/error_logger_SUITE.erl15
-rw-r--r--lib/kernel/test/file_SUITE.erl54
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl148
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl21
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl41
-rw-r--r--lib/kernel/test/init_SUITE.erl61
-rw-r--r--lib/kernel/test/os_SUITE.erl73
-rw-r--r--lib/kernel/test/os_SUITE_data/Makefile.src8
-rw-r--r--lib/kernel/test/os_SUITE_data/my_fds.c9
-rw-r--r--lib/kernel/test/rpc_SUITE.erl14
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/src/app/megaco.appup.src2
-rw-r--r--lib/megaco/test/megaco_app_test.erl308
-rw-r--r--lib/megaco/test/megaco_appup_test.erl498
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/Mnesia_chap1.xml28
-rw-r--r--lib/mnesia/doc/src/Mnesia_chap8.xml8
-rw-r--r--lib/mnesia/doc/src/Mnesia_overview.xml42
-rw-r--r--lib/mnesia/doc/src/mnesia.xml336
-rw-r--r--lib/mnesia/doc/src/mnesia_frag_hash.xml12
-rw-r--r--lib/mnesia/doc/src/mnesia_registry.xml12
-rw-r--r--lib/mnesia/doc/src/notes.xml89
-rw-r--r--lib/mnesia/doc/src/part.xml2
-rw-r--r--lib/mnesia/doc/src/ref_man.xml2
-rw-r--r--lib/mnesia/src/mnesia.erl15
-rw-r--r--lib/mnesia/src/mnesia_checkpoint.erl7
-rw-r--r--lib/mnesia/src/mnesia_controller.erl7
-rw-r--r--lib/mnesia/src/mnesia_event.erl3
-rw-r--r--lib/mnesia/src/mnesia_loader.erl17
-rw-r--r--lib/mnesia/src/mnesia_log.erl4
-rw-r--r--lib/mnesia/src/mnesia_schema.erl16
-rw-r--r--lib/mnesia/src/mnesia_tm.erl3
-rw-r--r--lib/mnesia/test/ext_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_evil_backup.erl43
-rw-r--r--lib/mnesia/test/mnesia_test_lib.erl1
-rw-r--r--lib/mnesia/test/mnesia_trans_access_test.erl10
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/notes.xml128
-rw-r--r--lib/observer/doc/src/ttb.xml18
-rwxr-xr-xlib/observer/priv/bin/cdv2
-rw-r--r--lib/observer/priv/bin/cdv.bat2
-rw-r--r--lib/observer/priv/crashdump_viewer.tool2
-rw-r--r--lib/observer/priv/crashdump_viewer/collapsd.gifbin141 -> 0 bytes
-rw-r--r--lib/observer/priv/crashdump_viewer/exploded.gifbin143 -> 0 bytes
-rw-r--r--lib/observer/src/Makefile10
-rw-r--r--lib/observer/src/cdv_bin_cb.erl4
-rw-r--r--lib/observer/src/cdv_detail_wx.erl4
-rw-r--r--lib/observer/src/cdv_ets_cb.erl7
-rw-r--r--lib/observer/src/cdv_mem_cb.erl4
-rw-r--r--lib/observer/src/crashdump_viewer.erl94
-rw-r--r--lib/observer/src/etop.erl24
-rw-r--r--lib/observer/src/etop_txt.erl24
-rw-r--r--lib/observer/src/observer_alloc_wx.erl2
-rw-r--r--lib/observer/src/observer_app_wx.erl10
-rw-r--r--lib/observer/src/observer_lib.erl44
-rw-r--r--lib/observer/src/observer_perf_wx.erl48
-rw-r--r--lib/observer/src/observer_port_wx.erl132
-rw-r--r--lib/observer/src/observer_pro_wx.erl8
-rw-r--r--lib/observer/src/observer_procinfo.erl6
-rw-r--r--lib/observer/src/observer_tv_wx.erl31
-rw-r--r--lib/observer/src/observer_wx.erl20
-rw-r--r--lib/observer/src/ttb.erl9
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl10
-rw-r--r--lib/observer/test/observer_SUITE.erl19
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/configure.in24
-rw-r--r--lib/odbc/doc/src/notes.xml41
-rw-r--r--lib/odbc/test/odbc_connect_SUITE.erl188
-rw-r--r--lib/odbc/test/odbc_data_type_SUITE.erl421
-rw-r--r--lib/odbc/test/odbc_query_SUITE.erl464
-rw-r--r--lib/odbc/test/odbc_start_SUITE.erl37
-rw-r--r--lib/odbc/test/odbc_test_lib.erl6
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/os_mon/doc/src/notes.xml15
-rw-r--r--lib/os_mon/src/memsup.erl3
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/parsetools/doc/src/notes.xml36
-rw-r--r--lib/parsetools/doc/src/yecc.xml2
-rw-r--r--lib/parsetools/include/leexinc.hrl35
-rw-r--r--lib/parsetools/src/leex.erl4
-rw-r--r--lib/parsetools/src/yecc.erl3
-rw-r--r--lib/parsetools/test/leex_SUITE.erl52
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl10
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/public_key/doc/src/notes.xml45
-rw-r--r--lib/public_key/doc/src/public_key.xml70
-rw-r--r--lib/public_key/doc/src/public_key_app.xml4
-rw-r--r--lib/public_key/doc/src/using_public_key.xml253
-rw-r--r--lib/public_key/src/public_key.erl215
-rw-r--r--lib/public_key/test/pbe_SUITE.erl7
-rw-r--r--lib/public_key/test/public_key.cover2
-rw-r--r--lib/public_key/test/public_key_SUITE.erl205
-rw-r--r--lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_cn.pem17
-rw-r--r--lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem14
-rw-r--r--lib/public_key/test/public_key_SUITE_data/verify_hostname.conf16
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/notes.xml52
-rw-r--r--lib/reltool/doc/src/part.xml2
-rw-r--r--lib/reltool/doc/src/ref_man.xml2
-rw-r--r--lib/reltool/doc/src/reltool.xml8
-rw-r--r--lib/reltool/doc/src/reltool_intro.xml4
-rw-r--r--lib/reltool/src/reltool.hrl28
-rw-r--r--lib/reltool/src/reltool_server.erl151
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl37
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app7
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl5
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app8
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl5
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app7
-rw-r--r--lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl5
-rw-r--r--lib/reltool/vsn.mk2
-rw-r--r--lib/runtime_tools/doc/src/LTTng.xml4
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml4
-rw-r--r--lib/runtime_tools/doc/src/notes.xml61
-rw-r--r--lib/runtime_tools/src/dbg.erl2
-rw-r--r--lib/runtime_tools/src/msacc.erl2
-rw-r--r--lib/runtime_tools/src/observer_backend.erl60
-rw-r--r--lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c2
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/doc/src/alarm_handler.xml4
-rw-r--r--lib/sasl/doc/src/appup.xml10
-rw-r--r--lib/sasl/doc/src/error_logging.xml18
-rw-r--r--lib/sasl/doc/src/notes.xml95
-rw-r--r--lib/sasl/doc/src/part.xml2
-rw-r--r--lib/sasl/doc/src/rb.xml6
-rw-r--r--lib/sasl/doc/src/ref_man.xml2
-rw-r--r--lib/sasl/doc/src/rel.xml6
-rw-r--r--lib/sasl/doc/src/release_handler.xml20
-rw-r--r--lib/sasl/doc/src/sasl_app.xml24
-rw-r--r--lib/sasl/doc/src/sasl_intro.xml2
-rw-r--r--lib/sasl/doc/src/script.xml2
-rw-r--r--lib/sasl/doc/src/systools.xml14
-rw-r--r--lib/sasl/src/sasl.app.src2
-rw-r--r--lib/sasl/src/systools_make.erl175
-rw-r--r--lib/sasl/src/systools_relup.erl152
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl18
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/start3
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/start_client3
-rw-r--r--lib/sasl/test/rh_test_lib.erl2
-rw-r--r--lib/sasl/test/systools_SUITE.erl118
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/doc/src/notes.xml50
-rw-r--r--lib/snmp/src/agent/snmpa_conf.erl16
-rw-r--r--lib/snmp/src/app/snmp.app.src14
-rw-r--r--lib/snmp/src/app/snmp.appup.src8
-rw-r--r--lib/snmp/src/app/snmp.erl80
-rw-r--r--lib/snmp/src/compile/snmpc.erl13
-rw-r--r--lib/snmp/src/compile/snmpc_lib.erl4
-rw-r--r--lib/snmp/src/compile/snmpc_mib_gram.yrl6
-rw-r--r--lib/snmp/src/compile/snmpc_misc.erl20
-rw-r--r--lib/snmp/test/modules.mk1
-rw-r--r--lib/snmp/test/snmp_SUITE.erl4
-rw-r--r--lib/snmp/test/snmp_agent_conf_test.erl210
-rw-r--r--lib/snmp/test/snmp_agent_test.erl26
-rw-r--r--lib/snmp/test/snmp_app_test.erl381
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl32
-rw-r--r--lib/snmp/test/snmp_manager_test.erl26
-rw-r--r--lib/snmp/test/snmp_test_data/OTP14145-MIB.mib44
-rw-r--r--lib/snmp/test/snmp_to_snmpnet_SUITE.erl10
-rw-r--r--lib/snmp/vsn.mk4
-rw-r--r--lib/ssh/doc/src/introduction.xml2
-rw-r--r--lib/ssh/doc/src/notes.xml387
-rw-r--r--lib/ssh/doc/src/ssh.xml56
-rw-r--r--lib/ssh/doc/src/ssh_app.xml4
-rw-r--r--lib/ssh/doc/src/ssh_channel.xml2
-rw-r--r--lib/ssh/doc/src/ssh_protocol.xml4
-rw-r--r--lib/ssh/doc/src/using_ssh.xml4
-rw-r--r--lib/ssh/src/Makefile2
-rw-r--r--lib/ssh/src/ssh.app.src7
-rw-r--r--lib/ssh/src/ssh.appup.src6
-rw-r--r--lib/ssh/src/ssh.erl175
-rw-r--r--lib/ssh/src/ssh.hrl8
-rw-r--r--lib/ssh/src/ssh_acceptor.erl2
-rw-r--r--lib/ssh/src/ssh_auth.erl359
-rw-r--r--lib/ssh/src/ssh_channel.erl9
-rw-r--r--lib/ssh/src/ssh_cli.erl46
-rw-r--r--lib/ssh/src/ssh_connection.erl5
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl260
-rw-r--r--lib/ssh/src/ssh_dbg.erl89
-rw-r--r--lib/ssh/src/ssh_dbg.hrl27
-rw-r--r--lib/ssh/src/ssh_info.erl2
-rw-r--r--lib/ssh/src/ssh_io.erl52
-rw-r--r--lib/ssh/src/ssh_sftpd.erl63
-rw-r--r--lib/ssh/src/ssh_sftpd_file_api.erl4
-rw-r--r--lib/ssh/src/ssh_transport.erl170
-rw-r--r--lib/ssh/test/Makefile3
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl92
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_encode_decode.erl372
-rw-r--r--lib/ssh/test/ssh.cover1
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE.erl50
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl148
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE.erl4
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl215
-rw-r--r--lib/ssh/test/ssh_eqc_event_handler.erl43
-rw-r--r--lib/ssh/test/ssh_options_SUITE.erl166
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE.erl10
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl74
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test4
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli5
-rw-r--r--lib/ssh/test/ssh_renegotiate_SUITE.erl40
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl24
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl163
-rw-r--r--lib/ssh/test/ssh_test_lib.erl153
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl147
-rw-r--r--lib/ssh/test/ssh_trpt_test_lib.erl2
-rw-r--r--lib/ssh/test/ssh_upgrade_SUITE.erl4
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml287
-rw-r--r--lib/ssl/doc/src/ssl.xml41
-rw-r--r--lib/ssl/doc/src/ssl_app.xml10
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache_api.xml2
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml6
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml31
-rw-r--r--lib/ssl/src/Makefile20
-rw-r--r--lib/ssl/src/dtls_connection.erl745
-rw-r--r--lib/ssl/src/dtls_connection.hrl20
-rw-r--r--lib/ssl/src/dtls_connection_sup.erl2
-rw-r--r--lib/ssl/src/dtls_handshake.erl575
-rw-r--r--lib/ssl/src/dtls_handshake.hrl15
-rw-r--r--lib/ssl/src/dtls_record.erl391
-rw-r--r--lib/ssl/src/dtls_record.hrl9
-rw-r--r--lib/ssl/src/dtls_socket.erl155
-rw-r--r--lib/ssl/src/dtls_udp_listener.erl249
-rw-r--r--lib/ssl/src/dtls_udp_sup.erl62
-rw-r--r--lib/ssl/src/dtls_v1.erl27
-rw-r--r--lib/ssl/src/ssl.app.src20
-rw-r--r--lib/ssl/src/ssl.appup.src3
-rw-r--r--lib/ssl/src/ssl.erl339
-rw-r--r--lib/ssl/src/ssl_admin_sup.erl95
-rw-r--r--lib/ssl/src/ssl_alert.erl13
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_certificate.erl52
-rw-r--r--lib/ssl/src/ssl_cipher.erl142
-rw-r--r--lib/ssl/src/ssl_config.erl54
-rw-r--r--lib/ssl/src/ssl_connection.erl801
-rw-r--r--lib/ssl/src/ssl_connection.hrl24
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl101
-rw-r--r--lib/ssl/src/ssl_crl.erl64
-rw-r--r--lib/ssl/src/ssl_crl_cache.erl2
-rw-r--r--lib/ssl/src/ssl_crl_cache_api.erl2
-rw-r--r--lib/ssl/src/ssl_dist_admin_sup.erl74
-rw-r--r--lib/ssl/src/ssl_dist_connection_sup.erl79
-rw-r--r--lib/ssl/src/ssl_dist_sup.erl42
-rw-r--r--lib/ssl/src/ssl_handshake.erl370
-rw-r--r--lib/ssl/src/ssl_handshake.hrl3
-rw-r--r--lib/ssl/src/ssl_internal.hrl12
-rw-r--r--lib/ssl/src/ssl_listen_tracker_sup.erl4
-rw-r--r--lib/ssl/src/ssl_manager.erl180
-rw-r--r--lib/ssl/src/ssl_pem_cache.erl266
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl135
-rw-r--r--lib/ssl/src/ssl_record.erl542
-rw-r--r--lib/ssl/src/ssl_record.hrl42
-rw-r--r--lib/ssl/src/ssl_sup.erl76
-rw-r--r--lib/ssl/src/ssl_tls_dist_proxy.erl2
-rw-r--r--lib/ssl/src/tls_connection.erl657
-rw-r--r--lib/ssl/src/tls_handshake.erl127
-rw-r--r--lib/ssl/src/tls_record.erl419
-rw-r--r--lib/ssl/src/tls_socket.erl (renamed from lib/ssl/src/ssl_socket.erl)93
-rw-r--r--lib/ssl/src/tls_v1.erl53
-rw-r--r--lib/ssl/test/make_certs.erl6
-rw-r--r--lib/ssl/test/ssl.spec3
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl320
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl269
-rw-r--r--lib/ssl/test/ssl_bench_SUITE.erl102
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl176
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl98
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl350
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl13
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl28
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl66
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl11
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl11
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl357
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl121
-rw-r--r--lib/ssl/test/ssl_upgrade_SUITE.erl22
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/assert_hrl.xml2
-rw-r--r--lib/stdlib/doc/src/dets.xml2
-rw-r--r--lib/stdlib/doc/src/ets.xml8
-rw-r--r--lib/stdlib/doc/src/filename.xml29
-rw-r--r--lib/stdlib/doc/src/gb_sets.xml2
-rw-r--r--lib/stdlib/doc/src/gb_trees.xml2
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml901
-rw-r--r--lib/stdlib/doc/src/introduction.xml2
-rw-r--r--lib/stdlib/doc/src/maps.xml2
-rw-r--r--lib/stdlib/doc/src/notes.xml225
-rw-r--r--lib/stdlib/doc/src/orddict.xml2
-rw-r--r--lib/stdlib/doc/src/proc_lib.xml4
-rw-r--r--lib/stdlib/doc/src/queue.xml2
-rw-r--r--lib/stdlib/doc/src/rand.xml2
-rw-r--r--lib/stdlib/doc/src/sets.xml2
-rw-r--r--lib/stdlib/doc/src/shell_default.xml2
-rw-r--r--lib/stdlib/doc/src/stdlib_app.xml8
-rw-r--r--lib/stdlib/doc/src/sys.xml6
-rw-r--r--lib/stdlib/doc/src/timer.xml2
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml8
-rw-r--r--lib/stdlib/doc/src/zip.xml6
-rw-r--r--lib/stdlib/src/beam_lib.erl2
-rw-r--r--lib/stdlib/src/edlin_expand.erl95
-rw-r--r--lib/stdlib/src/erl_eval.erl1
-rw-r--r--lib/stdlib/src/erl_parse.yrl42
-rw-r--r--lib/stdlib/src/escript.erl85
-rw-r--r--lib/stdlib/src/ets.erl8
-rw-r--r--lib/stdlib/src/filename.erl38
-rw-r--r--lib/stdlib/src/gen_event.erl4
-rw-r--r--lib/stdlib/src/gen_statem.erl1537
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl131
-rw-r--r--lib/stdlib/src/ms_transform.erl2
-rw-r--r--lib/stdlib/src/qlc.erl6
-rw-r--r--lib/stdlib/src/shell.erl4
-rw-r--r--lib/stdlib/src/stdlib.appup.src6
-rw-r--r--lib/stdlib/src/supervisor.erl4
-rw-r--r--lib/stdlib/src/zip.erl146
-rw-r--r--lib/stdlib/test/base64_SUITE.erl41
-rw-r--r--lib/stdlib/test/edlin_expand_SUITE.erl86
-rw-r--r--lib/stdlib/test/escript_SUITE.erl15
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/two_lines2
-rw-r--r--lib/stdlib/test/ets_SUITE.erl295
-rw-r--r--lib/stdlib/test/filename_SUITE.erl71
-rw-r--r--lib/stdlib/test/gen_statem_SUITE.erl408
-rw-r--r--lib/stdlib/test/io_SUITE.erl241
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl2
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl18
-rw-r--r--lib/stdlib/test/rand_SUITE.erl32
-rw-r--r--lib/stdlib/test/shell_SUITE.erl19
-rw-r--r--lib/stdlib/test/tar_SUITE.erl26
-rw-r--r--lib/stdlib/test/zip_SUITE.erl86
-rw-r--r--lib/stdlib/test/zip_SUITE_data/exploit.zipbin0 -> 797 bytes
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/specs/.gitignore1
-rw-r--r--lib/syntax_tools/doc/src/Makefile8
-rw-r--r--lib/syntax_tools/doc/src/notes.xml64
-rw-r--r--lib/syntax_tools/doc/src/specs.xml14
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl2
-rw-r--r--lib/syntax_tools/src/erl_comment_scan.erl12
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl23
-rw-r--r--lib/syntax_tools/src/erl_recomment.erl6
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl6
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl6
-rw-r--r--lib/syntax_tools/src/erl_tidy.erl15
-rw-r--r--lib/syntax_tools/src/igor.erl8
-rw-r--r--lib/syntax_tools/src/merl_tests.erl15
-rw-r--r--lib/syntax_tools/src/merl_transform.erl13
-rw-r--r--lib/syntax_tools/src/prettypr.erl2
-rw-r--r--lib/syntax_tools/test/merl_SUITE.erl21
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl34
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE_data/erl_tidy_tilde.erl13
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/tools/doc/src/erlang_mode.xml9
-rw-r--r--lib/tools/doc/src/notes.xml98
-rw-r--r--lib/tools/doc/src/xref_chapter.xml6
-rw-r--r--lib/tools/emacs/Makefile2
-rw-r--r--lib/tools/emacs/erlang-edoc.el172
-rw-r--r--lib/tools/emacs/erlang-skels.el169
-rw-r--r--lib/tools/emacs/erlang-start.el15
-rw-r--r--lib/tools/emacs/erlang-test.el106
-rw-r--r--lib/tools/emacs/erlang.el3636
-rw-r--r--lib/tools/emacs/erldoc.el508
-rw-r--r--lib/tools/emacs/test.erl.indented810
-rw-r--r--lib/tools/emacs/test.erl.orig210
-rw-r--r--lib/tools/examples/xref_examples.erl2
-rw-r--r--lib/tools/src/fprof.erl17
-rw-r--r--lib/tools/src/make.erl2
-rw-r--r--lib/tools/src/tags.erl2
-rw-r--r--lib/tools/src/tools.app.src4
-rw-r--r--lib/tools/src/xref_base.erl4
-rw-r--r--lib/tools/test/cover_SUITE.erl33
-rw-r--r--lib/tools/test/cover_SUITE_data/otp_6115/f1.erl15
-rw-r--r--lib/tools/test/cover_SUITE_data/otp_6115/f2.erl14
-rw-r--r--lib/tools/test/make_SUITE_data/test1.erl2
-rw-r--r--lib/tools/test/xref_SUITE.erl17
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/typer/doc/src/notes.xml14
-rw-r--r--lib/typer/src/typer.app.src4
-rw-r--r--lib/typer/src/typer.erl24
-rw-r--r--lib/typer/vsn.mk2
-rw-r--r--lib/wx/api_gen/gl_gen.erl33
-rw-r--r--lib/wx/api_gen/gl_gen_c.erl31
-rw-r--r--lib/wx/api_gen/gl_gen_erl.erl55
-rw-r--r--lib/wx/api_gen/glapi.conf6
-rw-r--r--lib/wx/api_gen/wx_doxygen.conf2
-rw-r--r--lib/wx/api_gen/wx_extra/added_func.h11
-rw-r--r--lib/wx/api_gen/wx_extra/wxListCtrl.erl62
-rw-r--r--lib/wx/api_gen/wx_extra/wxXmlResource.erl6
-rw-r--r--lib/wx/api_gen/wx_gen.erl34
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl10
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl13
-rw-r--r--lib/wx/api_gen/wxapi.conf15
-rw-r--r--lib/wx/c_src/gen/gl_funcs.cpp1052
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp17
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp40
-rw-r--r--lib/wx/c_src/gen/wxe_macros.h6659
-rw-r--r--lib/wx/c_src/wxe_main.cpp6
-rw-r--r--lib/wx/doc/specs/.gitignore1
-rw-r--r--lib/wx/doc/src/Makefile6
-rw-r--r--lib/wx/doc/src/notes.xml46
-rw-r--r--lib/wx/doc/src/specs.xml232
-rw-r--r--lib/wx/examples/demo/demo.erl19
-rw-r--r--lib/wx/include/wx.hrl465
-rw-r--r--lib/wx/src/gen/gl.erl1223
-rw-r--r--lib/wx/src/gen/glu.erl4
-rw-r--r--lib/wx/src/gen/wxArtProvider.erl8
-rw-r--r--lib/wx/src/gen/wxAuiManager.erl8
-rw-r--r--lib/wx/src/gen/wxAuiNotebook.erl78
-rw-r--r--lib/wx/src/gen/wxAuiPaneInfo.erl4
-rw-r--r--lib/wx/src/gen/wxBitmap.erl12
-rw-r--r--lib/wx/src/gen/wxBitmapButton.erl69
-rw-r--r--lib/wx/src/gen/wxButton.erl54
-rw-r--r--lib/wx/src/gen/wxCalendarCtrl.erl50
-rw-r--r--lib/wx/src/gen/wxCheckBox.erl58
-rw-r--r--lib/wx/src/gen/wxCheckListBox.erl19
-rw-r--r--lib/wx/src/gen/wxChoice.erl73
-rw-r--r--lib/wx/src/gen/wxChoicebook.erl60
-rw-r--r--lib/wx/src/gen/wxColourDialog.erl72
-rw-r--r--lib/wx/src/gen/wxColourPickerCtrl.erl29
-rw-r--r--lib/wx/src/gen/wxComboBox.erl84
-rw-r--r--lib/wx/src/gen/wxCommandEvent.erl2
-rw-r--r--lib/wx/src/gen/wxControl.erl54
-rw-r--r--lib/wx/src/gen/wxControlWithItems.erl66
-rw-r--r--lib/wx/src/gen/wxDC.erl20
-rw-r--r--lib/wx/src/gen/wxDatePickerCtrl.erl27
-rw-r--r--lib/wx/src/gen/wxDialog.erl64
-rw-r--r--lib/wx/src/gen/wxDirDialog.erl76
-rw-r--r--lib/wx/src/gen/wxDirPickerCtrl.erl29
-rw-r--r--lib/wx/src/gen/wxDropFilesEvent.erl89
-rw-r--r--lib/wx/src/gen/wxFileDataObject.erl2
-rw-r--r--lib/wx/src/gen/wxFileDialog.erl82
-rw-r--r--lib/wx/src/gen/wxFilePickerCtrl.erl29
-rw-r--r--lib/wx/src/gen/wxFindReplaceData.erl4
-rw-r--r--lib/wx/src/gen/wxFindReplaceDialog.erl80
-rw-r--r--lib/wx/src/gen/wxFont.erl4
-rw-r--r--lib/wx/src/gen/wxFontDialog.erl72
-rw-r--r--lib/wx/src/gen/wxFontPickerCtrl.erl27
-rw-r--r--lib/wx/src/gen/wxFrame.erl68
-rw-r--r--lib/wx/src/gen/wxGLCanvas.erl50
-rw-r--r--lib/wx/src/gen/wxGauge.erl50
-rw-r--r--lib/wx/src/gen/wxGenericDirCtrl.erl58
-rw-r--r--lib/wx/src/gen/wxGraphicsContext.erl12
-rw-r--r--lib/wx/src/gen/wxGrid.erl84
-rw-r--r--lib/wx/src/gen/wxGridCellBoolEditor.erl2
-rw-r--r--lib/wx/src/gen/wxGridCellChoiceEditor.erl2
-rw-r--r--lib/wx/src/gen/wxGridCellFloatEditor.erl2
-rw-r--r--lib/wx/src/gen/wxGridCellFloatRenderer.erl2
-rw-r--r--lib/wx/src/gen/wxGridCellNumberEditor.erl2
-rw-r--r--lib/wx/src/gen/wxGridCellTextEditor.erl2
-rw-r--r--lib/wx/src/gen/wxHtmlEasyPrinting.erl24
-rw-r--r--lib/wx/src/gen/wxHtmlWindow.erl78
-rw-r--r--lib/wx/src/gen/wxIcon.erl4
-rw-r--r--lib/wx/src/gen/wxIconBundle.erl4
-rw-r--r--lib/wx/src/gen/wxImage.erl34
-rw-r--r--lib/wx/src/gen/wxListBox.erl75
-rw-r--r--lib/wx/src/gen/wxListCtrl.erl148
-rw-r--r--lib/wx/src/gen/wxListItem.erl2
-rw-r--r--lib/wx/src/gen/wxListView.erl50
-rw-r--r--lib/wx/src/gen/wxListbook.erl60
-rw-r--r--lib/wx/src/gen/wxLocale.erl20
-rw-r--r--lib/wx/src/gen/wxMDIChildFrame.erl90
-rw-r--r--lib/wx/src/gen/wxMDIClientWindow.erl50
-rw-r--r--lib/wx/src/gen/wxMDIParentFrame.erl55
-rw-r--r--lib/wx/src/gen/wxMenu.erl56
-rw-r--r--lib/wx/src/gen/wxMenuBar.erl63
-rw-r--r--lib/wx/src/gen/wxMenuItem.erl6
-rw-r--r--lib/wx/src/gen/wxMessageDialog.erl76
-rw-r--r--lib/wx/src/gen/wxMiniFrame.erl55
-rw-r--r--lib/wx/src/gen/wxMultiChoiceDialog.erl76
-rw-r--r--lib/wx/src/gen/wxNotebook.erl60
-rw-r--r--lib/wx/src/gen/wxPanel.erl50
-rw-r--r--lib/wx/src/gen/wxPasswordEntryDialog.erl64
-rw-r--r--lib/wx/src/gen/wxPickerBase.erl50
-rw-r--r--lib/wx/src/gen/wxPopupTransientWindow.erl69
-rw-r--r--lib/wx/src/gen/wxPopupWindow.erl50
-rw-r--r--lib/wx/src/gen/wxPreviewCanvas.erl64
-rw-r--r--lib/wx/src/gen/wxPreviewControlBar.erl69
-rw-r--r--lib/wx/src/gen/wxPreviewFrame.erl47
-rw-r--r--lib/wx/src/gen/wxPrintData.erl2
-rw-r--r--lib/wx/src/gen/wxPrintDialog.erl72
-rw-r--r--lib/wx/src/gen/wxPrinter.erl2
-rw-r--r--lib/wx/src/gen/wxProgressDialog.erl76
-rw-r--r--lib/wx/src/gen/wxRadioBox.erl29
-rw-r--r--lib/wx/src/gen/wxRadioButton.erl58
-rw-r--r--lib/wx/src/gen/wxSashLayoutWindow.erl53
-rw-r--r--lib/wx/src/gen/wxSashWindow.erl50
-rw-r--r--lib/wx/src/gen/wxScrollBar.erl50
-rw-r--r--lib/wx/src/gen/wxScrolledWindow.erl69
-rw-r--r--lib/wx/src/gen/wxSingleChoiceDialog.erl76
-rw-r--r--lib/wx/src/gen/wxSlider.erl50
-rw-r--r--lib/wx/src/gen/wxSpinButton.erl50
-rw-r--r--lib/wx/src/gen/wxSpinCtrl.erl52
-rw-r--r--lib/wx/src/gen/wxSplashScreen.erl47
-rw-r--r--lib/wx/src/gen/wxSplitterWindow.erl50
-rw-r--r--lib/wx/src/gen/wxStaticBitmap.erl50
-rw-r--r--lib/wx/src/gen/wxStaticBox.erl58
-rw-r--r--lib/wx/src/gen/wxStaticLine.erl50
-rw-r--r--lib/wx/src/gen/wxStaticText.erl62
-rw-r--r--lib/wx/src/gen/wxStatusBar.erl58
-rw-r--r--lib/wx/src/gen/wxStyledTextCtrl.erl113
-rw-r--r--lib/wx/src/gen/wxSystemOptions.erl12
-rw-r--r--lib/wx/src/gen/wxTextCtrl.erl64
-rw-r--r--lib/wx/src/gen/wxTextDataObject.erl2
-rw-r--r--lib/wx/src/gen/wxTextEntryDialog.erl78
-rw-r--r--lib/wx/src/gen/wxToggleButton.erl58
-rw-r--r--lib/wx/src/gen/wxToolBar.erl74
-rw-r--r--lib/wx/src/gen/wxToolTip.erl4
-rw-r--r--lib/wx/src/gen/wxToolbook.erl60
-rw-r--r--lib/wx/src/gen/wxTopLevelWindow.erl52
-rw-r--r--lib/wx/src/gen/wxTreeCtrl.erl68
-rw-r--r--lib/wx/src/gen/wxTreeEvent.erl2
-rw-r--r--lib/wx/src/gen/wxTreebook.erl64
-rw-r--r--lib/wx/src/gen/wxUpdateUIEvent.erl2
-rw-r--r--lib/wx/src/gen/wxWindow.erl90
-rw-r--r--lib/wx/src/gen/wxXmlResource.erl40
-rw-r--r--lib/wx/src/gen/wx_misc.erl6
-rw-r--r--lib/wx/src/gen/wxe_debug.hrl6659
-rw-r--r--lib/wx/src/gen/wxe_funcs.hrl6659
-rw-r--r--lib/wx/src/wx_object.erl84
-rw-r--r--lib/wx/src/wxe.hrl2
-rw-r--r--lib/wx/test/wx_opengl_SUITE.erl2
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/doc/src/notes.xml91
-rw-r--r--lib/xmerl/src/xmerl_eventp.erl84
-rw-r--r--lib/xmerl/src/xmerl_sax_old_dom.erl7
-rw-r--r--lib/xmerl/src/xmerl_sax_parser.erl198
-rw-r--r--lib/xmerl/src/xmerl_sax_parser.hrl11
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_base.erlsrc411
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_latin1.erlsrc38
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_list.erlsrc21
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc50
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc50
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_utf8.erlsrc50
-rw-r--r--lib/xmerl/src/xmerl_sax_simple_dom.erl5
-rw-r--r--lib/xmerl/src/xmerl_scan.erl38
-rw-r--r--lib/xmerl/src/xmerl_xpath.erl30
-rw-r--r--lib/xmerl/src/xmerl_xs.erl7
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl13
-rw-r--r--lib/xmerl/test/Makefile7
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl49
-rw-r--r--lib/xmerl/test/xmerl_sax_SUITE.erl84
-rw-r--r--lib/xmerl/test/xmerl_sax_SUITE_data/test_data_1.xml4
-rw-r--r--lib/xmerl/test/xmerl_sax_std_SUITE.erl100
-rw-r--r--lib/xmerl/test/xmerl_sax_stream_SUITE.erl260
-rw-r--r--lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one.xml17
-rw-r--r--lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one_junk.xml18
-rw-r--r--lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_two.xml34
-rw-r--r--lib/xmerl/vsn.mk2
973 files changed, 68141 insertions, 32617 deletions
diff --git a/lib/asn1/doc/src/asn1_getting_started.xml b/lib/asn1/doc/src/asn1_getting_started.xml
index 3c8ec24723..d40b294c39 100644
--- a/lib/asn1/doc/src/asn1_getting_started.xml
+++ b/lib/asn1/doc/src/asn1_getting_started.xml
@@ -678,7 +678,7 @@ ok
1081,32,1043,1085,1086,1084]</pre>
<p>For details, see the <seealso marker="stdlib:unicode">unicode</seealso>
- module in <c>stdlib</c>.</p>
+ module in STDLIB.</p>
<p>In the following example, this ASN.1 specification is used:</p>
<pre>
diff --git a/lib/asn1/doc/src/asn1_introduction.xml b/lib/asn1/doc/src/asn1_introduction.xml
index d8b81aa467..e4f406364d 100644
--- a/lib/asn1/doc/src/asn1_introduction.xml
+++ b/lib/asn1/doc/src/asn1_introduction.xml
@@ -30,7 +30,7 @@
<file>asn1_introduction.xml</file>
</header>
- <p>The <c>ASN.1</c> application provides the following:</p>
+ <p>The ASN.1 application provides the following:</p>
<list type="bulleted">
<item>An ASN.1 compiler for Erlang, which generates encode and
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index 68d335f451..499a7e40c3 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 4.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Compiling multiple ASN.1 modules in the same directory
+ with parallel make (make -j) should now be safe.</p>
+ <p>
+ Own Id: OTP-13624</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 4.0.3</title>
<section><title>Improvements and New Features</title>
@@ -329,7 +345,7 @@
</item>
<item>
<p>
- The <c>asn1</c> application would fail to build if the
+ The ASN.1 application would fail to build if the
<c>.erlang</c> file printed something to standard output.</p>
<p>
Own Id: OTP-11360</p>
@@ -997,7 +1013,7 @@
also been extended. </item><item> The <c>configure</c>
scripts of <c>erl_interface</c> and <c>odbc</c> now
search for thread libraries and thread library quirks the
- same way as <c>erts</c> do. </item><item> The
+ same way as ERTS do. </item><item> The
<c>configure</c> script of the <c>odbc</c> application
now also looks for odbc libraries in <c>lib64</c> and
<c>lib/64</c> directories when building on a 64-bit
diff --git a/lib/asn1/src/asn1_db.erl b/lib/asn1/src/asn1_db.erl
index 557eca0ffd..869ea310aa 100644
--- a/lib/asn1/src/asn1_db.erl
+++ b/lib/asn1/src/asn1_db.erl
@@ -106,7 +106,9 @@ loop(#state{parent = Parent, monitor = MRef, table = Table,
loop(State);
{save, OutFile, Mod} ->
[{_,Mtab}] = ets:lookup(Table, Mod),
- ok = ets:tab2file(Mtab, OutFile),
+ TempFile = OutFile ++ ".#temp",
+ ok = ets:tab2file(Mtab, TempFile),
+ ok = file:rename(TempFile, OutFile),
loop(State);
{From, {new, Mod, Erule}} ->
[] = ets:lookup(Table, Mod), %Assertion.
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index dd269f095d..8783b5418d 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -221,9 +221,8 @@ check_pass(#st{code=M,file=File,includes=Includes,
{error,St#st{error=Reason}}
end.
-save_pass(#st{code=M,erule=Erule,dbfile=DbFile}=St) ->
+save_pass(#st{code=M,erule=Erule}=St) ->
ok = asn1ct_check:storeindb(#state{erule=Erule}, M),
- asn1_db:dbsave(DbFile,M#module.name),
{ok,St}.
parse_listing(#st{code=Code,outfile=OutFile0}=St) ->
diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl
index 1b4c3b3c77..dc614db4f2 100644
--- a/lib/asn1/test/asn1_test_lib.erl
+++ b/lib/asn1/test/asn1_test_lib.erl
@@ -34,12 +34,16 @@ run_dialyzer() ->
compile(File, Config, Options) -> compile_all([File], Config, Options).
-compile_all(Files, Config, Options) ->
+compile_all(Files, Config, Options0) ->
DataDir = proplists:get_value(data_dir, Config),
CaseDir = proplists:get_value(case_dir, Config),
- [compile_file(filename:join(DataDir, F), [{outdir, CaseDir},
- debug_info|Options])
- || F <- Files],
+ Options = [{outdir,CaseDir},debug_info|Options0],
+
+ Comp = fun(F) ->
+ compile_file(filename:join(DataDir, F), Options)
+ end,
+ p_run(Comp, Files),
+
dialyze(Files, Options),
ok.
@@ -94,9 +98,9 @@ compile_file(File, Options) ->
try
ok = asn1ct:compile(File, [warnings_as_errors|Options])
catch
- Class:Reason ->
- ct:print("Failed to compile ~s\n", [File]),
- erlang:error({compile_failed, {File, Options}, {Class, Reason}})
+ _:Reason ->
+ ct:print("Failed to compile ~s\n~p", [File,Reason]),
+ error
end.
compile_erlang(Mod, Config, Options) ->
@@ -219,3 +223,38 @@ ber_get_len(<<0:1,L:7,T/binary>>) ->
ber_get_len(<<1:1,Octets:7,T0/binary>>) ->
<<L:Octets/unit:8,T/binary>> = T0,
{L,T}.
+
+%% p_run(fun(Data) -> ok|error, List) -> ok
+%% Will fail the test case if there were any errors.
+
+p_run(Test, List) ->
+ S = erlang:system_info(schedulers),
+ N = case test_server:is_cover() of
+ false ->
+ S + 1;
+ true ->
+ %% Cover is running. Using too many processes
+ %% could slow us down.
+ min(S, 4)
+ end,
+ %%io:format("p_run: ~p parallel processes\n", [N]),
+ p_run_loop(Test, List, N, [], 0).
+
+p_run_loop(_, [], _, [], Errors) ->
+ case Errors of
+ 0 -> ok;
+ N -> ct:fail({N,errors})
+ end;
+p_run_loop(Test, [H|T], N, Refs, Errors) when length(Refs) < N ->
+ {_,Ref} = erlang:spawn_monitor(fun() -> exit(Test(H)) end),
+ p_run_loop(Test, T, N, [Ref|Refs], Errors);
+p_run_loop(Test, List, N, Refs0, Errors0) ->
+ receive
+ {'DOWN',Ref,process,_,Res} ->
+ Errors = case Res of
+ ok -> Errors0;
+ error -> Errors0+1
+ end,
+ Refs = Refs0 -- [Ref],
+ p_run_loop(Test, List, N, Refs, Errors)
+ end.
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 527af05da1..e4bf3e2236 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1 +1 @@
-ASN1_VSN = 4.0.3
+ASN1_VSN = 4.0.4
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index e495f587a3..152ece5d25 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -53,7 +53,8 @@ XML_REF3_FILES = ct.xml \
ct_slave.xml \
ct_property_test.xml \
ct_netconfc.xml \
- ct_hooks.xml
+ ct_hooks.xml \
+ ct_testspec.xml
XML_REF6_FILES = common_test_app.xml
XML_PART_FILES = part.xml
diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml
index 3f83747485..a3b3f927eb 100644
--- a/lib/common_test/doc/src/common_test_app.xml
+++ b/lib/common_test/doc/src/common_test_app.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -224,7 +224,9 @@
</type>
<desc>
- <p>OPTIONAL</p>
+ <p>OPTIONAL; if this function is defined, then <seealso
+ marker="#Module:end_per_suite-1"><c>end_per_suite/1</c></seealso>
+ must also be defined.</p>
<p>This configuration function is called as the first function in the
suite. It typically contains initializations that are common for
@@ -256,7 +258,9 @@
</type>
<desc>
- <p>OPTIONAL</p>
+ <p>OPTIONAL; if this function is defined, then <seealso
+ marker="#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso>
+ must also be defined.</p>
<p>This function is called as the last test case in the
suite. It is meant to be used for cleaning up after
@@ -360,7 +364,9 @@
</type>
<desc>
- <p>OPTIONAL</p>
+ <p>OPTIONAL; if this function is defined, then <seealso
+ marker="#Module:end_per_group-2"><c>end_per_group/2</c></seealso>
+ must also be defined.</p>
<p>This configuration function is called before execution of a
test case group. It typically contains initializations that are
@@ -396,7 +402,9 @@
</type>
<desc>
- <p>OPTIONAL</p>
+ <p>OPTIONAL; if this function is defined, then <seealso
+ marker="#Module:init_per_group-2"><c>init_per_group/2</c></seealso>
+ must also be defined.</p>
<p>This function is called after the execution of a test case group
is finished. It is meant to be used for cleaning up after
@@ -427,7 +435,10 @@
</type>
<desc>
- <p>OPTIONAL</p>
+ <p>OPTIONAL; if this function is defined,
+ then <seealso marker="#Module:end_per_testcase-2">
+ <c>end_per_testcase/2</c></seealso> must also be
+ defined.</p>
<p>This function is called before each test case. Argument
<c>TestCase</c> is the test case name, and
@@ -454,7 +465,10 @@
</type>
<desc>
- <p>OPTIONAL</p>
+ <p>OPTIONAL; if this function is defined,
+ then <seealso marker="#Module:init_per_testcase-2">
+ <c>init_per_testcase/2</c></seealso> must also be
+ defined.</p>
<p>This function is called after each test case, and can be used
to clean up after
@@ -566,7 +580,7 @@
(which also causes the test case process to terminate).</p>
<p>Elements from the <c>Config</c> list can, for example, be read
- with <c>proplists:get_value/2</c> in <c>STDLIB</c>
+ with <c>proplists:get_value/2</c> in STDLIB
(or the macro <c>?config</c> defined in <c>ct.hrl</c>).</p>
<p>If you decide not to run the test case after all, return
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index 264bcff251..ea9f956271 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -620,6 +620,21 @@
</func>
<func>
+ <name>get_verbosity(Category) -&gt; Level | undefined</name>
+ <fsummary>Read the verbosity level for a logging category.</fsummary>
+ <type>
+ <v>Category = default | atom()</v>
+ <v>Level = integer()</v>
+ </type>
+ <desc><marker id="get_verbosity-1"/>
+ <p>This function returns the verbosity level for the specified logging
+ category. See the <seealso marker="write_test_chapter#logging">
+ User's Guide</seealso> for details. Use the value <c>default</c> to read
+ the general verbosity level.</p>
+ </desc>
+ </func>
+
+ <func>
<name>install(Opts) -&gt; ok | {error, Reason}</name>
<fsummary>Installs configuration files and event handlers.</fsummary>
<type>
@@ -725,7 +740,7 @@
<v>Format = string()</v>
<v>FormatArgs = list()</v>
<v>Opts = [Opt]</v>
- <v>Opt = no_css | esc_chars</v>
+ <v>Opt = {heading,string()} | no_css | esc_chars</v>
</type>
<desc><marker id="log-5"/>
<p>Prints from a test case to the log file.</p>
@@ -777,59 +792,77 @@
caught by any installed event manager.</p>
<p>See also
- <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>.</p>
+ <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(Format) -&gt; ok</name>
- <fsummary>Equivalent to pal(default, 50, Format, []).</fsummary>
+ <fsummary>Equivalent to pal(default, 50, Format, [], []).</fsummary>
<desc><marker id="pal-1"/>
<p>Equivalent to
- <seealso marker="#pal-4"><c>ct:pal(default, 50, Format,
- [])</c></seealso>.</p>
+ <seealso marker="#pal-5"><c>ct:pal(default, 50, Format,
+ [], [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, []).</fsummary>
<type>
<v>X1 = Category | Importance | Format</v>
<v>X2 = Format | FormatArgs</v>
</type>
<desc><marker id="pal-2"/>
- <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, Opts).</fsummary>
<type>
<v>X1 = Category | Importance</v>
<v>X2 = Importance | Format</v>
- <v>X3 = Format | FormatArgs</v>
+ <v>X3 = Format | FormatArgs | Opts</v>
</type>
<desc><marker id="pal-3"/>
- <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pal(X1, X2, X3, X4) -&gt; ok</name>
+ <fsummary>Equivalent to pal(Category, Importance, Format,
+ FormatArgs, Opts).</fsummary>
+ <type>
+ <v>X1 = Category | Importance</v>
+ <v>X2 = Importance | Format</v>
+ <v>X3 = Format | FormatArgs</v>
+ <v>X4 = FormatArgs | Opts</v>
+ </type>
+ <desc><marker id="pal-4"/>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
</desc>
</func>
<func>
- <name>pal(Category, Importance, Format, FormatArgs) -&gt; ok</name>
+ <name>pal(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints and logs from a test case.</fsummary>
<type>
<v>Category = atom()</v>
<v>Importance = integer()</v>
<v>Format = string()</v>
<v>FormatArgs = list()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = {heading,string()} | no_css</v>
</type>
- <desc><marker id="pal-4"/>
+ <desc><marker id="pal-5"/>
<p>Prints and logs from a test case.</p>
<p>This function is meant for printing a string from a test case,
@@ -873,52 +906,70 @@
<func>
<name>print(Format) -&gt; ok</name>
- <fsummary>Equivalent to print(default, 50, Format, []).</fsummary>
+ <fsummary>Equivalent to print(default, 50, Format, [], []).</fsummary>
<desc><marker id="print-1"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(default,
- 50, Format, [])</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(default,
+ 50, Format, [], [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>print(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, []).</fsummary>
<type>
<v>X1 = Category | Importance | Format</v>
<v>X2 = Format | FormatArgs</v>
</type>
<desc><marker id="print-2"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>print(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, Opts).</fsummary>
<type>
<v>X1 = Category | Importance</v>
<v>X2 = Importance | Format</v>
- <v>X3 = Format | FormatArgs</v>
+ <v>X3 = Format | FormatArgs | Opts</v>
</type>
<desc><marker id="print-3"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>print(X1, X2, X3, X4) -&gt; ok</name>
+ <fsummary>Equivalent to print(Category, Importance, Format,
+ FormatArgs, Opts).</fsummary>
+ <type>
+ <v>X1 = Category | Importance</v>
+ <v>X2 = Importance | Format</v>
+ <v>X3 = Format | FormatArgs</v>
+ <v>X4 = FormatArgs | Opts</v>
+ </type>
+ <desc><marker id="print-4"/>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
</desc>
</func>
<func>
- <name>print(Category, Importance, Format, FormatArgs) -&gt; ok</name>
+ <name>print(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints from a test case to the console.</fsummary>
<type>
<v>Category = atom()</v>
<v>Importance = integer()</v>
<v>Format = string()</v>
<v>FormatArgs = list()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = {heading,string()}</v>
</type>
- <desc><marker id="print-4"/>
+ <desc><marker id="print-5"/>
<p>Prints from a test case to the console.</p>
<p>This function is meant for printing a string from a test case to
@@ -1225,6 +1276,21 @@
</func>
<func>
+ <name>set_verbosity(Category, Level) -&gt; ok</name>
+ <fsummary>Set the verbosity level for a logging category.</fsummary>
+ <type>
+ <v>Category = default | atom()</v>
+ <v>Level = integer()</v>
+ </type>
+ <desc><marker id="set_verbosity-2"/>
+ <p>Use this function to set, or modify, the verbosity level for a logging
+ category. See the <seealso marker="write_test_chapter#logging">
+ User's Guide</seealso> for details. Use the value <c>default</c> to set the
+ general verbosity level.</p>
+ </desc>
+ </func>
+
+ <func>
<name>sleep(Time) -&gt; ok</name>
<fsummary>This function, similar to timer:sleep/1, suspends the
test case for a specified time.</fsummary>
@@ -1236,7 +1302,7 @@
<v>Millisecs = integer() | float()</v>
</type>
<desc><marker id="sleep-1"/>
- <p>This function, similar to <c>timer:sleep/1</c> in <c>STDLIB</c>,
+ <p>This function, similar to <c>timer:sleep/1</c> in STDLIB,
suspends the test case for a specified time.
However, this function also multiplies <c>Time</c> with the
<c>multiply_timetraps</c> value (if set) and under certain
@@ -1330,7 +1396,7 @@
caught by any installed event manager.</p>
<p>See also
- <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>.
+ <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>.
</p>
</desc>
</func>
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 3b1e564b66..954be0ffba 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2010</year><year>2016</year>
+ <year>2010</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -94,7 +94,7 @@
<seealso marker="#Module:id-1"><c>ct_hooks:id/1</c></seealso>,
or a <c>reference</c> (created using
<seealso marker="erts:erlang#make_ref-0">erlang:make_ref/0</seealso>
- in <c>ERTS</c>) if
+ in ERTS) if
<seealso marker="#Module:id-1"><c>ct_hooks:id/1</c></seealso>
is not implemented.</p>
@@ -208,9 +208,10 @@
</func>
<func>
- <name>Module:pre_init_per_group(GroupName, InitData, CTHState) -&gt; Result</name>
+ <name>Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -&gt; Result</name>
<fsummary>Called before init_per_group.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>GroupName = atom()</v>
<v>InitData = Config | SkipOrFail</v>
<v>Config = NewConfig = [{Key,Value}]</v>
@@ -231,13 +232,19 @@
but for function
<seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso>
instead.</p>
+
+ <p>If <c>Module:pre_init_per_group/4</c> is not exported, common_test
+ will attempt to call <c>Module:pre_init_per_group(GroupName,
+ InitData, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:post_init_per_group(GroupName, Config, Return, CTHState) -&gt; Result</name>
+ <name>Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after init_per_group.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>GroupName = atom()</v>
<v>Config = [{Key,Value}]</v>
<v>Return = NewReturn = Config | SkipOrFail | term()</v>
@@ -258,13 +265,19 @@
but for function
<seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso>
instead.</p>
+
+ <p>If <c>Module:post_init_per_group/5</c> is not exported, common_test
+ will attempt to call <c>Module:post_init_per_group(GroupName,
+ Config, Return, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:pre_init_per_testcase(TestcaseName, InitData, CTHState) -&gt; Result</name>
+ <name>Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -&gt; Result</name>
<fsummary>Called before init_per_testcase.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>TestcaseName = atom()</v>
<v>InitData = Config | SkipOrFail</v>
<v>Config = NewConfig = [{Key,Value}]</v>
@@ -286,6 +299,11 @@
<seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso>
instead.</p>
+ <p>If <c>Module:pre_init_per_testcase/4</c> is not exported, common_test
+ will attempt to call <c>Module:pre_init_per_testcase(TestcaseName,
+ InitData, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
+
<p>CTHs cannot be added here right now. That feature may be added in
a later release, but it would right now break backwards
compatibility.</p>
@@ -293,9 +311,10 @@
</func>
<func>
- <name>Module:post_init_per_testcase(TestcaseName, Config, Return, CTHState) -&gt; Result</name>
+ <name>Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after init_per_testcase.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>TestcaseName = atom()</v>
<v>Config = [{Key,Value}]</v>
<v>Return = NewReturn = Config | SkipOrFail | term()</v>
@@ -316,15 +335,21 @@
but for function
<seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso>
instead.</p>
+
+ <p>If <c>Module:post_init_per_testcase/5</c> is not exported, common_test
+ will attempt to call <c>Module:post_init_per_testcase(TestcaseName,
+ Config, Return, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:pre_end_per_testcase(TestcaseName, InitData, CTHState) -&gt; Result</name>
+ <name>Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -&gt; Result</name>
<fsummary>Called before end_per_testcase.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>TestcaseName = atom()</v>
- <v>InitData = Config</v>
+ <v>EndData = Config</v>
<v>Config = NewConfig = [{Key,Value}]</v>
<v>CTHState = NewCTHState = term()</v>
<v>Result = {NewConfig, NewCTHState}</v>
@@ -345,14 +370,20 @@
<p>This function can not change the result of the test case by returning skip or fail
tuples, but it may insert items in <c>Config</c> that can be read in
- <c>end_per_testcase/2</c> or in <c>post_end_per_testcase/4</c>.</p>
+ <c>end_per_testcase/2</c> or in <c>post_end_per_testcase/5</c>.</p>
+
+ <p>If <c>Module:pre_end_per_testcase/4</c> is not exported, common_test
+ will attempt to call <c>Module:pre_end_per_testcase(TestcaseName,
+ EndData, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:post_end_per_testcase(TestcaseName, Config, Return, CTHState) -&gt; Result</name>
+ <name>Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after end_per_testcase.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>TestcaseName = atom()</v>
<v>Config = [{Key,Value}]</v>
<v>Return = NewReturn = Config | SkipOrFail | term()</v>
@@ -373,13 +404,19 @@
but for function
<seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso>
instead.</p>
+
+ <p>If <c>Module:post_end_per_testcase/5</c> is not exported, common_test
+ will attempt to call <c>Module:post_end_per_testcase(TestcaseName,
+ Config, Return, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:pre_end_per_group(GroupName, EndData, CTHState) -&gt; Result</name>
+ <name>Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -&gt; Result</name>
<fsummary>Called before end_per_group.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>GroupName = atom()</v>
<v>EndData = Config | SkipOrFail</v>
<v>Config = NewConfig = [{Key,Value}]</v>
@@ -400,13 +437,19 @@
but for function
<seealso marker="common_test#Module:end_per_group-2"><c>end_per_group</c></seealso>
instead.</p>
+
+ <p>If <c>Module:pre_end_per_group/4</c> is not exported, common_test
+ will attempt to call <c>Module:pre_end_per_group(GroupName,
+ EndData, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:post_end_per_group(GroupName, Config, Return, CTHState) -&gt; Result</name>
+ <name>Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after end_per_group.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>GroupName = atom()</v>
<v>Config = [{Key,Value}]</v>
<v>Return = NewReturn = Config | SkipOrFail | term()</v>
@@ -427,6 +470,11 @@
but for function
<seealso marker="common_test#Module:end_per_group-2">end_per_group</seealso>
instead.</p>
+
+ <p>If <c>Module:post_end_per_group/5</c> is not exported, common_test
+ will attempt to call <c>Module:post_end_per_group(GroupName,
+ Config, Return, CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
@@ -485,9 +533,10 @@
</func>
<func>
- <name>Module:on_tc_fail(TestName, Reason, CTHState) -&gt; NewCTHState</name>
+ <name>Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -&gt; NewCTHState</name>
<fsummary>Called after the CTH scope ends.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName</v>
<v>FuncName = atom()</v>
<v>GroupName = atom()</v>
@@ -505,7 +554,7 @@
<item><p>If <c>init_per_suite</c> fails, this function is called after
<seealso marker="#Module:post_init_per_suite-4"><c>post_init_per_suite</c></seealso>.</p></item>
<item><p>If a test case fails, this funcion is called after
- <seealso marker="#Module:post_end_per_testcase-4"><c>post_end_per_testcase</c></seealso>.</p></item>
+ <seealso marker="#Module:post_end_per_testcase-5"><c>post_end_per_testcase</c></seealso>.</p></item>
</list>
<p>If the failed test case belongs to a test case group, the first
@@ -519,13 +568,19 @@
For details, see section
<seealso marker="event_handler_chapter#events">Event Handling</seealso>
in the User's Guide.</p>
+
+ <p>If <c>Module:on_tc_fail/4</c> is not exported, common_test
+ will attempt to call <c>Module:on_tc_fail(TestName, Reason,
+ CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
<func>
- <name>Module:on_tc_skip(TestName, Reason, CTHState) -&gt; NewCTHState</name>
+ <name>Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -&gt; NewCTHState</name>
<fsummary>Called after the CTH scope ends.</fsummary>
<type>
+ <v>SuiteName = atom()</v>
<v>TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName</v>
<v>FuncName = atom()</v>
<v>GroupName = atom()</v>
@@ -542,9 +597,9 @@
<list type="bulleted">
<item><p>If <c>init_per_group</c> is skipped, this function is
called after
- <seealso marker="#Module:post_init_per_group-4"><c>post_init_per_group</c></seealso>.</p></item>
+ <seealso marker="#Module:post_init_per_group-5"><c>post_init_per_group</c></seealso>.</p></item>
<item><p>If a test case is skipped, this function is called after
- <seealso marker="#Module:post_end_per_testcase-4"><c>post_end_per_testcase</c></seealso>.</p></item>
+ <seealso marker="#Module:post_end_per_testcase-5"><c>post_end_per_testcase</c></seealso>.</p></item>
</list>
<p>If the skipped test case belongs to a test case group, the first
@@ -559,6 +614,11 @@
For details, see section
<seealso marker="event_handler_chapter#events">Event Handling</seealso>
in the User's Guide.</p>
+
+ <p>If <c>Module:on_tc_skip/4</c> is not exported, common_test
+ will attempt to call <c>Module:on_tc_skip(TestName, Reason,
+ CTHState)</c> instead. This is for backwards
+ compatibility.</p>
</desc>
</func>
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index 1998f15697..7ecc2e4298 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2011</year><year>2016</year>
+ <year>2011</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -38,7 +38,7 @@
extensions of the default behavior of <c>Common Test</c> using hooks
before and after all test suite calls. CTHs allow advanced <c>Common Test</c>
users to abstract out behavior that is common to multiple test suites
- without littering all test suites with library calls. this can be used
+ without littering all test suites with library calls. This can be used
for logging, starting, and monitoring external systems,
building C files needed by the tests, and so on.</p>
@@ -175,10 +175,10 @@
<row>
<cell><seealso marker="common_test#Module:init_per_group-2">
init_per_group/2</seealso></cell>
- <cell><seealso marker="ct_hooks#Module:post_init_per_group-4">
- post_init_per_group/4</seealso> is called</cell>
- <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4">
- post_end_per_group/4</seealso> has been called for that group</cell>
+ <cell><seealso marker="ct_hooks#Module:post_init_per_group-5">
+ post_init_per_group/5</seealso> is called</cell>
+ <cell><seealso marker="ct_hooks#Module:post_end_per_group-5">
+ post_end_per_group/5</seealso> has been called for that group</cell>
</row>
<tcaption>Scope of a CTH</tcaption>
</table>
@@ -245,16 +245,18 @@
</list>
<p>
- This is done in the CTH functions called pre_&lt;name of function&gt;.
- These functions take the same three arguments, <c>Name</c>,
+ This is done in the CTH functions called <c>pre_&lt;name of function&gt;</c>.
+ These functions take the arguments <c>SuiteName</c>, <c>Name</c> (group or test case name, if applicable),
<c>Config</c>, and <c>CTHState</c>. The return value of the CTH function
is always a combination of a result for the suite/group/test and an
updated <c>CTHState</c>.</p>
<p>To let the test suite continue on executing, return the configuration
- list that you want the test to use as the result. To skip or
- fail the test, return a tuple with <c>skip</c> or <c>fail</c>, and a reason
- as the result.</p>
+ list that you want the test to use as the result.</p>
+
+ <p>All pre hooks, except <c>pre_end_per_testcase/4</c>, can
+ skip or fail the test by returning a tuple with <c>skip</c> or
+ <c>fail</c>, and a reason as the result.</p>
<p><em>Example:</em></p>
<code>
@@ -290,7 +292,7 @@
<p>
This is done in the CTH functions called <c>post_&lt;name of function&gt;</c>.
- These functions take the same four arguments, <c>Name</c>,
+ These functions take the arguments <c>SuiteName</c>, <c>Name</c> (group or test case name, if applicable),
<c>Config</c>, <c>Return</c>, and <c>CTHState</c>. <c>Config</c> in this
case is the same <c>Config</c> as the testcase is called with.
<c>Return</c> is the value returned by the testcase. If the testcase
@@ -308,7 +310,7 @@
<p><em>Example:</em></p>
<code>
- post_end_per_testcase(_TC, Config, {'EXIT',{_,_}}, CTHState) -&gt;
+ post_end_per_testcase(_Suite, _TC, Config, {'EXIT',{_,_}}, CTHState) -&gt;
case db:check_consistency() of
true ->
%% DB is good, pass the test.
@@ -317,7 +319,7 @@
%% DB is not good, mark as skipped instead of failing
{{skip, "DB is inconsisten!"}, CTHState}
end;
- post_end_per_testcase(_TC, Config, Return, CTHState) -&gt;
+ post_end_per_testcase(_Suite, _TC, Config, Return, CTHState) -&gt;
%% Do nothing if tc does not crash.
{Return, CTHState}.</code>
@@ -331,8 +333,8 @@
<title>Skip and Fail Hooks</title>
<p>
After any post hook has been executed for all installed CTHs,
- <seealso marker="ct_hooks#Module:on_tc_fail-3">on_tc_fail</seealso>
- or <seealso marker="ct_hooks#Module:on_tc_skip-3">on_tc_skip</seealso>
+ <seealso marker="ct_hooks#Module:on_tc_fail-4">on_tc_fail</seealso>
+ or <seealso marker="ct_hooks#Module:on_tc_skip-4">on_tc_skip</seealso>
is called if the testcase failed or was skipped, respectively.
You cannot affect the outcome of the tests any further at this point.
</p>
@@ -374,7 +376,7 @@
<title>Example CTH</title>
<p>The following CTH logs information about a test run into a format
parseable by <seealso marker="kernel:file#consult-1">file:consult/1</seealso>
- (in <c>Kernel</c>):
+ (in Kernel):
</p>
<code>
%%% @doc Common Test Example Common Test Hook module.
@@ -389,18 +391,18 @@
-export([pre_end_per_suite/3]).
-export([post_end_per_suite/4]).
- -export([pre_init_per_group/3]).
- -export([post_init_per_group/4]).
- -export([pre_end_per_group/3]).
- -export([post_end_per_group/4]).
+ -export([pre_init_per_group/4]).
+ -export([post_init_per_group/5]).
+ -export([pre_end_per_group/4]).
+ -export([post_end_per_group/5]).
- -export([pre_init_per_testcase/3]).
- -export([post_init_per_testcase/4]).
- -export([pre_end_per_testcase/3]).
- -export([post_end_per_testcase/4]).
+ -export([pre_init_per_testcase/4]).
+ -export([post_init_per_testcase/5]).
+ -export([pre_end_per_testcase/4]).
+ -export([post_end_per_testcase/5]).
- -export([on_tc_fail/3]).
- -export([on_tc_skip/3]).
+ -export([on_tc_fail/4]).
+ -export([on_tc_skip/4]).
-export([terminate/1]).
@@ -435,46 +437,46 @@
total = State#state.total + State#state.suite_total } }.
%% @doc Called before each init_per_group.
- pre_init_per_group(Group,Config,State) ->
+ pre_init_per_group(Suite,Group,Config,State) ->
{Config, State}.
%% @doc Called after each init_per_group.
- post_init_per_group(Group,Config,Return,State) ->
+ post_init_per_group(Suite,Group,Config,Return,State) ->
{Return, State}.
%% @doc Called before each end_per_group.
- pre_end_per_group(Group,Config,State) ->
+ pre_end_per_group(Suite,Group,Config,State) ->
{Config, State}.
%% @doc Called after each end_per_group.
- post_end_per_group(Group,Config,Return,State) ->
+ post_end_per_group(Suite,Group,Config,Return,State) ->
{Return, State}.
%% @doc Called before each init_per_testcase.
- pre_init_per_testcase(TC,Config,State) ->
+ pre_init_per_testcase(Suite,TC,Config,State) ->
{Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }.
%% Called after each init_per_testcase (immediately before the test case).
- post_init_per_testcase(TC,Config,Return,State) ->
+ post_init_per_testcase(Suite,TC,Config,Return,State) ->
{Return, State}
%% @doc Called before each end_per_testcase (immediately after the test case).
- pre_end_per_testcase(TC,Config,State) ->
+ pre_end_per_testcase(Suite,TC,Config,State) ->
{Config, State}.
%% @doc Called after each end_per_testcase.
- post_end_per_testcase(TC,Config,Return,State) ->
- TCInfo = {testcase, TC, Return, timer:now_diff(now(), State#state.ts)},
+ post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ TCInfo = {testcase, Suite, TC, Return, timer:now_diff(now(), State#state.ts)},
{Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }.
%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed.
- on_tc_fail(TC, Reason, State) ->
+ on_tc_fail(Suite, TC, Reason, State) ->
State.
%% @doc Called when a test case is skipped by either user action
%% or due to an init function failing.
- on_tc_skip(TC, Reason, State) ->
+ on_tc_skip(Suite, TC, Reason, State) ->
State.
%% @doc Called when the scope of the CTH is done
@@ -499,13 +501,13 @@
<tag><c>cth_log_redirect</c></tag>
<item>
<p>Built-in</p>
- <p>Captures all <c>error_logger</c> and <c>SASL</c> logging
+ <p>Captures all <c>error_logger</c> and SASL logging
events and prints them to the current test case log. If an event cannot be
associated with a test case, it is printed in the <c>Common Test</c> framework log.
This happens for test cases running in parallel and events occuring
in-between test cases. You can configure the level of
- <seealso marker="sasl:sasl_app"><c>SASL</c></seealso> events report
- using the normal <c>SASL</c> mechanisms.</p>
+ <seealso marker="sasl:sasl_app">SASL</seealso> events report
+ using the normal SASL mechanisms.</p>
</item>
<tag><c>cth_surefire</c></tag>
<item>
diff --git a/lib/common_test/doc/src/ct_ssh.xml b/lib/common_test/doc/src/ct_ssh.xml
index d00737aa5a..137e4c3f1d 100644
--- a/lib/common_test/doc/src/ct_ssh.xml
+++ b/lib/common_test/doc/src/ct_ssh.xml
@@ -64,7 +64,7 @@
<p><c>ConnType = ssh | sftp</c>.</p>
<p>For other types, see
- <seealso marker="ssh:ssh"><c>ssh:ssh(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh"><c>ssh(3)</c></seealso>.</p>
<p>All time-out parameters in <c>ct_ssh</c> functions are values in
milliseconds.</p>
@@ -88,7 +88,7 @@
<tag><c>ssh_sftp_return() = term()</c></tag>
<item><marker id="type-ssh_sftp_return"/>
<p>Return value from an
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp</c></seealso>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp</c></seealso>
function.</p></item>
</taglist>
</section>
@@ -104,7 +104,7 @@
</type>
<desc><marker id="apread-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -118,7 +118,7 @@
</type>
<desc><marker id="apread-5"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -132,7 +132,7 @@
</type>
<desc><marker id="apwrite-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -146,7 +146,7 @@
</type>
<desc><marker id="apwrite-5"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -160,7 +160,7 @@
</type>
<desc><marker id="aread-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -174,7 +174,7 @@
</type>
<desc><marker id="aread-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -188,7 +188,7 @@
</type>
<desc><marker id="awrite-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -202,7 +202,7 @@
</type>
<desc><marker id="awrite-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -216,7 +216,7 @@
</type>
<desc><marker id="close-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -230,7 +230,7 @@
</type>
<desc><marker id="close-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -310,7 +310,7 @@
</type>
<desc><marker id="del_dir-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -324,7 +324,7 @@
</type>
<desc><marker id="del_dir-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -338,7 +338,7 @@
</type>
<desc><marker id="delete-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -352,7 +352,7 @@
</type>
<desc><marker id="delete-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -423,7 +423,7 @@
</type>
<desc><marker id="get_file_info-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -437,7 +437,7 @@
</type>
<desc><marker id="get_file_info-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -451,7 +451,7 @@
</type>
<desc><marker id="list_dir-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -465,7 +465,7 @@
</type>
<desc><marker id="list_dir-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -479,7 +479,7 @@
</type>
<desc><marker id="make_dir-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -493,7 +493,7 @@
</type>
<desc><marker id="make_dir-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -507,7 +507,7 @@
</type>
<desc><marker id="make_symlink-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -521,7 +521,7 @@
</type>
<desc><marker id="make_symlink-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -535,7 +535,7 @@
</type>
<desc><marker id="open-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -549,7 +549,7 @@
</type>
<desc><marker id="open-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -563,7 +563,7 @@
</type>
<desc><marker id="opendir-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -577,7 +577,7 @@
</type>
<desc><marker id="opendir-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -591,7 +591,7 @@
</type>
<desc><marker id="position-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -605,7 +605,7 @@
</type>
<desc><marker id="position-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -619,7 +619,7 @@
</type>
<desc><marker id="pread-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -633,7 +633,7 @@
</type>
<desc><marker id="pread-5"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -647,7 +647,7 @@
</type>
<desc><marker id="pwrite-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -661,7 +661,7 @@
</type>
<desc><marker id="pwrite-5"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -675,7 +675,7 @@
</type>
<desc><marker id="read-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -689,7 +689,7 @@
</type>
<desc><marker id="read-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -703,7 +703,7 @@
</type>
<desc><marker id="read_file-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -717,7 +717,7 @@
</type>
<desc><marker id="read_file-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -731,7 +731,7 @@
</type>
<desc><marker id="read_file_info-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -745,7 +745,7 @@
</type>
<desc><marker id="read_file_info-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -759,7 +759,7 @@
</type>
<desc><marker id="read_link-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -773,7 +773,7 @@
</type>
<desc><marker id="read_link-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -787,7 +787,7 @@
</type>
<desc><marker id="read_link_info-2"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -801,7 +801,7 @@
</type>
<desc><marker id="read_link_info-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -853,7 +853,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
<p>If <c>End</c> is a fun, this fun is called with one argument, the
data value in a received <c>ssh_cm</c> message (see
- <seealso marker="ssh:ssh_connection"><c>ssh:ssh_connection(3)</c></seealso>.
+ <seealso marker="ssh:ssh_connection"><c>ssh_connection(3)</c></seealso>.
The fun is to return either <c>true</c> to end the receiving
operation (and have the so far collected data returned) or
<c>false</c> to wait for more data from the server. Even if a fun
@@ -872,7 +872,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</type>
<desc><marker id="rename-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -886,7 +886,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</type>
<desc><marker id="rename-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -1070,7 +1070,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</type>
<desc><marker id="write-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -1084,7 +1084,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</type>
<desc><marker id="write-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -1098,7 +1098,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</type>
<desc><marker id="write_file-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -1112,7 +1112,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</type>
<desc><marker id="write_file-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -1126,7 +1126,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</type>
<desc><marker id="write_file_info-3"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
@@ -1140,7 +1140,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</type>
<desc><marker id="write_file_info-4"/>
<p>For information and other types, see
- <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p>
+ <seealso marker="ssh:ssh_sftp"><c>ssh_sftp(3)</c></seealso>.</p>
</desc>
</func>
</funcs>
diff --git a/lib/common_test/doc/src/ct_telnet.xml b/lib/common_test/doc/src/ct_telnet.xml
index e2a45e894b..8e85cccc99 100644
--- a/lib/common_test/doc/src/ct_telnet.xml
+++ b/lib/common_test/doc/src/ct_telnet.xml
@@ -198,7 +198,7 @@
<item><marker id="type-prompt_regexp"/>
<p>Regular expression matching all possible prompts for a specific
target type. <c>regexp</c> must not have any groups, that is, when
- matching, <c>re:run/3</c> (in <c>STDLIB</c>) must return a list with
+ matching, <c>re:run/3</c> (in STDLIB) must return a list with
one single element.</p></item>
</taglist>
</section>
@@ -337,7 +337,7 @@
<c>FullMatch</c> is the string matched by the whole regular
expression, and <c>SubMatchN</c> is the string that matched
subexpression number <c>N</c>. Subexpressions are denoted with
- <c>(' ')</c> in the regular expression.</p>
+ <c>'(' ')'</c> in the regular expression.</p>
<p>If a <c>Tag</c> is speciifed, the returned <c>Match</c> also
includes the matched <c>Tag</c>. Otherwise, only <c>RxMatch</c>
diff --git a/lib/common_test/doc/src/ct_testspec.xml b/lib/common_test/doc/src/ct_testspec.xml
new file mode 100644
index 0000000000..36893f66cf
--- /dev/null
+++ b/lib/common_test/doc/src/ct_testspec.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2016</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>ct_testspec</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev>A</rev>
+ <file>ct_testspec.xml</file>
+ </header>
+ <module>ct_testspec</module>
+ <modulesummary>Parsing of test specifications for Common Test.
+ </modulesummary>
+
+<description>
+
+ <p>Parsing of test specifications for <c>Common Test</c>.</p>
+
+ <p>This module exports help functions for parsing of test specifications.</p>
+
+</description>
+
+ <funcs>
+ <func>
+ <name>get_tests(SpecsIn) -&gt; {ok, [{Specs,Tests}]} | {error, Reason}</name>
+ <fsummary>Parse the given test specification files and return the tests to run and skip.</fsummary>
+ <type>
+ <v>SpecsIn = [string()] | [[string()]]</v>
+ <v>Specs = [string()]</v>
+ <v>Test = [{Node,Run,Skip}]</v>
+ <v>Node = atom()</v>
+ <v>Run = {Dir,Suites,Cases}</v>
+ <v>Skip = {Dir,Suites,Comment} | {Dir,Suites,Cases,Comment}</v>
+ <v>Dir = string()</v>
+ <v>Suites = atom | [atom()] | all</v>
+ <v>Cases = atom | [atom()] | all</v>
+ <v>Comment = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc><marker id="add_nodes-1"/>
+ <p>Parse the given test specification files and return the
+ tests to run and skip.</p>
+
+ <p>If <c>SpecsIn=[Spec1,Spec2,...]</c>, separate tests will be
+ created per specification. If
+ <c>SpecsIn=[[Spec1,Spec2,...]]</c>, all specifications will be
+ merge into one test.</p>
+
+ <p>For each test, a <c>{Specs,Tests}</c> element is returned,
+ where <c>Specs</c> is a list of all included test
+ specifications, and <c>Tests</c> specifies actual tests to
+ run/skip per node.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
+
diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml
index 2978226a19..bd9ed21cb4 100644
--- a/lib/common_test/doc/src/event_handler_chapter.xml
+++ b/lib/common_test/doc/src/event_handler_chapter.xml
@@ -50,7 +50,7 @@
pass the information on. The event handlers are Erlang modules
implemented by the <c>Common Test</c> user according to the <c>gen_event</c>
behavior (for details, see module
- <seealso marker="stdlib:gen_event"><c>stdlib:gen_event</c></seealso> and
+ <seealso marker="stdlib:gen_event"><c>gen_event</c></seealso> and
section
<seealso marker="doc/design_principles:events"><c>gen_event Behaviour</c></seealso>
in OTP Design Principles in the System Documentation).
@@ -69,8 +69,8 @@
manager, either by telling <c>Common Test</c> to install them before the test
run (described later), or by adding the handlers dynamically during the test
run using
- <seealso marker="stdlib:gen_event#add_handler-3"><c>stdlib:gen_event:add_handler/3</c></seealso> or
- <seealso marker="stdlib:gen_event#add_sup_handler-3"><c>stdlib:gen_event:add_sup_handler/3</c></seealso>.
+ <seealso marker="stdlib:gen_event#add_handler-3"><c>gen_event:add_handler/3</c></seealso> or
+ <seealso marker="stdlib:gen_event#add_sup_handler-3"><c>gen_event:add_sup_handler/3</c></seealso>.
In the latter scenario, the reference of the <c>Common Test</c> event manager is
required. To get it, call
<seealso marker="ct#get_event_mgr_ref-0"><c>ct:get_event_mgr_ref/0</c></seealso>
diff --git a/lib/common_test/doc/src/introduction.xml b/lib/common_test/doc/src/introduction.xml
index 40724f24e9..df12bea6dd 100644
--- a/lib/common_test/doc/src/introduction.xml
+++ b/lib/common_test/doc/src/introduction.xml
@@ -45,7 +45,7 @@
</list>
<p><c>Common Test</c> also integrates use of the OTP
<seealso marker="tools:cover">cover</seealso> tool in application
- <c>Tools</c> for code coverage analysis of Erlang/OTP programs.</p>
+ Tools for code coverage analysis of Erlang/OTP programs.</p>
<p><c>Common Test</c> executes test suite programs automatically,
without operator interaction. Test progress and results are
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 32ae699c7a..efeacd4a72 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -33,6 +33,218 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The following corrections and improvements are done in
+ the common_test hook handling:</p> <list> <item> <p>An
+ extra argument, <c>Suite</c>, is added as the first
+ argument to each of the following hook callback
+ functions:</p> <list>
+ <item><c>pre_init_per_group</c></item>
+ <item><c>post_init_per_group</c></item>
+ <item><c>pre_end_per_group</c></item>
+ <item><c>post_end_per_group</c></item>
+ <item><c>pre_init_per_testcase</c></item>
+ <item><c>post_init_per_testcase</c></item>
+ <item><c>pre_end_per_testcase</c></item>
+ <item><c>post_end_per_testcase</c></item>
+ <item><c>on_tc_fail</c></item>
+ <item><c>on_tc_skip</c></item> </list> <p>For backwards
+ compatibility, if the new function is not exported from a
+ hook callback module, <c>common_test</c> will fall back
+ to the old interface and call the function without the
+ <c>Suite</c> argument.</p> </item> <item> <p>If either
+ <c>init_per_suite</c> or <c>end_per_suite</c> exists, but
+ not the other, then the non-existing function will be
+ reported as failed with reason <c>undef</c> in the test
+ log. The same goes for <c>init/end_per_group</c>. This
+ has always been a requirement according to the user's
+ guide, but now <c>common_test</c> is more explicit in the
+ report.</p> </item> <item> <p>If <c>init_per_suite</c>
+ was exported from a test suite, but not
+ <c>end_per_suite</c>, then <c>pre/post_end_per_suite</c>
+ was called with <c>Suite=ct_framework</c> instead of the
+ correct suite name. This is now corrected.</p> </item>
+ <item> <p>If <c>end_per_group</c> was exported from a
+ suite, but not <c>init_per_group</c>, then
+ <c>end_per_group</c> was never called. This is now
+ corrected.</p> </item> <item> <p>Tests that were skipped
+ before calling <c>pre_init_per_*</c> got faulty calls to
+ the corresponding <c>post_init_per_*</c>. E.g. if a test
+ was skipped because <c>suite/0</c> failed, then
+ <c>post_init_per_suite</c> would be called even though
+ <c>pre_init_per_suite</c> and <c>init_per_suite</c> were
+ not called. This is now corrected so a <c>post_*</c>
+ callback will never be called unless the corresponding
+ <c>pre_*</c> callback has been called first.</p> </item>
+ <item> <p>Tests that were skipped before or in
+ <c>init_per_testcase</c> got faulty calls to
+ <c>pre_end_per_testcase</c> and
+ <c>post_end_per_testcase</c>. This is now corrected so
+ <c>pre/post_end_per_testcase</c> are not called when
+ <c>end_per_testcase</c> is not called.</p> </item> <item>
+ <p>If an exit signal causes the test case process to die
+ while running <c>init_per_testcase</c>, the case was
+ earlier reported as failed with reason <c>{skip,...}</c>.
+ This is now corrected so the case will be marked as
+ skipped.</p> </item> <item> <p>If an exist signal causes
+ the test case process to die while running
+ <c>end_per_testcase</c>, the case was earlier marked as
+ failed. This is now corrected so the status of the test
+ case is not changed - there is only a warning added to
+ the comment field.</p> </item> <item> <p>If a test case
+ was skipped because of option
+ <c>{force_stop,skip_rest}</c> or because of a failed
+ sequence, then no <c>tc_start</c> event would be sent,
+ only <c>tc_done</c>. This is now corrected so both events
+ are sent.</p> </item> <item> <p>When skipping or failing
+ in a configuration function, the configuration function
+ itself would get <c>{auto_skipped,Reason}</c>,
+ <c>{skipped,Reason}</c> or <c>{failed,Reason}</c> in the
+ hook callbacks <c>on_tc_skip</c> or <c>on_tc_fail</c>.
+ The other test cases that were skipped as a result of
+ this would only get <c>Reason</c> in <c>on_tc_skip</c>.
+ This is now corrected so even the configuration function
+ that caused the skip/fail will only get <c>Reason</c> in
+ the hook callback.</p> </item> </list>
+ <p>
+ Own Id: OTP-10599 Aux Id: kunagi-344 [255] </p>
+ </item>
+ <item>
+ <p>
+ When a test case was skipped by a <c>skip_cases</c>
+ statement in a test spec, then <c>cth_surefire</c> would
+ erroneously mark the previous test case as skipped in the
+ xml report. The actually skipped test case would not be
+ present in the xml report at all. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14129 Aux Id: seq13244 </p>
+ </item>
+ <item>
+ <p>The <c>multiply_timetraps</c> and
+ <c>scale_timetraps</c> options did not work with test
+ specifications, which has been corrected.</p>
+ <p>
+ Own Id: OTP-14210</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ ct_testspec:get_tests/1 is added. This is used by rebar3
+ to get all directories that must be compiled when running
+ tests from testspec - instead of implementing testspec
+ parsing in rebar3.</p>
+ <p>
+ Own Id: OTP-14132</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Some types of printouts to screen during test runs
+ (including <c>ct:print/1,2,3,4</c>) used the local
+ <c>user</c> process as IO device and these printouts
+ would not be visible when e.g. running tests via a shell
+ on a remote node. A default Common Test group leader
+ process has been introduced to solve the problem. This
+ process routes printouts to the group leader of the
+ starting process, if available, otherwise to <c>user</c>.</p>
+ <p>
+ Own Id: OTP-13973 Aux Id: ERL-279 </p>
+ </item>
+ <item>
+ <p>
+ Some Common Test processes, that act as I/O group leaders
+ for test cases, would not terminate as expected at the
+ end of test runs. This error has been corrected.</p>
+ <p>
+ Own Id: OTP-14026 Aux Id: ERL-287 </p>
+ </item>
+ <item>
+ <p>
+ The logging verbosity feature was incorrectly documented.
+ The default verbosity levels for test runs is e.g. not 50
+ (<c>?STD_VERBOSITY</c>), but 100 (<c>?MAX_VERBOSITY</c>).
+ Also, some of the examples had errors and flaws. The
+ corresponding chapter (5.18) in the User's Guide has been
+ updated.</p>
+ <p>
+ Own Id: OTP-14044 Aux Id: seq13223 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A feature to let the user specify headings to log
+ printouts has been added. The heading is specified as
+ <c>{heading,string()}</c> in the <c>Opts</c> list
+ argument to <c>ct:pal/3,4,5</c>, <c>ct:print/3,4,5</c>,
+ or <c>ct:log/3,4,5</c>. If the heading option is omitted,
+ the category name, or <c>"User"</c>, is used as the
+ heading instead.</p>
+ <p>
+ Own Id: OTP-14043 Aux Id: seq13226 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.12.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If the telnet server would pause during transmission of a
+ line of text before terminating the line, the
+ <c>ct_telnet:expect/3</c> function would print the line
+ twice in the test case HTML log. This problem has been
+ fixed.</p>
+ <p>
+ Own Id: OTP-13730 Aux Id: seq13135 </p>
+ </item>
+ <item>
+ <p>
+ The functions <c>ct:set_verbosity/2</c> and
+ <c>ct:get_verbosity/1</c> have been added in order to
+ make it possible for test cases, CT Hooks, or test
+ framework functions, to modify and read verbosity levels
+ for logging.</p>
+ <p>
+ Own Id: OTP-13841</p>
+ </item>
+ <item>
+ <p><c>make</c> (tools) and <c>ct_make</c> (common_test)
+ would crash if an Erlang source file contained a
+ <c>-warning()</c> directive.</p>
+ <p>
+ Own Id: OTP-13855</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.12.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/doc/src/ref_man.xml b/lib/common_test/doc/src/ref_man.xml
index d1567e2d3c..1ac20db5c2 100644
--- a/lib/common_test/doc/src/ref_man.xml
+++ b/lib/common_test/doc/src/ref_man.xml
@@ -47,6 +47,7 @@
<xi:include href="ct_slave.xml"/>
<xi:include href="ct_hooks.xml"/>
<xi:include href="ct_property_test.xml"/>
+ <xi:include href="ct_testspec.xml"/>
</application>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 43e36adfb6..76e306c4ed 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -274,7 +274,7 @@
<note><p>Directories passed to <c>Common Test</c> can have either relative or absolute paths.</p></note>
- <note><p>Any start flags to the Erlang runtime system (application <c>ERTS</c>) can also be passed as
+ <note><p>Any start flags to the Erlang runtime system (application ERTS) can also be passed as
parameters to <c>ct_run</c>. It is, for example, useful to be able to
pass directories to be added to the Erlang code server search path
with flag <c>-pa</c> or <c>-pz</c>. If you have common help- or library
@@ -286,7 +286,7 @@
<p>The absolute path of directory <c>chat_server/ebin</c>
is here passed to the code server. This is essential because relative
paths are stored by the code server as relative, and <c>Common Test</c> changes
- the current working directory of <c>ERTS</c> during the test run.</p>
+ the current working directory of ERTS during the test run.</p>
</note>
<p>The <c>ct_run</c> program sets the exit status before shutting down. The following values
@@ -1258,7 +1258,7 @@
<p>The minor log files contain full details of every single test
case, each in a separate file. This way, it is
straightforward to compare the latest results to that of previous
- test runs, even if the set of test cases changes. If application <c>SASL</c>
+ test runs, even if the set of test cases changes. If application SASL
is running, its logs are also printed to the current minor log file by the
<seealso marker="common_test:ct_hooks_chapter#builtin_cths">
cth_log_redirect built-in hook</seealso>.
diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml
index 83daf771a6..d2d41625c4 100644
--- a/lib/common_test/doc/src/write_test_chapter.xml
+++ b/lib/common_test/doc/src/write_test_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -269,10 +269,10 @@
<p>As parameter <c>Config</c> is a list of key-value tuples, that is,
a data type called a property list, it can be handled by the
- <seealso marker="stdlib:proplists"><c>stdlib:proplists</c></seealso> module.
+ <seealso marker="stdlib:proplists"><c>proplists</c></seealso> module.
A value can, for example, be searched for and returned with function
<seealso marker="stdlib:proplists#get_value-2"><c>proplists:get_value/2</c></seealso>.
- Also, or alternatively, the general <seealso marker="stdlib:lists"><c>stdlib:lists</c></seealso>
+ Also, or alternatively, the general <seealso marker="stdlib:lists"><c>lists</c></seealso>
module contains useful functions. Normally, the only operations
performed on <c>Config</c> is insert (adding a tuple to the head of the list)
and lookup. <c>Common Test</c> provides a simple macro named <c>?config</c>,
@@ -566,7 +566,7 @@
for the test cases in the group. After execution of the group is finished, function
<seealso marker="common_test#Module:end_per_group-2"><c>end_per_group(GroupName, Config)</c></seealso>
is called. This function is meant to be used for cleaning up after
- <c>init_per_group/2</c>.</p>
+ <c>init_per_group/2</c>. If the init function is defined, so must the end function be.</p>
<p>Whenever a group is executed, if <c>init_per_group</c> and
<c>end_per_group</c> do not exist in the suite, <c>Common Test</c> calls
@@ -652,7 +652,7 @@
<title>Parallel Test Cases and I/O</title>
<p>A parallel test case has a private I/O server as its group leader.
(For a description of the group leader concept, see
- <seealso marker="erts:index"><c>ERTS</c></seealso>).
+ <seealso marker="erts:index">ERTS</seealso>).
The central I/O server process, which handles the output from
regular test cases and configuration functions, does not respond to I/O messages
during execution of parallel groups. This is important to understand
@@ -986,15 +986,17 @@
<c>io:put_chars/1</c>, and so on.</p>
<p><c>Importance</c> is compared to a verbosity level set by the
- <c>verbosity</c> start flag/option. The verbosity level can be set per
- category or generally, or both. The default verbosity level,
- <c>?STD_VERBOSITY</c>, is 50, that is, all standard I/O gets printed.
- If a lower verbosity level is set, standard I/O printouts are ignored.
- <c>Common Test</c> performs the following test:</p>
+ <c>verbosity</c> start flag/option. The level can be set per
+ category or generally, or both. If <c>verbosity</c> is not set by the user,
+ a level of 100 (<c>?MAX_VERBOSITY</c> = all printouts visible) is used as
+ default value. <c>Common Test</c> performs the following test:</p>
<pre>
- Importance >= (100-VerbosityLevel)</pre>
- <p>This also means that verbosity level 0 effectively turns all logging off
- (except from printouts made by <c>Common Test</c> itself).</p>
+Importance >= (100-VerbosityLevel)</pre>
+ <p>The constant <c>?STD_VERBOSITY</c> has value 50 (see <c>ct.hrl</c>).
+ At this level, all standard I/O gets printed. If a lower verbosity level
+ is set, standard I/O printouts are ignored. Verbosity level 0 effectively
+ turns all logging off (except from printouts made by <c>Common Test</c>
+ itself).</p>
<p>The general verbosity level is not associated with any particular
category. This level sets the threshold for the standard I/O printouts,
@@ -1003,17 +1005,17 @@
<p><em>Examples:</em></p>
<p>Some printouts during test case execution:</p>
- <pre>
+ <pre>
io:format("1. Standard IO, importance = ~w~n", [?STD_IMPORTANCE]),
ct:log("2. Uncategorized, importance = ~w", [?STD_IMPORTANCE]),
- ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]]),
+ ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]),
ct:log(info, ?LOW_IMPORTANCE, "4. Categorized info, importance = ~w", [?LOW_IMPORTANCE]),
- ct:log(error, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]),
- ct:log(error, ?HI_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre>
+ ct:log(error, ?HI_IMPORTANCE, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]),
+ ct:log(error, ?MAX_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre>
- <p>If starting the test without specifying any verbosity levels as follows:</p>
+ <p>If starting the test with a general verbosity level of 50 (<c>?STD_VERBOSITY</c>):</p>
<pre>
- $ ct_run ...</pre>
+ $ ct_run -verbosity 50</pre>
<p>the following is printed:</p>
<pre>
1. Standard IO, importance = 50
@@ -1031,9 +1033,25 @@
4. Categorized info, importance = 25
6. Categorized error, importance = 99</pre>
+ <p>Note that the category argument is not required in order to only specify the
+ importance of a printout. Example:</p>
+ <pre>
+<c>ct:pal(?LOW_IMPORTANCE, "Info report: ~p", [Info])</c></pre>
+ <p>Or perhaps in combination with constants:</p>
+ <pre>
+-define(INFO, ?LOW_IMPORTANCE).
+-define(ERROR, ?HI_IMPORTANCE).
+
+ct:log(?INFO, "Info report: ~p", [Info])
+ct:pal(?ERROR, "Error report: ~p", [Error])</pre>
+
+ <p>The functions <seealso marker="ct#set_verbosity-2"><c>ct:set_verbosity/2</c></seealso>
+ and <seealso marker="ct#get_verbosity-1"><c>ct:get_verbosity/1</c></seealso> may be used
+ to modify and read verbosity levels during test execution.</p>
+
<p>The arguments <c>Format</c> and <c>FormatArgs</c> in <c>ct:log/print/pal</c> are
- always passed on to the <c>stdlib</c> function <c>io:format/3</c> (For details,
- see the <seealso marker="stdlib:io"><c>stdlib:io</c></seealso> manual page).</p>
+ always passed on to the STDLIB function <c>io:format/3</c> (For details,
+ see the <seealso marker="stdlib:io"><c>io</c></seealso> manual page).</p>
<p><c>ct:pal/4</c> and <c>ct:log/5</c> add headers to strings being printed to the
log file. The strings are also wrapped in div tags with a CSS class
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 0f9e044f9e..9d751996ad 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -80,6 +80,7 @@ MODULES= \
ct_groups \
ct_property_test \
ct_release_test \
+ ct_default_gl \
erl2html2 \
test_server_ctrl \
test_server_gl \
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index 77588af59b..430a4fa2fb 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
{vsn, "%VSN%"},
{modules, [ct_cover,
ct,
+ ct_default_gl,
ct_event,
ct_framework,
ct_ftp,
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index d7ae81a5ce..43abb91819 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -66,8 +66,9 @@
reload_config/1,
escape_chars/1, escape_chars/2,
log/1, log/2, log/3, log/4, log/5,
- print/1, print/2, print/3, print/4,
- pal/1, pal/2, pal/3, pal/4,
+ print/1, print/2, print/3, print/4, print/5,
+ pal/1, pal/2, pal/3, pal/4, pal/5,
+ set_verbosity/2, get_verbosity/1,
capture_start/0, capture_stop/0, capture_get/0, capture_get/1,
fail/1, fail/2, comment/1, comment/2, make_priv_dir/0,
testcases/2, userdata/2, userdata/3,
@@ -591,7 +592,7 @@ log(X1,X2,X3,X4) ->
%%% Format = string()
%%% Args = list()
%%% Opts = [Opt]
-%%% Opt = esc_chars | no_css
+%%% Opt = {heading,string()} | esc_chars | no_css
%%%
%%% @doc Printout from a test case to the log file.
%%%
@@ -609,43 +610,61 @@ log(Category,Importance,Format,Args,Opts) ->
%%%-----------------------------------------------------------------
%%% @spec print(Format) -> ok
-%%% @equiv print(default,50,Format,[])
+%%% @equiv print(default,50,Format,[],[])
print(Format) ->
- print(default,?STD_IMPORTANCE,Format,[]).
+ print(default,?STD_IMPORTANCE,Format,[],[]).
%%%-----------------------------------------------------------------
%%% @spec print(X1,X2) -> ok
%%% X1 = Category | Importance | Format
%%% X2 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args)
+%%% @equiv print(Category,Importance,Format,Args,[])
print(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
is_integer(X1) -> {default,X1,X2,[]};
is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2}
end,
- print(Category,Importance,Format,Args).
+ print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec print(X1,X2,X3) -> ok
+%%% X1 = Category | Importance | Format
+%%% X2 = Importance | Format | Args
+%%% X3 = Format | Args | Opts
+%%% @equiv print(Category,Importance,Format,Args,Opts)
+print(X1,X2,X3) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]};
+ is_integer(X1) -> {default,X1,X2,X3,[]};
+ is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3}
+ end,
+ print(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec print(X1,X2,X3,X4) -> ok
%%% X1 = Category | Importance
%%% X2 = Importance | Format
%%% X3 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args)
-print(X1,X2,X3) ->
- {Category,Importance,Format,Args} =
- if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]};
- is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3};
- is_integer(X1) -> {default,X1,X2,X3}
+%%% X4 = Args | Opts
+%%% @equiv print(Category,Importance,Format,Args,Opts)
+print(X1,X2,X3,X4) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4};
+ is_integer(X1) -> {default,X1,X2,X3,X4}
end,
- print(Category,Importance,Format,Args).
+ print(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec print(Category,Importance,Format,Args) -> ok
+%%% @spec print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = [Opt]
+%%% Opt = {heading,string()}
%%%
%%% @doc Printout from a test case to the console.
%%%
@@ -657,13 +676,13 @@ print(X1,X2,X3) ->
%%% and default value for <c>Args</c> is <c>[]</c>.</p>
%%% <p>Please see the User's Guide for details on <c>Category</c>
%%% and <c>Importance</c>.</p>
-print(Category,Importance,Format,Args) ->
- ct_logs:tc_print(Category,Importance,Format,Args).
+print(Category,Importance,Format,Args,Opts) ->
+ ct_logs:tc_print(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
%%% @spec pal(Format) -> ok
-%%% @equiv pal(default,50,Format,[])
+%%% @equiv pal(default,50,Format,[],[])
pal(Format) ->
pal(default,?STD_IMPORTANCE,Format,[]).
@@ -671,35 +690,53 @@ pal(Format) ->
%%% @spec pal(X1,X2) -> ok
%%% X1 = Category | Importance | Format
%%% X2 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args)
+%%% @equiv pal(Category,Importance,Format,Args,[])
pal(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
is_integer(X1) -> {default,X1,X2,[]};
is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2}
end,
- pal(Category,Importance,Format,Args).
+ pal(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec pal(X1,X2,X3) -> ok
+%%% X1 = Category | Importance | Format
+%%% X2 = Importance | Format | Args
+%%% X3 = Format | Args | Opts
+%%% @equiv pal(Category,Importance,Format,Args,Opts)
+pal(X1,X2,X3) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]};
+ is_integer(X1) -> {default,X1,X2,X3,[]};
+ is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3}
+ end,
+ pal(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec pal(X1,X2,X3,X4) -> ok
%%% X1 = Category | Importance
%%% X2 = Importance | Format
%%% X3 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args)
-pal(X1,X2,X3) ->
- {Category,Importance,Format,Args} =
- if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]};
- is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3};
- is_integer(X1) -> {default,X1,X2,X3}
+%%% X4 = Args | Opts
+%%% @equiv pal(Category,Importance,Format,Args,Opts)
+pal(X1,X2,X3,X4) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4};
+ is_integer(X1) -> {default,X1,X2,X3,X4}
end,
- pal(Category,Importance,Format,Args).
+ pal(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec pal(Category,Importance,Format,Args) -> ok
+%%% @spec pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = [Opt]
+%%% Opt = {heading,string()} | no_css
%%%
%%% @doc Print and log from a test case.
%%%
@@ -711,8 +748,26 @@ pal(X1,X2,X3) ->
%%% and default value for <c>Args</c> is <c>[]</c>.</p>
%%% <p>Please see the User's Guide for details on <c>Category</c>
%%% and <c>Importance</c>.</p>
-pal(Category,Importance,Format,Args) ->
- ct_logs:tc_pal(Category,Importance,Format,Args).
+pal(Category,Importance,Format,Args,Opts) ->
+ ct_logs:tc_pal(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec set_verbosity(Category, Level) -> ok
+%%% Category = default | atom()
+%%% Level = integer()
+%%%
+%%% @doc Set the verbosity level for a category
+set_verbosity(Category, Level) ->
+ ct_util:set_verbosity({Category,Level}).
+
+%%%-----------------------------------------------------------------
+%%% @spec get_verbosity(Category) -> Level | undefined
+%%% Category = default | atom()
+%%% Level = integer()
+%%%
+%%% @doc Read the verbosity level for a category
+get_verbosity(Category) ->
+ ct_util:get_verbosity(Category).
%%%-----------------------------------------------------------------
%%% @spec capture_start() -> ok
diff --git a/lib/common_test/src/ct_default_gl.erl b/lib/common_test/src/ct_default_gl.erl
new file mode 100644
index 0000000000..d1b52e5f4f
--- /dev/null
+++ b/lib/common_test/src/ct_default_gl.erl
@@ -0,0 +1,83 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_default_gl).
+-export([start_link/1, stop/0]).
+
+-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]).
+
+%% start_link()
+%% Start a new group leader process.
+start_link(ParentGL) ->
+ do_start(ParentGL, 3).
+
+do_start(_ParentGL, 0) ->
+ exit({?MODULE,startup});
+do_start(ParentGL, Retries) ->
+ case whereis(?MODULE) of
+ undefined ->
+ case gen_server:start_link(?MODULE, [ParentGL], []) of
+ {ok,Pid} ->
+ {ok,Pid};
+ Other ->
+ Other
+ end;
+ Pid ->
+ exit(Pid, kill),
+ timer:sleep(1000),
+ do_start(ParentGL, Retries-1)
+ end.
+
+%% stop(Pid)
+%% Stop a group leader process.
+stop() ->
+ gen_server:cast(whereis(?MODULE), stop).
+
+
+%%% Internal functions.
+
+init([ParentGL]) ->
+ register(?MODULE, self()),
+ {ok,#{parent_gl_pid => ParentGL,
+ parent_gl_monitor => erlang:monitor(process,ParentGL)}}.
+
+handle_cast(stop, St) ->
+ {stop,normal,St}.
+
+%% If the parent group leader dies, fall back on using the local user process
+handle_info({'DOWN',Ref,process,_,_Reason}, #{parent_gl_monitor := Ref} = St) ->
+ User = whereis(user),
+ {noreply,St#{parent_gl_pid => User,
+ parent_gl_monitor => erlang:monitor(process,User)}};
+
+handle_info({io_request,_From,_ReplyAs,_Req} = IoReq,
+ #{parent_gl_pid := ParentGL} = St) ->
+ ParentGL ! IoReq,
+ {noreply,St};
+
+handle_info(Msg, St) ->
+ io:format(user, "Common Test Group Leader process got: ~tp~n", [Msg]),
+ {noreply,St}.
+
+handle_call(_Req, _From, St) ->
+ {reply,ok,St}.
+
+terminate(_, _) ->
+ ok.
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 104515e57e..141c7f5b0a 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,6 +52,10 @@
%%%
%%% @doc Test server framework callback, called by the test_server
%%% when a new test case is started.
+init_tc(_,{end_per_testcase_not_run,_},[Config]) ->
+ %% Testcase is completed (skipped or failed), but end_per_testcase
+ %% is not run - don't call pre-hook.
+ {ok,[Config]};
init_tc(Mod,EPTC={end_per_testcase,_},[Config]) ->
%% in case Mod == ct_framework, lookup the suite name
Suite = get_suite_name(Mod, Config),
@@ -62,7 +66,7 @@ init_tc(Mod,EPTC={end_per_testcase,_},[Config]) ->
Other
end;
-init_tc(Mod,Func0,Args) ->
+init_tc(Mod,Func0,Args) ->
%% in case Mod == ct_framework, lookup the suite name
Suite = get_suite_name(Mod, Args),
{Func,HookFunc} = case Func0 of
@@ -84,12 +88,15 @@ init_tc(Mod,Func0,Args) ->
andalso Func=/=end_per_group
andalso ct_util:get_testdata(skip_rest) of
true ->
+ initialize(false,Mod,Func,Args),
{auto_skip,"Repeated test stopped by force_stop option"};
_ ->
case ct_util:get_testdata(curr_tc) of
{Suite,{suite0_failed,{require,Reason}}} ->
+ initialize(false,Mod,Func,Args),
{auto_skip,{require_failed_in_suite0,Reason}};
{Suite,{suite0_failed,_}=Failure} ->
+ initialize(false,Mod,Func,Args),
{fail,Failure};
_ ->
ct_util:update_testdata(curr_tc,
@@ -118,16 +125,14 @@ init_tc(Mod,Func0,Args) ->
end,
init_tc1(Mod,Suite,Func,HookFunc,Args);
{failed,Seq,BadFunc} ->
- {auto_skip,{sequence_failed,Seq,BadFunc}}
+ initialize(false,Mod,Func,Args),
+ {auto_skip,{sequence_failed,Seq,BadFunc}}
end
end
end.
init_tc1(?MODULE,_,error_in_suite,_,[Config0]) when is_list(Config0) ->
- ct_logs:init_tc(false),
- ct_event:notify(#event{name=tc_start,
- node=node(),
- data={?MODULE,error_in_suite}}),
+ initialize(false,?MODULE,error_in_suite),
_ = ct_suite_init(?MODULE,error_in_suite,[],Config0),
case ?val(error,Config0) of
undefined ->
@@ -177,27 +182,21 @@ init_tc1(Mod,Suite,Func,HookFunc,[Config0]) when is_list(Config0) ->
ct_config:delete_default_config(testcase),
HookFunc
end,
- Initialize = fun() ->
- ct_logs:init_tc(false),
- ct_event:notify(#event{name=tc_start,
- node=node(),
- data={Mod,FuncSpec}})
- end,
case add_defaults(Mod,Func,AllGroups) of
Error = {suite0_failed,_} ->
- Initialize(),
+ initialize(false,Mod,FuncSpec),
ct_util:set_testdata({curr_tc,{Suite,Error}}),
{error,Error};
Error = {group0_failed,_} ->
- Initialize(),
+ initialize(false,Mod,FuncSpec),
{auto_skip,Error};
Error = {testcase0_failed,_} ->
- Initialize(),
+ initialize(false,Mod,FuncSpec),
{auto_skip,Error};
{SuiteInfo,MergeResult} ->
case MergeResult of
{error,Reason} ->
- Initialize(),
+ initialize(false,Mod,FuncSpec),
{fail,Reason};
_ ->
init_tc2(Mod,Suite,Func,HookFunc1,
@@ -236,11 +235,8 @@ init_tc2(Mod,Suite,Func,HookFunc,SuiteInfo,MergeResult,Config) ->
Conns ->
ct_util:silence_connections(Conns)
end,
- ct_logs:init_tc(Func == init_per_suite),
FuncSpec = group_or_func(Func,Config),
- ct_event:notify(#event{name=tc_start,
- node=node(),
- data={Mod,FuncSpec}}),
+ initialize((Func==init_per_suite),Mod,FuncSpec),
case catch configure(MergedInfo,MergedInfo,SuiteInfo,
FuncSpec,[],Config) of
@@ -268,6 +264,18 @@ init_tc2(Mod,Suite,Func,HookFunc,SuiteInfo,MergeResult,Config) ->
end
end.
+initialize(RefreshLogs,Mod,Func,[Config]) when is_list(Config) ->
+ initialize(RefreshLogs,Mod,group_or_func(Func,Config));
+initialize(RefreshLogs,Mod,Func,_) ->
+ initialize(RefreshLogs,Mod,Func).
+
+initialize(RefreshLogs,Mod,FuncSpec) ->
+ ct_logs:init_tc(RefreshLogs),
+ ct_event:notify(#event{name=tc_start,
+ node=node(),
+ data={Mod,FuncSpec}}).
+
+
ct_suite_init(Suite,HookFunc,PostInitHook,Config) when is_list(Config) ->
case ct_hooks:init_tc(Suite,HookFunc,Config) of
NewConfig when is_list(NewConfig) ->
@@ -307,7 +315,7 @@ add_defaults(Mod,Func, GroupPath) ->
"~w:suite/0 failed: ~p~n",
[Suite,Reason]),
io:format(ErrStr, []),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
{suite0_failed,{exited,Reason}};
SuiteInfo when is_list(SuiteInfo) ->
case lists:all(fun(E) when is_tuple(E) -> true;
@@ -330,7 +338,7 @@ add_defaults(Mod,Func, GroupPath) ->
"~w:suite/0: ~p~n",
[Suite,SuiteInfo]),
io:format(ErrStr, []),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
{suite0_failed,bad_return_value}
end;
SuiteInfo ->
@@ -338,7 +346,7 @@ add_defaults(Mod,Func, GroupPath) ->
"Invalid return value from "
"~w:suite/0: ~p~n", [Suite,SuiteInfo]),
io:format(ErrStr, []),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
{suite0_failed,bad_return_value}
end.
@@ -366,7 +374,7 @@ add_defaults1(Mod,Func, GroupPath, SuiteInfo) ->
"~w:group(~w): ~p~n",
[Mod,GrName,BadGr0Val]),
io:format(Gr0ErrStr, []),
- io:format(user, Gr0ErrStr, []),
+ io:format(?def_gl, Gr0ErrStr, []),
{group0_failed,bad_return_value};
_ ->
Args = if Func == init_per_group ; Func == end_per_group ->
@@ -388,7 +396,7 @@ add_defaults1(Mod,Func, GroupPath, SuiteInfo) ->
"~w:~w/0: ~p~n",
[Mod,Func,BadTC0Val]),
io:format(TC0ErrStr, []),
- io:format(user, TC0ErrStr, []),
+ io:format(?def_gl, TC0ErrStr, []),
{testcase0_failed,bad_return_value};
_ ->
%% let test case info (also for all config funcs) override
@@ -675,22 +683,35 @@ end_tc(Mod,Func,{Result,[Args]}, Return) ->
end_tc(Mod,Func,self(),Result,Args,Return).
end_tc(Mod,IPTC={init_per_testcase,_Func},_TCPid,Result,Args,Return) ->
- %% in case Mod == ct_framework, lookup the suite name
- Suite = get_suite_name(Mod, Args),
- case ct_hooks:end_tc(Suite,IPTC,Args,Result,Return) of
- '$ct_no_change' ->
- ok;
- HookResult ->
- HookResult
+ case end_hook_func(IPTC,Return,IPTC) of
+ undefined -> ok;
+ _ ->
+ %% in case Mod == ct_framework, lookup the suite name
+ Suite = get_suite_name(Mod, Args),
+ case ct_hooks:end_tc(Suite,IPTC,Args,Result,Return) of
+ '$ct_no_change' ->
+ ok;
+ HookResult ->
+ HookResult
+ end
end;
end_tc(Mod,Func0,TCPid,Result,Args,Return) ->
%% in case Mod == ct_framework, lookup the suite name
Suite = get_suite_name(Mod, Args),
- {EPTC,Func} = case Func0 of
- {end_per_testcase,F} -> {true,F};
- _ -> {false,Func0}
- end,
+ {Func,FuncSpec,HookFunc} =
+ case Func0 of
+ {end_per_testcase_not_run,F} ->
+ %% Testcase is completed (skipped or failed), but
+ %% end_per_testcase is not run - don't call post-hook.
+ {F,F,undefined};
+ {end_per_testcase,F} ->
+ {F,F,Func0};
+ _ ->
+ FS = group_or_func(Func0,Args),
+ HF = end_hook_func(Func0,Return,FS),
+ {Func0,FS,HF}
+ end,
test_server:timetrap_cancel(),
@@ -717,20 +738,18 @@ end_tc(Mod,Func0,TCPid,Result,Args,Return) ->
end,
ct_util:delete_suite_data(last_saved_config),
- {FuncSpec,HookFunc} =
- if not EPTC ->
- FS = group_or_func(Func,Args),
- {FS,FS};
- true ->
- {Func,Func0}
- end,
{Result1,FinalNotify} =
- case ct_hooks:end_tc(Suite,HookFunc,Args,Result,Return) of
- '$ct_no_change' ->
- {ok,Result};
- HookResult ->
- {HookResult,HookResult}
- end,
+ case HookFunc of
+ undefined ->
+ {ok,Result};
+ _ ->
+ case ct_hooks:end_tc(Suite,HookFunc,Args,Result,Return) of
+ '$ct_no_change' ->
+ {ok,Result};
+ HookResult ->
+ {HookResult,HookResult}
+ end
+ end,
FinalResult =
case get('$test_server_framework_test') of
undefined ->
@@ -821,6 +840,34 @@ end_tc(Mod,Func0,TCPid,Result,Args,Return) ->
end,
FinalResult.
+%% This is to make sure that no post_init_per_* is ever called if the
+%% corresponding pre_init_per_* was not called.
+%% The skip or fail reasons are those that can be returned from
+%% init_tc above in situations where we never came to call
+%% ct_hooks:init_tc/3, e.g. if suite/0 fails, then we never call
+%% ct_hooks:init_tc for init_per_suite, and thus we must not call
+%% ct_hooks:end_tc for init_per_suite either.
+end_hook_func({init_per_testcase,_},{auto_skip,{sequence_failed,_,_}},_) ->
+ undefined;
+end_hook_func({init_per_testcase,_},{auto_skip,"Repeated test stopped by force_stop option"},_) ->
+ undefined;
+end_hook_func({init_per_testcase,_},{fail,{config_name_already_in_use,_}},_) ->
+ undefined;
+end_hook_func({init_per_testcase,_},{auto_skip,{InfoFuncError,_}},_)
+ when InfoFuncError==testcase0_failed;
+ InfoFuncError==require_failed ->
+ undefined;
+end_hook_func(init_per_group,{auto_skip,{InfoFuncError,_}},_)
+ when InfoFuncError==group0_failed;
+ InfoFuncError==require_failed ->
+ undefined;
+end_hook_func(init_per_suite,{auto_skip,{require_failed_in_suite0,_}},_) ->
+ undefined;
+end_hook_func(init_per_suite,{auto_skip,{failed,{error,{suite0_failed,_}}}},_) ->
+ undefined;
+end_hook_func(_,_,Default) ->
+ Default.
+
%% {error,Reason} | {skip,Reason} | {timetrap_timeout,TVal} |
%% {testcase_aborted,Reason} | testcase_aborted_or_killed |
%% {'EXIT',Reason} | {fail,Reason} | {failed,Reason} |
@@ -927,7 +974,7 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
Div = "~n- - - - - - - - - - - - - - - - - - - "
"- - - - - - - - - - - - - - - - - - - - -~n",
ErrorStr2 = io_lib:format(ErrorFormat, ErrorArgs),
- io:format(user, lists:concat([Div,ErrorStr2,Div,"~n"]),
+ io:format(?def_gl, lists:concat([Div,ErrorStr2,Div,"~n"]),
[]),
Link =
"\n\n<a href=\"#end\">"
@@ -1133,7 +1180,7 @@ get_all(Mod, ConfTests) ->
ErrStr = io_lib:format("~n*** ERROR *** "
"~w:all/0 failed: ~p~n",
[Mod,ExitReason]),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
%% save the error info so it doesn't get printed twice
ct_util:set_testdata_async({{error_in_suite,Mod},
ExitReason});
@@ -1339,25 +1386,25 @@ report(What,Data) ->
ok;
tc_done ->
{Suite,{Func,GrName},Result} = Data,
- Data1 = if GrName == undefined -> {Suite,Func,Result};
- true -> Data
- end,
+ FuncSpec = if GrName == undefined -> Func;
+ true -> {Func,GrName}
+ end,
%% Register the group leader for the process calling the report
%% function, making it possible for a hook function to print
%% in the test case log file
ReportingPid = self(),
ct_logs:register_groupleader(ReportingPid, group_leader()),
case Result of
- {failed, _} ->
- ct_hooks:on_tc_fail(What, Data1);
- {skipped,{failed,{_,init_per_testcase,_}}} ->
- ct_hooks:on_tc_skip(tc_auto_skip, Data1);
- {skipped,{require_failed,_}} ->
- ct_hooks:on_tc_skip(tc_auto_skip, Data1);
- {skipped,_} ->
- ct_hooks:on_tc_skip(tc_user_skip, Data1);
- {auto_skipped,_} ->
- ct_hooks:on_tc_skip(tc_auto_skip, Data1);
+ {failed, Reason} ->
+ ct_hooks:on_tc_fail(What, {Suite,FuncSpec,Reason});
+ {skipped,{failed,{_,init_per_testcase,_}}=Reason} ->
+ ct_hooks:on_tc_skip(tc_auto_skip, {Suite,FuncSpec,Reason});
+ {skipped,{require_failed,_}=Reason} ->
+ ct_hooks:on_tc_skip(tc_auto_skip, {Suite,FuncSpec,Reason});
+ {skipped,Reason} ->
+ ct_hooks:on_tc_skip(tc_user_skip, {Suite,FuncSpec,Reason});
+ {auto_skipped,Reason} ->
+ ct_hooks:on_tc_skip(tc_auto_skip, {Suite,FuncSpec,Reason});
_Else ->
ok
end,
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 23ba1ab981..8b59d3ab23 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -27,7 +27,7 @@
-export([start/4, stop/1, get_conn_pid/1, check_opts/1]).
-export([call/2, call/3, return/2, do_within_time/2]).
--export([log/3, start_log/1, cont_log/2, end_log/0]).
+-export([log/3, start_log/1, cont_log/2, cont_log_no_timestamp/2, end_log/0]).
%%----------------------------------------------------------------------
%% Exported types
@@ -175,6 +175,14 @@ cont_log(Format,Args) ->
log(cont_log,[Format,Args]).
%%%-----------------------------------------------------------------
+%%% @spec cont_log_no_timestamp(Format,Args) -> ok
+%%%
+%%% @doc Log activities on the current connection (tool-internal use only).
+%%% @see ct_logs:cont_log/2
+cont_log_no_timestamp(Format,Args) ->
+ log(cont_log_no_timestamp,[Format,Args]).
+
+%%%-----------------------------------------------------------------
%%% @spec end_log() -> ok
%%%
%%% @doc Log activities on the current connection (tool-internal use only).
diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl
index 1375e7dcc7..333151ee1b 100644
--- a/lib/common_test/src/ct_groups.erl
+++ b/lib/common_test/src/ct_groups.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -442,17 +442,21 @@ make_conf(Mod, Name, Props, TestSpec) ->
ok
end,
{InitConf,EndConf,ExtraProps} =
- case erlang:function_exported(Mod,init_per_group,2) of
- true ->
- {{Mod,init_per_group},{Mod,end_per_group},[]};
- false ->
+ case {erlang:function_exported(Mod,init_per_group,2),
+ erlang:function_exported(Mod,end_per_group,2)} of
+ {false,false} ->
ct_logs:log("TEST INFO", "init_per_group/2 and "
"end_per_group/2 missing for group "
"~w in ~w, using default.",
[Name,Mod]),
{{ct_framework,init_per_group},
{ct_framework,end_per_group},
- [{suite,Mod}]}
+ [{suite,Mod}]};
+ _ ->
+ %% If any of these exist, the other should too
+ %% (required and documented). If it isn't, it will fail
+ %% with reason 'undef'.
+ {{Mod,init_per_group},{Mod,end_per_group},[]}
end,
{conf,[{name,Name}|Props++ExtraProps],InitConf,TestSpec,EndConf}.
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index c9a4abb5ee..8cdc6d8c75 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,15 +92,17 @@ 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, 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]);
-init_tc(_Mod, {init_per_testcase,TC}, Config) ->
- call(fun call_generic/3, Config, [pre_init_per_testcase, TC]);
-init_tc(_Mod, {end_per_testcase,TC}, Config) ->
- call(fun call_generic/3, Config, [pre_end_per_testcase, TC]);
-init_tc(_Mod, TC = error_in_suite, Config) ->
- call(fun call_generic/3, Config, [pre_init_per_testcase, TC]).
+ call(fun call_generic_fallback/3, Config,
+ [pre_init_per_group, Mod, GroupName]);
+init_tc(Mod, {end_per_group, GroupName, _}, Config) ->
+ call(fun call_generic_fallback/3, Config,
+ [pre_end_per_group, Mod, GroupName]);
+init_tc(Mod, {init_per_testcase,TC}, Config) ->
+ call(fun call_generic_fallback/3, Config, [pre_init_per_testcase, Mod, TC]);
+init_tc(Mod, {end_per_testcase,TC}, Config) ->
+ call(fun call_generic_fallback/3, Config, [pre_end_per_testcase, Mod, TC]);
+init_tc(Mod, TC = error_in_suite, Config) ->
+ call(fun call_generic_fallback/3, Config, [pre_init_per_testcase, Mod, TC]).
%% @doc Called as each test case is completed. This includes all configuration
%% tests.
@@ -126,23 +128,23 @@ end_tc(Mod, init_per_suite, Config, _Result, Return) ->
end_tc(Mod, end_per_suite, Config, Result, _Return) ->
call(fun call_generic/3, Result, [post_end_per_suite, Mod, Config],
'$ct_no_change');
-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, {init_per_group, GroupName, _}, Config, _Result, Return) ->
+ call(fun call_generic_fallback/3, Return,
+ [post_init_per_group, Mod, GroupName, Config], '$ct_no_change');
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'),
+ Res = call(fun call_generic_fallback/3, Result,
+ [post_end_per_group, Mod, GroupName, Config], '$ct_no_change'),
maybe_stop_locker(Mod, GroupName, Properties),
Res;
-end_tc(_Mod, {init_per_testcase,TC}, Config, Result, _Return) ->
- call(fun call_generic/3, Result, [post_init_per_testcase, TC, Config],
- '$ct_no_change');
-end_tc(_Mod, {end_per_testcase,TC}, Config, Result, _Return) ->
- call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config],
- '$ct_no_change');
-end_tc(_Mod, TC = error_in_suite, Config, Result, _Return) ->
- call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config],
- '$ct_no_change').
+end_tc(Mod, {init_per_testcase,TC}, Config, Result, _Return) ->
+ call(fun call_generic_fallback/3, Result,
+ [post_init_per_testcase, Mod, TC, Config], '$ct_no_change');
+end_tc(Mod, {end_per_testcase,TC}, Config, Result, _Return) ->
+ call(fun call_generic_fallback/3, Result,
+ [post_end_per_testcase, Mod, TC, Config], '$ct_no_change');
+end_tc(Mod, TC = error_in_suite, Config, Result, _Return) ->
+ call(fun call_generic_fallback/3, Result,
+ [post_end_per_testcase, Mod, TC, Config], '$ct_no_change').
%% Case = TestCase | {TestCase,GroupName}
@@ -181,15 +183,21 @@ call_terminate(#ct_hook_config{ module = Mod, state = State} = Hook, _, _) ->
{[],Hook}.
call_cleanup(#ct_hook_config{ module = Mod, state = State} = Hook,
- Reason, [Function, _Suite | Args]) ->
+ Reason, [Function | Args]) ->
NewState = catch_apply(Mod,Function, Args ++ [Reason, State],
- State),
+ State, true),
{Reason, Hook#ct_hook_config{ state = NewState } }.
-call_generic(#ct_hook_config{ module = Mod, state = State} = Hook,
- Value, [Function | Args]) ->
+call_generic(Hook, Value, Meta) ->
+ do_call_generic(Hook, Value, Meta, false).
+
+call_generic_fallback(Hook, Value, Meta) ->
+ do_call_generic(Hook, Value, Meta, true).
+
+do_call_generic(#ct_hook_config{ module = Mod, state = State} = Hook,
+ Value, [Function | Args], Fallback) ->
{NewValue, NewState} = catch_apply(Mod, Function, Args ++ [Value, State],
- {Value,State}),
+ {Value,State}, Fallback),
{NewValue, Hook#ct_hook_config{ state = NewState } }.
%% Generic call function
@@ -257,15 +265,15 @@ remove(Key,List) when is_list(List) ->
remove(_, Else) ->
Else.
-%% Translate scopes, i.e. init_per_group,group1 -> end_per_group,group1 etc
-scope([pre_init_per_testcase, TC|_]) ->
- [post_init_per_testcase, TC];
-scope([pre_end_per_testcase, TC|_]) ->
- [post_end_per_testcase, TC];
-scope([pre_init_per_group, GroupName|_]) ->
- [post_end_per_group, GroupName];
-scope([post_init_per_group, GroupName|_]) ->
- [post_end_per_group, GroupName];
+%% Translate scopes, i.e. is_tuplenit_per_group,group1 -> end_per_group,group1 etc
+scope([pre_init_per_testcase, SuiteName, TC|_]) ->
+ [post_init_per_testcase, SuiteName, TC];
+scope([pre_end_per_testcase, SuiteName, TC|_]) ->
+ [post_end_per_testcase, SuiteName, TC];
+scope([pre_init_per_group, SuiteName, GroupName|_]) ->
+ [post_end_per_group, SuiteName, GroupName];
+scope([post_init_per_group, SuiteName, GroupName|_]) ->
+ [post_end_per_group, SuiteName, GroupName];
scope([pre_init_per_suite, SuiteName|_]) ->
[post_end_per_suite, SuiteName];
scope([post_init_per_suite, SuiteName|_]) ->
@@ -273,14 +281,29 @@ scope([post_init_per_suite, SuiteName|_]) ->
scope(init) ->
none.
-terminate_if_scope_ends(HookId, [on_tc_skip,_Suite,{end_per_group,Name}],
+strip_config([post_init_per_testcase, SuiteName, TC|_]) ->
+ [post_init_per_testcase, SuiteName, TC];
+strip_config([post_end_per_testcase, SuiteName, TC|_]) ->
+ [post_end_per_testcase, SuiteName, TC];
+strip_config([post_init_per_group, SuiteName, GroupName|_]) ->
+ [post_init_per_group, SuiteName, GroupName];
+strip_config([post_end_per_group, SuiteName, GroupName|_]) ->
+ [post_end_per_group, SuiteName, GroupName];
+strip_config([post_init_per_suite, SuiteName|_]) ->
+ [post_init_per_suite, SuiteName];
+strip_config([post_end_per_suite, SuiteName|_]) ->
+ [post_end_per_suite, SuiteName];
+strip_config(Other) ->
+ Other.
+
+
+terminate_if_scope_ends(HookId, [on_tc_skip,Suite,{end_per_group,Name}],
Hooks) ->
- terminate_if_scope_ends(HookId, [post_end_per_group, Name], Hooks);
+ terminate_if_scope_ends(HookId, [post_end_per_group, Suite, Name], Hooks);
terminate_if_scope_ends(HookId, [on_tc_skip,Suite,end_per_suite], Hooks) ->
terminate_if_scope_ends(HookId, [post_end_per_suite, Suite], Hooks);
-terminate_if_scope_ends(HookId, [Function,Tag|T], Hooks) when T =/= [] ->
- terminate_if_scope_ends(HookId,[Function,Tag],Hooks);
-terminate_if_scope_ends(HookId, Function, Hooks) ->
+terminate_if_scope_ends(HookId, Function0, Hooks) ->
+ Function = strip_config(Function0),
case lists:keyfind(HookId, #ct_hook_config.id, Hooks) of
#ct_hook_config{ id = HookId, scope = Function} = Hook ->
terminate([Hook]),
@@ -384,21 +407,29 @@ pos(Id,[_|Rest],Num) ->
catch_apply(M,F,A, Default) ->
+ catch_apply(M,F,A,Default,false).
+catch_apply(M,F,A, Default, Fallback) ->
+ not erlang:module_loaded(M) andalso (catch M:module_info()),
+ case erlang:function_exported(M,F,length(A)) of
+ false when Fallback ->
+ catch_apply(M,F,tl(A),Default,false);
+ false ->
+ Default;
+ true ->
+ catch_apply(M,F,A)
+ end.
+
+catch_apply(M,F,A) ->
try
- erlang:apply(M,F,A)
+ erlang:apply(M,F,A)
catch _:Reason ->
- case erlang:get_stacktrace() of
- %% Return the default if it was the CTH module which did not have the function.
- [{M,F,A,_}|_] when Reason == undef ->
- Default;
- Trace ->
- ct_logs:log("Suite Hook","Call to CTH failed: ~w:~p",
- [error,{Reason,Trace}]),
- throw({error_in_cth_call,
- lists:flatten(
- io_lib:format("~w:~w/~w CTH call failed",
- [M,F,length(A)]))})
- end
+ Trace = erlang:get_stacktrace(),
+ ct_logs:log("Suite Hook","Call to CTH failed: ~w:~p",
+ [error,{Reason,Trace}]),
+ throw({error_in_cth_call,
+ lists:flatten(
+ io_lib:format("~w:~w/~w CTH call failed",
+ [M,F,length(A)]))})
end.
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 53245c596a..09ad709da5 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -32,7 +32,7 @@
-export([init/2, close/2, init_tc/1, end_tc/1]).
-export([register_groupleader/2, unregister_groupleader/1]).
-export([get_log_dir/0, get_log_dir/1]).
--export([log/3, start_log/1, cont_log/2, end_log/0]).
+-export([log/3, start_log/1, cont_log/2, cont_log_no_timestamp/2, end_log/0]).
-export([set_stylesheet/2, clear_stylesheet/1]).
-export([add_external_logs/1, add_link/3]).
-export([make_last_run_index/0]).
@@ -45,8 +45,8 @@
%% Logging stuff directly from testcase
-export([tc_log/3, tc_log/4, tc_log/5, tc_log/6,
tc_log_async/3, tc_log_async/5,
- tc_print/3, tc_print/4,
- tc_pal/3, tc_pal/4, ct_log/3,
+ tc_print/3, tc_print/4, tc_print/5,
+ tc_pal/3, tc_pal/4, tc_pal/5, ct_log/3,
basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -373,6 +373,20 @@ cont_log(Format,Args) ->
ok.
%%%-----------------------------------------------------------------
+%%% @spec cont_log_no_timestamp(Format,Args) -> ok
+%%%
+%%% @doc Adds information about an activity (tool-internal use only).
+%%%
+%%% @see start_log/1
+%%% @see end_log/0
+cont_log_no_timestamp([],[]) ->
+ ok;
+cont_log_no_timestamp(Format,Args) ->
+ cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
+ [{Format,Args}],true}),
+ ok.
+
+%%%-----------------------------------------------------------------
%%% @spec end_log() -> ok
%%%
%%% @doc Ends the logging of an activity (tool-internal use only).
@@ -433,10 +447,10 @@ tc_log(Category,Importance,Format,Args,Opts) ->
tc_log(Category,Importance,"User",Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Printer,Format,Args,Opts) -> ok
+%%% @spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
-%%% Printer = string()
+%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
@@ -446,13 +460,18 @@ tc_log(Category,Importance,Format,Args,Opts) ->
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase (i.e. not from within the CT
%%% framework).</p>
-tc_log(Category,Importance,Printer,Format,Args,Opts) ->
+tc_log(Category,Importance,Heading,Format,Args,Opts) ->
Data =
case lists:member(no_css, Opts) of
true ->
[{Format,Args}];
false ->
- [{hd,div_header(Category,Printer),[]},
+ Heading1 =
+ case proplists:get_value(heading, Opts) of
+ undefined -> Heading;
+ Str -> Str
+ end,
+ [{hd,div_header(Category,Heading1),[]},
{Format,Args},
{ft,div_footer(),[]}]
end,
@@ -470,7 +489,7 @@ tc_log_async(Category,Format,Args) ->
%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
-%%% Printer = string()
+%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -481,31 +500,38 @@ tc_log_async(Category,Format,Args) ->
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
%%% asks ct_logs for an html wrapper.</p>
-tc_log_async(Category,Importance,Printer,Format,Args) ->
+tc_log_async(Category,Importance,Heading,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
- [{hd,div_header(Category,Printer),[]},
+ [{hd,div_header(Category,Heading),[]},
{Format,Args},
{ft,div_footer(),[]}],
true}),
ok.
%%%-----------------------------------------------------------------
%%% @spec tc_print(Category,Format,Args)
-%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args)
+%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
tc_print(Category,Format,Args) ->
- tc_print(Category,?STD_IMPORTANCE,Format,Args).
+ tc_print(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args) -> ok
+%%% @spec tc_print(Category,Importance,Format,Args)
+%%% @equiv tc_print(Category,Importance,Format,Args,[])
+tc_print(Category,Importance,Format,Args) ->
+ tc_print(Category,Importance,Format,Args,[]).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = list()
%%%
%%% @doc Console printout from a testcase.
%%%
%%% <p>This function is called by <code>ct</code> when printing
%%% stuff from a testcase on the user console.</p>
-tc_print(Category,Importance,Format,Args) ->
+tc_print(Category,Importance,Format,Args,Opts) ->
VLvl = case ct_util:get_verbosity(Category) of
undefined ->
ct_util:get_verbosity('$unspecified');
@@ -517,50 +543,61 @@ tc_print(Category,Importance,Format,Args) ->
Val
end,
if Importance >= (100-VLvl) ->
- Head = get_heading(Category),
- io:format(user, lists:concat([Head,Format,"\n\n"]), Args),
+ Heading =
+ case proplists:get_value(heading, Opts) of
+ undefined -> atom_to_list(Category);
+ Hd -> Hd
+ end,
+ Str = lists:concat([get_header(Heading),Format,"\n\n"]),
+ try
+ io:format(?def_gl, Str, Args)
+ catch
+ %% default group leader probably not started, or has stopped
+ _:_ -> io:format(user, Str, Args)
+ end,
ok;
true ->
ok
end.
-get_heading(default) ->
+get_header("default") ->
io_lib:format("\n-----------------------------"
"-----------------------\n~s\n",
[log_timestamp(?now)]);
-get_heading(Category) ->
+get_header(Heading) ->
io_lib:format("\n-----------------------------"
- "-----------------------\n~s ~w\n",
- [log_timestamp(?now),Category]).
+ "-----------------------\n~s ~s\n",
+ [Heading,log_timestamp(?now)]).
%%%-----------------------------------------------------------------
%%% @spec tc_pal(Category,Format,Args) -> ok
-%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args) -> ok
+%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
tc_pal(Category,Format,Args) ->
- tc_pal(Category,?STD_IMPORTANCE,Format,Args).
+ tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec tc_pal(Category,Importance,Format,Args) -> ok
+%%% @equiv tc_pal(Category,Importance,Format,Args,[]) -> ok
+tc_pal(Category,Importance,Format,Args) ->
+ tc_pal(Category,Importance,Format,Args,[]).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = list()
%%%
%%% @doc Print and log from a testcase.
%%%
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase. The info is written both in the
%%% log and on the console.</p>
-tc_pal(Category,Importance,Format,Args) ->
- tc_print(Category,Importance,Format,Args),
- cast({log,sync,self(),group_leader(),Category,Importance,
- [{hd,div_header(Category),[]},
- {Format,Args},
- {ft,div_footer(),[]}],
- true}),
- ok.
-
+tc_pal(Category,Importance,Format,Args,Opts) ->
+ tc_print(Category,Importance,Format,Args,Opts),
+ tc_log(Category,Importance,"User",Format,Args,[esc_chars|Opts]).
%%%-----------------------------------------------------------------
%%% @spec ct_log(Category,Format,Args) -> ok
@@ -589,13 +626,12 @@ int_footer() ->
div_header(Class) ->
div_header(Class,"User").
-div_header(Class,Printer) ->
+div_header(Class,Heading) ->
"\n</pre>\n<div class=\"" ++ atom_to_list(Class) ++ "\"><pre><b>*** "
- ++ Printer ++ " " ++ log_timestamp(?now) ++ " ***</b>".
+ ++ Heading ++ " " ++ log_timestamp(?now) ++ " ***</b>".
div_footer() ->
"</pre></div>\n<pre>".
-
maybe_log_timestamp() ->
{MS,S,US} = ?now,
case get(log_timestamp) of
@@ -666,7 +702,7 @@ logger(Parent, Mode, Verbosity) ->
PrivFilesDestRun = [filename:join(AbsDir, F) || F <- PrivFiles],
case copy_priv_files(PrivFilesSrc, PrivFilesDestTop) of
{error,Src1,Dest1,Reason1} ->
- io:format(user, "ERROR! "++
+ io:format(?def_gl, "ERROR! "++
"Priv file ~p could not be copied to ~p. "++
"Reason: ~p~n",
[Src1,Dest1,Reason1]),
@@ -674,7 +710,7 @@ logger(Parent, Mode, Verbosity) ->
ok ->
case copy_priv_files(PrivFilesSrc, PrivFilesDestRun) of
{error,Src2,Dest2,Reason2} ->
- io:format(user,
+ io:format(?def_gl,
"ERROR! "++
"Priv file ~p could not be copied to ~p. "
++"Reason: ~p~n",
diff --git a/lib/common_test/src/ct_make.erl b/lib/common_test/src/ct_make.erl
index e7a9cfa843..f22959d457 100644
--- a/lib/common_test/src/ct_make.erl
+++ b/lib/common_test/src/ct_make.erl
@@ -342,5 +342,7 @@ check_includes2(Epp, File, ObjMTime) ->
epp:close(Epp),
false;
{error, _Error} ->
+ check_includes2(Epp, File, ObjMTime);
+ {warning, _Warning} ->
check_includes2(Epp, File, ObjMTime)
end.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index fbb9c7ab60..10e62e18b8 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,8 +76,8 @@
abort_if_missing_suites,
silent_connections = [],
stylesheet,
- multiply_timetraps = 1,
- scale_timetraps = false,
+ multiply_timetraps,
+ scale_timetraps,
create_priv_dir,
testspec_files = [],
current_testspec,
@@ -264,11 +264,11 @@ script_start1(Parent, Args) ->
[], Args),
Verbosity = verbosity_args2opts(Args),
MultTT = get_start_opt(multiply_timetraps,
- fun([MT]) -> list_to_integer(MT) end, 1, Args),
+ fun([MT]) -> list_to_integer(MT) end, Args),
ScaleTT = get_start_opt(scale_timetraps,
fun([CT]) -> list_to_atom(CT);
([]) -> true
- end, false, Args),
+ end, Args),
CreatePrivDir = get_start_opt(create_priv_dir,
fun([PD]) -> list_to_atom(PD);
([]) -> auto_per_tc
@@ -1055,8 +1055,8 @@ run_test2(StartOpts) ->
CoverStop = get_start_opt(cover_stop, value, StartOpts),
%% timetrap manipulation
- MultiplyTT = get_start_opt(multiply_timetraps, value, 1, StartOpts),
- ScaleTT = get_start_opt(scale_timetraps, value, false, StartOpts),
+ MultiplyTT = get_start_opt(multiply_timetraps, value, StartOpts),
+ ScaleTT = get_start_opt(scale_timetraps, value, StartOpts),
%% create unique priv dir names
CreatePrivDir = get_start_opt(create_priv_dir, value, StartOpts),
@@ -2155,8 +2155,8 @@ continue(_MakeErrors, true) ->
false;
continue(_MakeErrors, _AbortIfMissingSuites) ->
io:nl(),
- OldGl = group_leader(),
- case set_group_leader_same_as_shell() of
+ OldGL = group_leader(),
+ case set_group_leader_same_as_shell(OldGL) of
true ->
S = self(),
io:format("Failed to compile or locate one "
@@ -2172,7 +2172,7 @@ continue(_MakeErrors, _AbortIfMissingSuites) ->
S ! false
end
end),
- group_leader(OldGl, self()),
+ group_leader(OldGL, self()),
receive R when R==true; R==false ->
R
after 15000 ->
@@ -2184,7 +2184,9 @@ continue(_MakeErrors, _AbortIfMissingSuites) ->
true
end.
-set_group_leader_same_as_shell() ->
+set_group_leader_same_as_shell(OldGL) ->
+ %% find the group leader process on the node in a dirty fashion
+ %% (check initial function call and look in the process dictionary)
GS2or3 = fun(P) ->
case process_info(P,initial_call) of
{initial_call,{group,server,X}} when X == 2 ; X == 3 ->
@@ -2197,7 +2199,10 @@ set_group_leader_same_as_shell() ->
true == lists:keymember(shell,1,
element(2,process_info(P,dictionary)))] of
[GL|_] ->
- group_leader(GL, self());
+ %% check if started from remote node (skip interaction)
+ if node(OldGL) /= node(GL) -> false;
+ true -> group_leader(GL, self())
+ end;
[] ->
false
end.
@@ -2275,8 +2280,19 @@ do_run_test(Tests, Skip, Opts0) ->
_Lower ->
ok
end,
- test_server_ctrl:multiply_timetraps(Opts0#opts.multiply_timetraps),
- test_server_ctrl:scale_timetraps(Opts0#opts.scale_timetraps),
+
+ case Opts0#opts.multiply_timetraps of
+ undefined -> MultTT = 1;
+ MultTT -> MultTT
+ end,
+ case Opts0#opts.scale_timetraps of
+ undefined -> ScaleTT = false;
+ ScaleTT -> ScaleTT
+ end,
+ ct_logs:log("TEST INFO","Timetrap time multiplier = ~w~n"
+ "Timetrap scaling enabled = ~w", [MultTT,ScaleTT]),
+ test_server_ctrl:multiply_timetraps(MultTT),
+ test_server_ctrl:scale_timetraps(ScaleTT),
test_server_ctrl:create_priv_dir(choose_val(
Opts0#opts.create_priv_dir,
diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl
index 2c59b19196..5844909d17 100644
--- a/lib/common_test/src/ct_snmp.erl
+++ b/lib/common_test/src/ct_snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 8fb411ec4f..bff1112ab9 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -954,7 +954,7 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
true ->
ok;
false ->
- ct_gen_conn:cont_log(String,Args)
+ ct_gen_conn:cont_log_no_timestamp(String,Args)
end;
ForcePrint == true ->
@@ -965,7 +965,7 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
%% called
ct_gen_conn:log(heading(Action,Name1),String,Args);
false ->
- ct_gen_conn:cont_log(String,Args)
+ ct_gen_conn:cont_log_no_timestamp(String,Args)
end
end
end.
@@ -1224,7 +1224,6 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO,
EOMod = if TotalTO /= infinity -> EO#eo{total_timeout=trunc(TotalTO)};
true -> EO
end,
-
ExpectFun = case EOMod#eo.seq of
true -> fun() ->
seq_expect(Name,Pid,Data,Pattern,Acc,EOMod)
@@ -1247,38 +1246,34 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO,
true ->
IdleTO
end,
+ {PatOrPats1,Acc1,Rest1} = case NotFinished of
+ {nomatch,Rest0} ->
+ %% one expect
+ {Pattern,[],Rest0};
+ {continue,Pats0,Acc0,Rest0} ->
+ %% sequence
+ {Pats0,Acc0,Rest0}
+ end,
case timer:tc(ct_gen_conn, do_within_time, [Fun,BreakAfter]) of
- {_,{error,Reason}} ->
+ {_,{error,Reason}} ->
%% A timeout will occur when the telnet connection
%% is idle for EO#eo.idle_timeout milliseconds.
+ if Rest1 /= [] ->
+ log(name_or_pid(Name,Pid)," ~ts",[Rest1]);
+ true ->
+ ok
+ end,
{error,Reason};
{_,{ok,Data1}} when TotalTO == infinity ->
- case NotFinished of
- {nomatch,Rest} ->
- %% One expect
- teln_expect1(Name,Pid,Rest++Data1,
- Pattern,[],EOMod);
- {continue,Patterns1,Acc1,Rest} ->
- %% Sequence
- teln_expect1(Name,Pid,Rest++Data1,
- Patterns1,Acc1,EOMod)
- end;
+ teln_expect1(Name,Pid,Rest1++Data1,PatOrPats1,Acc1,EOMod);
{Elapsed,{ok,Data1}} ->
TVal = 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
+ teln_expect1(Name,Pid,Rest1++Data1,
+ PatOrPats1,Acc1,EO1)
end
end
end.
@@ -1416,14 +1411,14 @@ match_lines(Name,Pid,Data,Patterns,EO) ->
case one_line(Data,[]) of
{noline,Rest} when FoundPrompt=/=false ->
%% This is the line including the prompt
- case match_line(Name,Pid,Rest,Patterns,FoundPrompt,EO) of
+ case match_line(Name,Pid,Rest,Patterns,FoundPrompt,false,EO) of
nomatch ->
{nomatch,prompt};
{Tag,Match} ->
{Tag,Match,[]}
end;
{noline,Rest} when EO#eo.prompt_check==false ->
- case match_line(Name,Pid,Rest,Patterns,false,EO) of
+ case match_line(Name,Pid,Rest,Patterns,false,false,EO) of
nomatch ->
{nomatch,Rest};
{Tag,Match} ->
@@ -1432,7 +1427,7 @@ match_lines(Name,Pid,Data,Patterns,EO) ->
{noline,Rest} ->
{nomatch,Rest};
{Line,Rest} ->
- case match_line(Name,Pid,Line,Patterns,false,EO) of
+ case match_line(Name,Pid,Line,Patterns,false,true,EO) of
nomatch ->
match_lines(Name,Pid,Rest,Patterns,EO);
{Tag,Match} ->
@@ -1440,45 +1435,50 @@ match_lines(Name,Pid,Data,Patterns,EO) ->
end
end.
-
%% For one line, match each pattern
-match_line(Name,Pid,Line,Patterns,FoundPrompt,EO) ->
- match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,match).
+match_line(Name,Pid,Line,Patterns,FoundPrompt,Terminated,EO) ->
+ match_line(Name,Pid,Line,Patterns,FoundPrompt,Terminated,EO,match).
-match_line(Name,Pid,Line,[prompt|Patterns],false,EO,RetTag) ->
- match_line(Name,Pid,Line,Patterns,false,EO,RetTag);
-match_line(Name,Pid,Line,[prompt|_Patterns],FoundPrompt,_EO,RetTag) ->
+match_line(Name,Pid,Line,[prompt|Patterns],false,Term,EO,RetTag) ->
+ match_line(Name,Pid,Line,Patterns,false,Term,EO,RetTag);
+match_line(Name,Pid,Line,[prompt|_Patterns],FoundPrompt,_Term,_EO,RetTag) ->
log(name_or_pid(Name,Pid)," ~ts",[Line]),
log(name_or_pid(Name,Pid),"PROMPT: ~ts",[FoundPrompt]),
{RetTag,{prompt,FoundPrompt}};
-match_line(Name,Pid,Line,[{prompt,PromptType}|_Patterns],FoundPrompt,_EO,RetTag)
- when PromptType==FoundPrompt ->
+match_line(Name,Pid,Line,[{prompt,PromptType}|_Patterns],FoundPrompt,_Term,
+ _EO,RetTag) when PromptType==FoundPrompt ->
log(name_or_pid(Name,Pid)," ~ts",[Line]),
log(name_or_pid(Name,Pid),"PROMPT: ~ts",[FoundPrompt]),
{RetTag,{prompt,FoundPrompt}};
-match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,EO,RetTag)
+match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,Term,
+ EO,RetTag)
when PromptType=/=FoundPrompt ->
- match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,RetTag);
-match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,EO,RetTag) ->
+ match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag);
+match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) ->
case re:run(Line,Pattern,[{capture,all,list}]) of
nomatch ->
- match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,RetTag);
+ match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag);
{match,Match} ->
log(name_or_pid(Name,Pid),"MATCH: ~ts",[Line]),
{RetTag,{Tag,Match}}
end;
-match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,EO,RetTag) ->
+match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) ->
case re:run(Line,Pattern,[{capture,all,list}]) of
nomatch ->
- match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,RetTag);
+ match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag);
{match,Match} ->
log(name_or_pid(Name,Pid),"MATCH: ~ts",[Line]),
{RetTag,Match}
end;
-match_line(Name,Pid,Line,[],FoundPrompt,EO,match) ->
- match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,EO,halt);
-match_line(Name,Pid,Line,[],_FoundPrompt,_EO,halt) ->
+match_line(Name,Pid,Line,[],FoundPrompt,Term,EO,match) ->
+ match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,Term,EO,halt);
+%% print any terminated line that can not be matched
+match_line(Name,Pid,Line,[],_FoundPrompt,true,_EO,halt) ->
log(name_or_pid(Name,Pid)," ~ts",[Line]),
+ nomatch;
+%% if there's no line termination, Line is saved as Rest (above) and will
+%% be printed later
+match_line(_Name,_Pid,_Line,[],_FoundPrompt,false,_EO,halt) ->
nomatch.
one_line([$\n|Rest],Line) ->
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 991abb0666..180786273d 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,8 @@
-export([prepare_tests/1, prepare_tests/2,
collect_tests_from_list/2, collect_tests_from_list/3,
- collect_tests_from_file/2, collect_tests_from_file/3]).
+ collect_tests_from_file/2, collect_tests_from_file/3,
+ get_tests/1]).
-export([testspec_rec2list/1, testspec_rec2list/2]).
@@ -803,6 +804,31 @@ list_nodes(#testspec{nodes=NodeRefs}) ->
lists:map(fun({_Ref,Node}) -> Node end, NodeRefs).
+%%%-----------------------------------------------------------------
+%%% Parse the given test specs and return the complete set of specs
+%%% and tests to run/skip.
+%%% [Spec1,Spec2,...] means create separate tests per spec
+%%% [[Spec1,Spec2,...]] means merge all specs into one
+-spec get_tests(Specs) -> {ok,[{Specs,Tests}]} | {error,Reason} when
+ Specs :: [string()] | [[string()]],
+ Tests :: {Node,Run,Skip},
+ Node :: atom(),
+ Run :: {Dir,Suites,Cases},
+ Skip :: {Dir,Suites,Comment} | {Dir,Suites,Cases,Comment},
+ Dir :: string(),
+ Suites :: atom | [atom()] | all,
+ Cases :: atom | [atom()] | all,
+ Comment :: string(),
+ Reason :: term().
+
+get_tests(Specs) ->
+ case collect_tests_from_file(Specs,true) of
+ Tests when is_list(Tests) ->
+ {ok,[{S,prepare_tests(R)} || {S,R} <- Tests]};
+ Error ->
+ Error
+ end.
+
%% -----------------------------------------------------
%% / \
%% | When adding test/config terms, remember to update |
@@ -1132,6 +1158,11 @@ handle_data(verbosity,Node,VLvls,_Spec) when is_list(VLvls) ->
VLvls1 = lists:map(fun(VLvl = {_Cat,_Lvl}) -> VLvl;
(Lvl) -> {'$unspecified',Lvl} end, VLvls),
[{Node,VLvls1}];
+handle_data(multiply_timetraps,Node,Mult,_Spec) when is_integer(Mult) ->
+ [{Node,Mult}];
+handle_data(scale_timetraps,Node,Scale,_Spec) when Scale == true;
+ Scale == false ->
+ [{Node,Scale}];
handle_data(silent_connections,Node,all,_Spec) ->
[{Node,[all]}];
handle_data(silent_connections,Node,Conn,_Spec) when is_atom(Conn) ->
@@ -1150,6 +1181,8 @@ should_be_added(Tag,Node,_Data,Spec) ->
Tag == label; Tag == auto_compile;
Tag == abort_if_missing_suites;
Tag == stylesheet; Tag == verbosity;
+ Tag == multiply_timetraps;
+ Tag == scale_timetraps;
Tag == silent_connections ->
lists:keymember(ref2node(Node,Spec#testspec.nodes),1,
read_field(Spec,Tag)) == false;
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 82a8743cf0..4d3a2ae7e3 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -188,6 +188,8 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
ok
end,
+ ct_default_gl:start_link(group_leader()),
+
{StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),
ct_event:notify(#event{name=test_start,
@@ -474,6 +476,7 @@ loop(Mode,TestData,StartDir) ->
ct_logs:close(Info, StartDir),
ct_event:stop(),
ct_config:stop(),
+ ct_default_gl:stop(),
ok = file:set_cwd(StartDir),
return(From, Info);
{Ref, _Msg} when is_reference(Ref) ->
@@ -926,7 +929,8 @@ warn_duplicates(Suites) ->
[] ->
ok;
_ ->
- io:format(user,"~nWARNING! Deprecated function: ~w:sequences/0.~n"
+ io:format(?def_gl,
+ "~nWARNING! Deprecated function: ~w:sequences/0.~n"
" Use group with sequence property instead.~n",[Mod])
end
end,
@@ -980,12 +984,12 @@ get_profile_data(Profile, Key, StartDir) ->
end,
case Result of
{error,enoent} when Profile /= default ->
- io:format(user, "~nERROR! Missing profile file ~p~n", [File]),
+ io:format(?def_gl, "~nERROR! Missing profile file ~p~n", [File]),
undefined;
{error,enoent} when Profile == default ->
undefined;
{error,Reason} ->
- io:format(user,"~nERROR! Error in profile file ~p: ~p~n",
+ io:format(?def_gl,"~nERROR! Error in profile file ~p: ~p~n",
[WhichFile,Reason]),
undefined;
{ok,Data} ->
@@ -995,7 +999,7 @@ get_profile_data(Profile, Key, StartDir) ->
_ when is_list(Data) ->
Data;
_ ->
- io:format(user,
+ io:format(?def_gl,
"~nERROR! Invalid profile data in ~p~n",
[WhichFile]),
[]
@@ -1082,10 +1086,10 @@ open_url(iexplore, Args, URL) ->
Path = proplists:get_value(default, Paths),
[Cmd | _] = string:tokens(Path, "%"),
Cmd1 = Cmd ++ " " ++ Args ++ " " ++ URL,
- io:format(user, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
+ io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
open_port({spawn,Cmd1}, []);
_ ->
- io:format("~nNo path to iexplore.exe~n",[])
+ io:format(?def_gl, "~nNo path to iexplore.exe~n",[])
end,
win32reg:close(R),
ok;
@@ -1095,6 +1099,6 @@ open_url(Prog, Args, URL) ->
is_list(Prog) -> Prog
end,
Cmd = ProgStr ++ " " ++ Args ++ " " ++ URL,
- io:format(user, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd]),
+ io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd]),
open_port({spawn,Cmd},[]),
ok.
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index d7efa26863..039c8168ec 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -23,6 +23,7 @@
-define(board_table,ct_boards).
-define(suite_table,ct_suite_data).
-define(verbosity_table,ct_verbosity_table).
+-define(def_gl, ct_default_gl).
-record(conn, {handle,
targetref,
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
index 883da0da0a..ef92532969 100644
--- a/lib/common_test/src/cth_conn_log.erl
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -54,8 +54,8 @@
-include_lib("common_test/include/ct.hrl").
-export([init/2,
- pre_init_per_testcase/3,
- post_end_per_testcase/4]).
+ pre_init_per_testcase/4,
+ post_end_per_testcase/5]).
%%----------------------------------------------------------------------
%% Exported types
@@ -104,7 +104,7 @@ get_log_opts(Mod,Opts) ->
Hosts = proplists:get_value(hosts,Opts,[]),
{LogType,Hosts}.
-pre_init_per_testcase(TestCase,Config,CthState) ->
+pre_init_per_testcase(_Suite,TestCase,Config,CthState) ->
Logs =
lists:map(
fun({ConnMod,{LogType,Hosts}}) ->
@@ -158,7 +158,7 @@ pre_init_per_testcase(TestCase,Config,CthState) ->
ct_util:update_testdata(?MODULE, Update, [create]),
{Config,CthState}.
-post_end_per_testcase(TestCase,_Config,Return,CthState) ->
+post_end_per_testcase(_Suite,TestCase,_Config,Return,CthState) ->
Update =
fun(PrevUsers) ->
case lists:delete(TestCase, PrevUsers) of
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 6d77d7ee9e..1bc9b10d41 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,10 +28,10 @@
%% CTH Callbacks
-export([id/1, init/2,
pre_init_per_suite/3, pre_end_per_suite/3, post_end_per_suite/4,
- pre_init_per_group/3, post_init_per_group/4,
- pre_end_per_group/3, post_end_per_group/4,
- pre_init_per_testcase/3, post_init_per_testcase/4,
- pre_end_per_testcase/3, post_end_per_testcase/4]).
+ pre_init_per_group/4, post_init_per_group/5,
+ pre_end_per_group/4, post_end_per_group/5,
+ pre_init_per_testcase/4, post_init_per_testcase/5,
+ pre_end_per_testcase/4, post_end_per_testcase/5]).
%% Event handler Callbacks
-export([init/1,
@@ -71,11 +71,11 @@ post_end_per_suite(_Suite, Config, Return, State) ->
set_curr_func(undefined, Config),
{Return, State}.
-pre_init_per_group(Group, Config, State) ->
+pre_init_per_group(_Suite, Group, Config, State) ->
set_curr_func({group,Group,init_per_group}, Config),
{Config, State}.
-post_init_per_group(Group, Config, Result, tc_log_async) when is_list(Config) ->
+post_init_per_group(_Suite, Group, Config, Result, tc_log_async) when is_list(Config) ->
case lists:member(parallel,proplists:get_value(
tc_group_properties,Config,[])) of
true ->
@@ -83,33 +83,33 @@ post_init_per_group(Group, Config, Result, tc_log_async) when is_list(Config) ->
false ->
{Result, tc_log_async}
end;
-post_init_per_group(_Group, _Config, Result, State) ->
+post_init_per_group(_Suite, _Group, _Config, Result, State) ->
{Result, State}.
-pre_init_per_testcase(TC, Config, State) ->
+pre_init_per_testcase(_Suite, TC, Config, State) ->
set_curr_func(TC, Config),
{Config, State}.
-post_init_per_testcase(_TC, _Config, Return, State) ->
+post_init_per_testcase(_Suite, _TC, _Config, Return, State) ->
{Return, State}.
-pre_end_per_testcase(_TC, Config, State) ->
+pre_end_per_testcase(_Suite, _TC, Config, State) ->
{Config, State}.
-post_end_per_testcase(_TC, _Config, Result, State) ->
+post_end_per_testcase(_Suite, _TC, _Config, Result, State) ->
%% Make sure that the event queue is flushed
%% before ending this test case.
gen_event:call(error_logger, ?MODULE, flush, 300000),
{Result, State}.
-pre_end_per_group(Group, Config, {tc_log, Group}) ->
+pre_end_per_group(_Suite, Group, Config, {tc_log, Group}) ->
set_curr_func({group,Group,end_per_group}, Config),
{Config, set_log_func(tc_log_async)};
-pre_end_per_group(Group, Config, State) ->
+pre_end_per_group(_Suite, Group, Config, State) ->
set_curr_func({group,Group,end_per_group}, Config),
{Config, State}.
-post_end_per_group(_Group, Config, Return, State) ->
+post_end_per_group(_Suite, _Group, Config, Return, State) ->
set_curr_func({group,undefined}, Config),
{Return, State}.
diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl
index 59b916851e..0bbb217275 100644
--- a/lib/common_test/src/cth_surefire.erl
+++ b/lib/common_test/src/cth_surefire.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,16 +33,16 @@
-export([pre_end_per_suite/3]).
-export([post_end_per_suite/4]).
--export([pre_init_per_group/3]).
--export([post_init_per_group/4]).
--export([pre_end_per_group/3]).
--export([post_end_per_group/4]).
+-export([pre_init_per_group/4]).
+-export([post_init_per_group/5]).
+-export([pre_end_per_group/4]).
+-export([post_end_per_group/5]).
--export([pre_init_per_testcase/3]).
--export([post_end_per_testcase/4]).
+-export([pre_init_per_testcase/4]).
+-export([post_end_per_testcase/5]).
--export([on_tc_fail/3]).
--export([on_tc_skip/3]).
+-export([on_tc_fail/4]).
+-export([on_tc_skip/4]).
-export([terminate/1]).
@@ -116,29 +116,29 @@ pre_end_per_suite(_Suite,Config,State) ->
post_end_per_suite(_Suite,Config,Result,State) ->
{Result, end_tc(end_per_suite,Config,Result,State)}.
-pre_init_per_group(Group,Config,State) ->
+pre_init_per_group(_Suite,Group,Config,State) ->
{Config, init_tc(State#state{ curr_group = [Group|State#state.curr_group]},
Config)}.
-post_init_per_group(_Group,Config,Result,State) ->
+post_init_per_group(_Suite,_Group,Config,Result,State) ->
{Result, end_tc(init_per_group,Config,Result,State)}.
-pre_end_per_group(_Group,Config,State) ->
+pre_end_per_group(_Suite,_Group,Config,State) ->
{Config, init_tc(State, Config)}.
-post_end_per_group(_Group,Config,Result,State) ->
+post_end_per_group(_Suite,_Group,Config,Result,State) ->
NewState = end_tc(end_per_group, Config, Result, State),
{Result, NewState#state{ curr_group = tl(NewState#state.curr_group)}}.
-pre_init_per_testcase(_TC,Config,State) ->
+pre_init_per_testcase(_Suite,_TC,Config,State) ->
{Config, init_tc(State, Config)}.
-post_end_per_testcase(TC,Config,Result,State) ->
+post_end_per_testcase(_Suite,TC,Config,Result,State) ->
{Result, end_tc(TC,Config, Result,State)}.
-on_tc_fail(_TC, _Res, State = #state{test_cases = []}) ->
+on_tc_fail(_Suite,_TC, _Res, State = #state{test_cases = []}) ->
State;
-on_tc_fail(_TC, Res, State) ->
+on_tc_fail(_Suite,_TC, Res, State) ->
TCs = State#state.test_cases,
TC = hd(TCs),
NewTC = TC#testcase{
@@ -146,10 +146,9 @@ on_tc_fail(_TC, Res, State) ->
{fail,lists:flatten(io_lib:format("~p",[Res]))} },
State#state{ test_cases = [NewTC | tl(TCs)]}.
-on_tc_skip({ConfigFunc,_GrName},{Type,_Reason} = Res, State0)
- when Type == tc_auto_skip; Type == tc_user_skip ->
- on_tc_skip(ConfigFunc, Res, State0);
-on_tc_skip(Tc,{Type,_Reason} = Res, State0) when Type == tc_auto_skip ->
+on_tc_skip(Suite,{ConfigFunc,_GrName}, Res, State) ->
+ on_tc_skip(Suite,ConfigFunc, Res, State);
+on_tc_skip(Suite,Tc, Res, State0) ->
TcStr = atom_to_list(Tc),
State =
case State0#state.test_cases of
@@ -158,11 +157,7 @@ on_tc_skip(Tc,{Type,_Reason} = Res, State0) when Type == tc_auto_skip ->
_ ->
State0
end,
- do_tc_skip(Res, end_tc(Tc,[],Res,init_tc(State,[])));
-on_tc_skip(_Tc, _Res, State = #state{test_cases = []}) ->
- State;
-on_tc_skip(_Tc, Res, State) ->
- do_tc_skip(Res, State).
+ do_tc_skip(Res, end_tc(Tc,[],Res,init_tc(set_suite(Suite,State),[]))).
do_tc_skip(Res, State) ->
TCs = State#state.test_cases,
@@ -209,6 +204,12 @@ end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite,
result = passed }|
State#state.test_cases],
tc_log = ""}. % so old tc_log is not set if next is on_tc_skip
+
+set_suite(Suite,#state{curr_suite=undefined}=State) ->
+ State#state{curr_suite=Suite, curr_suite_ts=?now};
+set_suite(_,State) ->
+ State.
+
close_suite(#state{ test_cases = [] } = State) ->
State;
close_suite(#state{ test_cases = TCs, url_base = UrlBase } = State) ->
@@ -228,7 +229,8 @@ close_suite(#state{ test_cases = TCs, url_base = UrlBase } = State) ->
testcases = lists:reverse(TCs),
log = SuiteLog,
url = SuiteUrl},
- State#state{ test_cases = [],
+ State#state{ curr_suite = undefined,
+ test_cases = [],
test_suites = [Suite | State#state.test_suites]}.
terminate(State = #state{ test_cases = [] }) ->
diff --git a/lib/common_test/src/erl2html2.erl b/lib/common_test/src/erl2html2.erl
index e819f345de..7f3eb699de 100644
--- a/lib/common_test/src/erl2html2.erl
+++ b/lib/common_test/src/erl2html2.erl
@@ -130,6 +130,8 @@ parse_preprocessed_file(Epp, File, InCorrectFile) ->
throw({error,Reason,InCorrectFile});
{error,_Reason} ->
parse_preprocessed_file(Epp, File, InCorrectFile);
+ {warning,_} ->
+ parse_preprocessed_file(Epp, File, InCorrectFile);
{eof,_Location} ->
[]
end.
diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl
index 924086f2bd..857ff27258 100644
--- a/lib/common_test/src/test_server.erl
+++ b/lib/common_test/src/test_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -778,9 +778,9 @@ spawn_fw_call(Mod,IPTC={init_per_testcase,Func},CurrConf,Pid,
%% if init_per_testcase fails, the test case
%% should be skipped
try begin do_end_tc_call(Mod,IPTC, {Pid,Skip,[CurrConf]}, Why),
- do_init_tc_call(Mod,{end_per_testcase,Func},
+ do_init_tc_call(Mod,{end_per_testcase_not_run,Func},
[CurrConf],{ok,[CurrConf]}),
- do_end_tc_call(Mod,{end_per_testcase,Func},
+ do_end_tc_call(Mod,{end_per_testcase_not_run,Func},
{Pid,Skip,[CurrConf]}, Why) end of
_ -> ok
catch
@@ -1151,14 +1151,14 @@ do_end_tc_call(Mod, IPTC={init_per_testcase,Func}, Res, Return) ->
Args
end,
EPTCInitRes =
- case do_init_tc_call(Mod,{end_per_testcase,Func},
+ case do_init_tc_call(Mod,{end_per_testcase_not_run,Func},
IPTCEndRes,Return) of
{ok,EPTCInitConfig} when is_list(EPTCInitConfig) ->
{Return,EPTCInitConfig};
_ ->
- Return
+ {Return,IPTCEndRes}
end,
- do_end_tc_call1(Mod, {end_per_testcase,Func},
+ do_end_tc_call1(Mod, {end_per_testcase_not_run,Func},
EPTCInitRes, Return);
_Ok ->
do_end_tc_call1(Mod, IPTC, Res, Return)
diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl
index b52e4bef9b..064e375cd5 100644
--- a/lib/common_test/src/test_server_ctrl.erl
+++ b/lib/common_test/src/test_server_ctrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -2051,17 +2051,21 @@ add_init_and_end_per_suite([], _LastMod, skipped_suite, _FwMod) ->
add_init_and_end_per_suite([], LastMod, LastRef, FwMod) ->
%% we'll add end_per_suite here even if it's not exported
%% (and simply let the call fail if it's missing)
- case erlang:function_exported(LastMod, end_per_suite, 1) of
- true ->
- [{conf,LastRef,[],{LastMod,end_per_suite}}];
- false ->
+ case {erlang:function_exported(LastMod, end_per_suite, 1),
+ erlang:function_exported(LastMod, init_per_suite, 1)} of
+ {false,false} ->
%% let's call a "fake" end_per_suite if it exists
case erlang:function_exported(FwMod, end_per_suite, 1) of
true ->
[{conf,LastRef,[{suite,LastMod}],{FwMod,end_per_suite}}];
false ->
[{conf,LastRef,[],{LastMod,end_per_suite}}]
- end
+ end;
+ _ ->
+ %% If any of these exist, the other should too
+ %% (required and documented). If it isn't, it will fail
+ %% with reason 'undef'.
+ [{conf,LastRef,[],{LastMod,end_per_suite}}]
end.
do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
@@ -2070,11 +2074,9 @@ do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
_ -> ok
end,
{Init,NextMod,NextRef} =
- case erlang:function_exported(Mod, init_per_suite, 1) of
- true ->
- Ref = make_ref(),
- {[{conf,Ref,[],{Mod,init_per_suite}}],Mod,Ref};
- false ->
+ case {erlang:function_exported(Mod, init_per_suite, 1),
+ erlang:function_exported(Mod, end_per_suite, 1)} of
+ {false,false} ->
%% let's call a "fake" init_per_suite if it exists
case erlang:function_exported(FwMod, init_per_suite, 1) of
true ->
@@ -2083,8 +2085,13 @@ do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
{FwMod,init_per_suite}}],Mod,Ref};
false ->
{[],Mod,undefined}
- end
-
+ end;
+ _ ->
+ %% If any of these exist, the other should too
+ %% (required and documented). If it isn't, it will fail
+ %% with reason 'undef'.
+ Ref = make_ref(),
+ {[{conf,Ref,[],{Mod,init_per_suite}}],Mod,Ref}
end,
Cases =
if LastRef==undefined ->
@@ -2094,10 +2101,9 @@ do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
true ->
%% we'll add end_per_suite here even if it's not exported
%% (and simply let the call fail if it's missing)
- case erlang:function_exported(LastMod, end_per_suite, 1) of
- true ->
- [{conf,LastRef,[],{LastMod,end_per_suite}}|Init];
- false ->
+ case {erlang:function_exported(LastMod, end_per_suite, 1),
+ erlang:function_exported(LastMod, init_per_suite, 1)} of
+ {false,false} ->
%% let's call a "fake" end_per_suite if it exists
case erlang:function_exported(FwMod, end_per_suite, 1) of
true ->
@@ -2105,8 +2111,13 @@ do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
{FwMod,end_per_suite}}|Init];
false ->
[{conf,LastRef,[],{LastMod,end_per_suite}}|Init]
- end
- end
+ end;
+ _ ->
+ %% If any of these exist, the other should too
+ %% (required and documented). If it isn't, it will fail
+ %% with reason 'undef'.
+ [{conf,LastRef,[],{LastMod,end_per_suite}}|Init]
+ end
end,
{Cases,NextMod,NextRef}.
@@ -2115,11 +2126,9 @@ do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod) ->
No when No==undefined ; No==skipped_suite ->
{[],Mod,skipped_suite};
_Ref ->
- case erlang:function_exported(LastMod, end_per_suite, 1) of
- true ->
- {[{conf,LastRef,[],{LastMod,end_per_suite}}],
- Mod,skipped_suite};
- false ->
+ case {erlang:function_exported(LastMod, end_per_suite, 1),
+ erlang:function_exported(LastMod, init_per_suite, 1)} of
+ {false,false} ->
case erlang:function_exported(FwMod, end_per_suite, 1) of
true ->
%% let's call "fake" end_per_suite if it exists
@@ -2128,7 +2137,13 @@ do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod) ->
false ->
{[{conf,LastRef,[],{LastMod,end_per_suite}}],
Mod,skipped_suite}
- end
+ end;
+ _ ->
+ %% If any of these exist, the other should too
+ %% (required and documented). If it isn't, it will fail
+ %% with reason 'undef'.
+ {[{conf,LastRef,[],{LastMod,end_per_suite}}],
+ Mod,skipped_suite}
end
end.
@@ -2924,22 +2939,21 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
exit(framework_error);
%% sequential execution of test case finished
{Time,RetVal,_} ->
+ RetTag =
+ if is_tuple(RetVal) -> element(1,RetVal);
+ true -> undefined
+ end,
{Failed,Status1} =
- case Time of
- died ->
- {true,update_status(failed, Mod, Func, Status)};
- _ when is_tuple(RetVal) ->
- case element(1, RetVal) of
- R when R=='EXIT'; R==failed ->
- {true,update_status(failed, Mod, Func, Status)};
- R when R==skip; R==skipped ->
- {false,update_status(skipped, Mod, Func, Status)};
- _ ->
- {false,update_status(ok, Mod, Func, Status)}
- end;
- _ ->
- {false,update_status(ok, Mod, Func, Status)}
- end,
+ case RetTag of
+ Skip when Skip==skip; Skip==skipped ->
+ {false,update_status(skipped, Mod, Func, Status)};
+ Fail when Fail=='EXIT'; Fail==failed ->
+ {true,update_status(failed, Mod, Func, Status)};
+ _ when Time==died, RetVal=/=ok ->
+ {true,update_status(failed, Mod, Func, Status)};
+ _ ->
+ {false,update_status(ok, Mod, Func, Status)}
+ end,
case check_prop(sequence, Mode) of
false ->
stop_minor_log_file(),
@@ -3794,7 +3808,15 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
{died,{timetrap_timeout,TimetrapTimeout}} ->
progress(failed, Num, Mod, Func, GrName, Loc,
timetrap_timeout, TimetrapTimeout, Comment, Style);
- {died,Reason} ->
+ {died,{Skip,Reason}} when Skip==skip; Skip==skipped ->
+ %% died in init_per_testcase
+ progress(skip, Num, Mod, Func, GrName, Loc, Reason,
+ Time, Comment, Style);
+ {died,Reason} when Reason=/=ok ->
+ %% (If Reason==ok it means that process died in
+ %% end_per_testcase after successfully completing the
+ %% test case itself - then we shall not fail, but a
+ %% warning will be issued in the comment field.)
progress(failed, Num, Mod, Func, GrName, Loc, Reason,
Time, Comment, Style);
{_,{'EXIT',{Skip,Reason}}} when Skip==skip; Skip==skipped;
@@ -3943,6 +3965,9 @@ progress(skip, CaseNum, Mod, Func, GrName, Loc, Reason, Time,
[get_info_str(Mod,Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName},
{ReportTag,Reason1}}]),
+ TimeStr = io_lib:format(if is_float(Time) -> "~.3fs";
+ true -> "~w"
+ end, [Time]),
ReasonStr = escape_chars(reason_to_string(Reason1)),
ReasonStr1 = lists:flatten([string:strip(S,left) ||
S <- string:tokens(ReasonStr,[$\n])]),
@@ -3957,10 +3982,10 @@ progress(skip, CaseNum, Mod, Func, GrName, Loc, Reason, Time,
_ -> xhtml("<br>(","<br />(") ++ to_string(Comment) ++ ")"
end,
print(html,
- "<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
+ "<td>" ++ St0 ++ "~ts" ++ St1 ++ "</td>"
"<td><font color=\"~ts\">SKIPPED</font></td>"
"<td>~ts~ts</td></tr>\n",
- [Time,Color,ReasonStr2,Comment1]),
+ [TimeStr,Color,ReasonStr2,Comment1]),
FormatLoc = test_server_sup:format_loc(Loc),
print(minor, "=== Location: ~ts", [FormatLoc]),
print(minor, "=== Reason: ~ts", [ReasonStr1]),
@@ -4098,6 +4123,9 @@ progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time,
Comment0, {St0,St1}) ->
print(minor, "successfully completed test case", []),
test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName},ok}]),
+ TimeStr = io_lib:format(if is_float(Time) -> "~.3fs";
+ true -> "~w"
+ end, [Time]),
Comment =
case RetVal of
{comment,RetComment} ->
@@ -4116,10 +4144,10 @@ progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time,
end,
print(major, "=elapsed ~p", [Time]),
print(html,
- "<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
+ "<td>" ++ St0 ++ "~ts" ++ St1 ++ "</td>"
"<td><font color=\"green\">Ok</font></td>"
"~ts</tr>\n",
- [Time,Comment]),
+ [TimeStr,Comment]),
print(minor,
escape_chars(io_lib:format("=== Returned value: ~tp", [RetVal])),
[]),
diff --git a/lib/common_test/src/test_server_gl.erl b/lib/common_test/src/test_server_gl.erl
index 7d6fe64b92..4845b86dd3 100644
--- a/lib/common_test/src/test_server_gl.erl
+++ b/lib/common_test/src/test_server_gl.erl
@@ -24,7 +24,7 @@
%% through the test_server_io module/process.
-module(test_server_gl).
--export([start_link/0,stop/1,set_minor_fd/3,unset_minor_fd/1,
+-export([start_link/1,stop/1,set_minor_fd/3,unset_minor_fd/1,
get_tc_supervisor/1,print/4,set_props/2]).
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]).
@@ -33,6 +33,7 @@
tc :: mfa() | 'undefined', %Current test case MFA
minor :: 'none'|pid(), %Minor fd
minor_monitor, %Monitor ref for minor fd
+ tsio_monitor, %Monitor red for controlling proc
capture :: 'none'|pid(), %Capture output
reject_io :: boolean(), %Reject I/O requests...
permit_io, %... and exceptions
@@ -45,8 +46,8 @@
%% Start a new group leader process. Only to be called by
%% the test_server_io process.
-start_link() ->
- case gen_server:start_link(?MODULE, [], []) of
+start_link(TSIO) ->
+ case gen_server:start_link(?MODULE, [TSIO], []) of
{ok,Pid} ->
{ok,Pid};
Other ->
@@ -130,14 +131,16 @@ set_props(GL, PropList) ->
%%% Internal functions.
-init([]) ->
+init([TSIO]) ->
EscChars = case application:get_env(test_server, esc_chars) of
{ok,ECBool} -> ECBool;
_ -> true
end,
+ Ref = erlang:monitor(process, TSIO),
{ok,#st{tc_supervisor=none,
minor=none,
minor_monitor=none,
+ tsio_monitor=Ref,
capture=none,
reject_io=false,
permit_io=gb_sets:empty(),
@@ -176,6 +179,9 @@ handle_info({'DOWN',Ref,process,_,Reason}=D, #st{minor_monitor=Ref}=St) ->
test_server_io:print_unexpected(Data)
end,
{noreply,St#st{minor=none,minor_monitor=none}};
+handle_info({'DOWN',Ref,process,_,_}, #st{tsio_monitor=Ref}=St) ->
+ %% controlling process (test_server_io) terminated, we're done
+ {stop,normal,St};
handle_info({permit_io,Pid}, #st{permit_io=P}=St) ->
{noreply,St#st{permit_io=gb_sets:add(Pid, P)}};
handle_info({capture,Cap0}, St) ->
diff --git a/lib/common_test/src/test_server_io.erl b/lib/common_test/src/test_server_io.erl
index 3d5238052b..fdabf17b08 100644
--- a/lib/common_test/src/test_server_io.erl
+++ b/lib/common_test/src/test_server_io.erl
@@ -185,7 +185,7 @@ reset_state() ->
init([]) ->
process_flag(trap_exit, true),
Empty = gb_trees:empty(),
- {ok,Shared} = test_server_gl:start_link(),
+ {ok,Shared} = test_server_gl:start_link(self()),
{ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
io_buffering=gb_sets:empty(),
buffered=Empty,
@@ -200,7 +200,7 @@ req(Req) ->
gen_server:call(?MODULE, Req, infinity).
handle_call({get_gl,false}, _From, #st{gls=Gls,gl_props=Props}=St) ->
- {ok,Pid} = test_server_gl:start_link(),
+ {ok,Pid} = test_server_gl:start_link(self()),
test_server_gl:set_props(Pid, Props),
{reply,Pid,St#st{gls=gb_sets:insert(Pid, Gls)}};
handle_call({get_gl,true}, _From, #st{shared_gl=Shared}=St) ->
@@ -285,7 +285,7 @@ handle_call(reset_state, _From, #st{fds=Fds,tags=Tags,gls=Gls,
ok
end,
Empty = gb_trees:empty(),
- {ok,Shared} = test_server_gl:start_link(),
+ {ok,Shared} = test_server_gl:start_link(self()),
{reply,ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
io_buffering=gb_sets:empty(),
buffered=Empty,
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index b1eddfedd7..2f0fc2e05a 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -70,7 +70,8 @@ MODULES= \
test_server_SUITE \
test_server_test_lib \
ct_release_test_SUITE \
- ct_log_SUITE
+ ct_log_SUITE \
+ ct_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
diff --git a/lib/common_test/test/ct_SUITE.erl b/lib/common_test/test/ct_SUITE.erl
new file mode 100644
index 0000000000..eb98c2544f
--- /dev/null
+++ b/lib/common_test/test/ct_SUITE.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ct_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [app_file, appup_file].
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+
+app_file(_Config) ->
+ ok = test_server:app_test(common_test),
+ ok.
+
+appup_file(_Config) ->
+ ok = test_server:appup_test(common_test).
+
diff --git a/lib/common_test/test/ct_auto_compile_SUITE.erl b/lib/common_test/test/ct_auto_compile_SUITE.erl
index e6939d23c0..dface99b8f 100644
--- a/lib/common_test/test/ct_auto_compile_SUITE.erl
+++ b/lib/common_test/test/ct_auto_compile_SUITE.erl
@@ -27,6 +27,7 @@
%%% The suites used for the test are located in the data directory.
%%%-------------------------------------------------------------------
-module(ct_auto_compile_SUITE).
+-warning("Ignore me -- testing that the debugger can handle warnings").
-compile(export_all).
diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl
index 9879e0f20d..cbbfe408a8 100644
--- a/lib/common_test/test/ct_config_SUITE.erl
+++ b/lib/common_test/test/ct_config_SUITE.erl
@@ -113,10 +113,14 @@ userconfig_static(Config) when is_list(Config) ->
["config_static_SUITE"]).
userconfig_dynamic(Config) when is_list(Config) ->
- run_test(config_dynamic_SUITE,
- Config,
- {userconfig, {config_driver, "config_server"}},
- ["config_dynamic_SUITE"]).
+ case skip_dynamic() of
+ true -> {skip,"TimeWarpingOS"};
+ false ->
+ run_test(config_dynamic_SUITE,
+ Config,
+ {userconfig, {config_driver, "config_server"}},
+ ["config_dynamic_SUITE"])
+ end.
testspec_legacy(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
@@ -147,16 +151,20 @@ testspec_static(Config) when is_list(Config) ->
file:delete(filename:join(ConfigDir, "spec_static.spec")).
testspec_dynamic(Config) when is_list(Config) ->
- DataDir = ?config(data_dir, Config),
- ConfigDir = ?config(config_dir, Config),
- make_spec(DataDir, ConfigDir, "spec_dynamic.spec",
- [config_dynamic_SUITE],
- [{userconfig, {config_driver, "config_server"}}]),
- run_test(config_dynamic_SUITE,
- Config,
- {spec, filename:join(ConfigDir, "spec_dynamic.spec")},
- []),
- file:delete(filename:join(ConfigDir, "spec_dynamic.spec")).
+ case skip_dynamic() of
+ true -> {skip,"TimeWarpingOS"};
+ false ->
+ DataDir = ?config(data_dir, Config),
+ ConfigDir = ?config(config_dir, Config),
+ make_spec(DataDir, ConfigDir, "spec_dynamic.spec",
+ [config_dynamic_SUITE],
+ [{userconfig, {config_driver, "config_server"}}]),
+ run_test(config_dynamic_SUITE,
+ Config,
+ {spec, filename:join(ConfigDir, "spec_dynamic.spec")},
+ []),
+ file:delete(filename:join(ConfigDir, "spec_dynamic.spec"))
+ end.
@@ -198,6 +206,23 @@ setup_env(Test, Config, CTConfig) ->
reformat_events(Events, EH) ->
ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% Test related to 'localtime' will often fail if the test host is
+%%% time warping, so let's just skip the 'dynamic' tests then.
+skip_dynamic() ->
+ case os:getenv("TS_EXTRA_PLATFORM_LABEL") of
+ TSExtraPlatformLabel when is_list(TSExtraPlatformLabel) ->
+ case string:str(TSExtraPlatformLabel,"TimeWarpingOS") of
+ 0 -> false;
+ _ -> true
+ end;
+ _ ->
+ false
+ end.
+
+
+
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl
index fae23484e6..7468ebe9d9 100644
--- a/lib/common_test/test/ct_error_SUITE.erl
+++ b/lib/common_test/test/ct_error_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1531,17 +1531,17 @@ test_events(config_func_errors) ->
{?eh,tc_start,{config_func_error_1_SUITE,exit_in_iptc}},
{?eh,tc_done,{config_func_error_1_SUITE,exit_in_iptc,'_'}},
- {?eh,test_stats,{0,1,{0,0}}},
+ {?eh,test_stats,{0,0,{0,1}}},
{?eh,tc_start,{config_func_error_1_SUITE,exit_in_eptc}},
{?eh,tc_done,{config_func_error_1_SUITE,exit_in_eptc,'_'}},
- {?eh,test_stats,{0,2,{0,0}}},
+ {?eh,test_stats,{1,0,{0,1}}},
[{?eh,tc_start,{config_func_error_1_SUITE,{init_per_group,g1,[]}}},
{?eh,tc_done,{config_func_error_1_SUITE,{init_per_group,g1,[]},ok}},
{?eh,tc_start,{config_func_error_1_SUITE,exit_in_iptc}},
{?eh,tc_done,{config_func_error_1_SUITE,exit_in_iptc,'_'}},
- {?eh,test_stats,{0,3,{0,0}}},
+ {?eh,test_stats,{1,0,{0,2}}},
{?eh,tc_start,{config_func_error_1_SUITE,{end_per_group,g1,[]}}},
{?eh,tc_done,{config_func_error_1_SUITE,{end_per_group,g1,[]},ok}}],
@@ -1549,7 +1549,7 @@ test_events(config_func_errors) ->
{?eh,tc_done,{config_func_error_1_SUITE,{init_per_group,g2,[]},ok}},
{?eh,tc_start,{config_func_error_1_SUITE,exit_in_eptc}},
{?eh,tc_done,{config_func_error_1_SUITE,exit_in_eptc,'_'}},
- {?eh,test_stats,{0,4,{0,0}}},
+ {?eh,test_stats,{2,0,{0,2}}},
{?eh,tc_start,{config_func_error_1_SUITE,{end_per_group,g2,[]}}},
{?eh,tc_done,{config_func_error_1_SUITE,{end_per_group,g2,[]},ok}}],
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 690d0af1bb..8ba14e63bc 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,22 +70,25 @@ suite() ->
all() ->
all(suite).
-all(suite) ->
+all(suite) ->
lists:reverse(
[
one_cth, two_cth, faulty_cth_no_init, faulty_cth_id_no_init,
faulty_cth_exit_in_init, faulty_cth_exit_in_id,
- faulty_cth_exit_in_init_scope_suite, minimal_cth,
- minimal_and_maximal_cth, faulty_cth_undef,
+ faulty_cth_exit_in_init_scope_suite, minimal_cth,
+ minimal_and_maximal_cth, faulty_cth_undef,
scope_per_suite_cth, scope_per_group_cth, scope_suite_cth,
- scope_per_suite_state_cth, scope_per_group_state_cth,
+ scope_per_suite_state_cth, scope_per_group_state_cth,
scope_suite_state_cth,
fail_pre_suite_cth, double_fail_pre_suite_cth,
fail_post_suite_cth, skip_pre_suite_cth, skip_pre_end_cth,
+ skip_pre_init_tc_cth,
skip_post_suite_cth, recover_post_suite_cth, update_config_cth,
- state_update_cth, options_cth, same_id_cth,
+ state_update_cth, options_cth, same_id_cth,
fail_n_skip_with_minimal_cth, prio_cth, no_config,
- data_dir, cth_log
+ no_init_suite_config, no_init_config, no_end_config,
+ failed_sequence, repeat_force_stop, config_clash,
+ callbacks_on_skip, fallback, data_dir, cth_log
]
).
@@ -96,10 +99,10 @@ all(suite) ->
%%%-----------------------------------------------------------------
%%%
-one_cth(Config) when is_list(Config) ->
+one_cth(Config) when is_list(Config) ->
do_test(one_empty_cth, "ct_cth_empty_SUITE.erl",[empty_cth], Config).
-two_cth(Config) when is_list(Config) ->
+two_cth(Config) when is_list(Config) ->
do_test(two_empty_cth, "ct_cth_empty_SUITE.erl",[empty_cth,empty_cth],
Config).
@@ -119,13 +122,13 @@ minimal_cth(Config) when is_list(Config) ->
minimal_and_maximal_cth(Config) when is_list(Config) ->
do_test(minimal_and_maximal_cth, "ct_cth_empty_SUITE.erl",
[minimal_cth, empty_cth],Config).
-
+
faulty_cth_undef(Config) when is_list(Config) ->
do_test(faulty_cth_undef, "ct_cth_empty_SUITE.erl",
[undef_cth],Config).
faulty_cth_exit_in_init_scope_suite(Config) when is_list(Config) ->
- do_test(faulty_cth_exit_in_init_scope_suite,
+ do_test(faulty_cth_exit_in_init_scope_suite,
"ct_exit_in_init_scope_suite_cth_SUITE.erl",
[],Config).
@@ -190,6 +193,10 @@ skip_post_suite_cth(Config) when is_list(Config) ->
do_test(skip_post_suite_cth, "ct_cth_empty_SUITE.erl",
[skip_post_suite_cth],Config).
+skip_pre_init_tc_cth(Config) ->
+ do_test(skip_pre_init_tc_cth, "ct_cth_empty_SUITE.erl",
+ [skip_pre_init_tc_cth],Config).
+
recover_post_suite_cth(Config) when is_list(Config) ->
do_test(recover_post_suite_cth, "ct_cth_fail_per_suite_SUITE.erl",
[recover_post_suite_cth],Config).
@@ -205,7 +212,7 @@ state_update_cth(Config) when is_list(Config) ->
options_cth(Config) when is_list(Config) ->
do_test(options_cth, "ct_cth_empty_SUITE.erl",
[{empty_cth,[test]}],Config).
-
+
same_id_cth(Config) when is_list(Config) ->
do_test(same_id_cth, "ct_cth_empty_SUITE.erl",
[same_id_cth,same_id_cth],Config).
@@ -223,13 +230,24 @@ no_config(Config) when is_list(Config) ->
do_test(no_config, "ct_no_config_SUITE.erl",
[verify_config_cth],Config).
+no_init_suite_config(Config) when is_list(Config) ->
+ do_test(no_init_suite_config, "ct_no_init_suite_config_SUITE.erl",
+ [empty_cth],Config).
+
+no_init_config(Config) when is_list(Config) ->
+ do_test(no_init_config, "ct_no_init_config_SUITE.erl",[empty_cth],Config).
+
+no_end_config(Config) when is_list(Config) ->
+ do_test(no_end_config, "ct_no_end_config_SUITE.erl",[empty_cth],Config).
+
data_dir(Config) when is_list(Config) ->
do_test(data_dir, "ct_data_dir_SUITE.erl",
[verify_data_dir_cth],Config).
-cth_log(Config) when is_list(Config) ->
+cth_log(Config) when is_list(Config) ->
%% test that cth_log_redirect writes properly to
%% unexpected I/O log
+ ct:timetrap({minutes,10}),
StartOpts = do_test(cth_log, "cth_log_SUITE.erl", [], Config),
Logdir = proplists:get_value(logdir, StartOpts),
UnexpIoLogs =
@@ -253,29 +271,57 @@ cth_log(Config) when is_list(Config) ->
end, UnexpIoLogs),
ok.
+%% OTP-10599 adds the Suite argument as first argument to all hook
+%% callbacks that did not have a Suite argument from before. This test
+%% checks that ct_hooks will fall back to old versions of callbacks if
+%% new versions are not exported.
+fallback(Config) ->
+ do_test(fallback, "all_hook_callbacks_SUITE.erl",[fallback_cth], Config).
+
+%% Test that expected callbacks, and only those, are called when tests
+%% are skipped in different ways
+callbacks_on_skip(Config) ->
+ do_test(callbacks_on_skip, {spec,"skip.spec"},[skip_cth], Config).
+
+%% Test that expected callbacks, and only those, are called when tests
+%% are skipped due to failed sequence
+failed_sequence(Config) ->
+ do_test(failed_sequence, "seq_SUITE.erl", [skip_cth], Config).
+
+%% Test that expected callbacks, and only those, are called when tests
+%% are skipped due to {force_stop,skip_rest} option
+repeat_force_stop(Config) ->
+ do_test(repeat_force_stop, "repeat_SUITE.erl", [skip_cth], Config, ok, 2,
+ [{force_stop,skip_rest},{duration,"000009"}]).
+
+%% Test that expected callbacks, and only those, are called when a test
+%% are fails due to clash in config alias names
+config_clash(Config) ->
+ do_test(config_clash, "config_clash_SUITE.erl", [skip_cth], Config).
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
-do_test(Tag, SWC, CTHs, Config) ->
- do_test(Tag, SWC, CTHs, Config, ok).
-do_test(Tag, SWC, CTHs, Config, {error,_} = Res) ->
- do_test(Tag, SWC, CTHs, Config, Res, 1);
-do_test(Tag, SWC, CTHs, Config, Res) ->
- do_test(Tag, SWC, CTHs, Config, Res, 2).
+do_test(Tag, WTT, CTHs, Config) ->
+ do_test(Tag, WTT, CTHs, Config, ok).
+do_test(Tag, WTT, CTHs, Config, {error,_} = Res) ->
+ do_test(Tag, WTT, CTHs, Config, Res, 1,[]);
+do_test(Tag, WTT, CTHs, Config, Res) ->
+ do_test(Tag, WTT, CTHs, Config, Res, 2,[]).
-do_test(Tag, SuiteWildCard, CTHs, Config, Res, EC) ->
-
+do_test(Tag, WhatToTest, CTHs, Config, Res, EC, ExtraOpts) when is_list(WhatToTest) ->
+ do_test(Tag, {suite,WhatToTest}, CTHs, Config, Res, EC, ExtraOpts);
+do_test(Tag, {WhatTag,Wildcard}, CTHs, Config, Res, EC, ExtraOpts) ->
DataDir = ?config(data_dir, Config),
- Suites = filelib:wildcard(
- filename:join([DataDir,"cth/tests",SuiteWildCard])),
- {Opts,ERPid} = setup([{suite,Suites},
- {ct_hooks,CTHs},{label,Tag}], Config),
+ Files = filelib:wildcard(
+ filename:join([DataDir,"cth/tests",Wildcard])),
+ {Opts,ERPid} =
+ setup([{WhatTag,Files},{ct_hooks,CTHs},{label,Tag}|ExtraOpts], Config),
Res = ct_test_support:run(Opts, Config),
Events = ct_test_support:get_events(ERPid, Config),
- ct_test_support:log_events(Tag,
+ ct_test_support:log_events(Tag,
reformat(Events, ?eh),
?config(priv_dir, Config),
Opts),
@@ -323,12 +369,12 @@ test_events(one_empty_cth) ->
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
- {?eh,cth,{empty_cth,pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{empty_cth,post_init_per_testcase,[test_case,'$proplist','_',[]]}},
- {?eh,cth,{empty_cth,pre_end_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{empty_cth,post_end_per_testcase,[test_case,'$proplist','_',[]]}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist','_',[]]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist','_',[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
{?eh,cth,{empty_cth,pre_end_per_suite,
[ct_cth_empty_SUITE,'$proplist',[]]}},
@@ -355,12 +401,12 @@ test_events(two_empty_cth) ->
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{?eh,cth,{'_',pre_end_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
@@ -402,7 +448,7 @@ test_events(minimal_cth) ->
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
{?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
{?eh,tc_done,{ct_cth_empty_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
@@ -423,10 +469,10 @@ test_events(minimal_and_maximal_cth) ->
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{?eh,cth,{'_',post_end_per_suite,[ct_cth_empty_SUITE,'$proplist','_',[]]}},
@@ -452,11 +498,11 @@ test_events(faulty_cth_undef) ->
{?eh,tc_auto_skip,{ct_cth_empty_SUITE,test_case,
{failed, FailReason}}},
{?eh,cth,{'_',on_tc_skip,'_'}},
-
+
{?eh,tc_auto_skip,{ct_cth_empty_SUITE,end_per_suite,
{failed, FailReason}}},
{?eh,cth,{'_',on_tc_skip,'_'}},
-
+
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]}
];
@@ -512,10 +558,10 @@ test_events(scope_per_suite_cth) ->
{?eh,tc_done,{ct_scope_per_suite_cth_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_scope_per_suite_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_per_suite_cth_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_per_suite_cth_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_scope_per_suite_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_per_suite_cth_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,
[ct_scope_per_suite_cth_SUITE,'$proplist',[]]}},
@@ -538,10 +584,10 @@ test_events(scope_suite_cth) ->
{?eh,tc_done,{ct_scope_suite_cth_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_scope_suite_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_suite_cth_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_suite_cth_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_scope_suite_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_suite_cth_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,[ct_scope_suite_cth_SUITE,'$proplist',[]]}},
{?eh,cth,{'_',post_end_per_suite,[ct_scope_suite_cth_SUITE,'$proplist','_',[]]}},
@@ -561,20 +607,20 @@ test_events(scope_per_group_cth) ->
[{?eh,tc_start,{ct_scope_per_group_cth_SUITE,{init_per_group,group1,[]}}},
{?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
- {?eh,cth,{'_',post_init_per_group,[group1,'$proplist','$proplist',[]]}},
+ {?eh,cth,{'_',post_init_per_group,[ct_scope_per_group_cth_SUITE,group1, '$proplist','$proplist',[]]}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,{init_per_group,group1,[]},ok}},
-
+
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_per_group_cth_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_per_group_cth_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,{end_per_group,group1,[]}}},
- {?eh,cth,{'_',pre_end_per_group,[group1,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_group,[group1,'$proplist','_',[]]}},
+ {?eh,cth,{'_',pre_end_per_group,[ct_scope_per_group_cth_SUITE,group1,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_group,[ct_scope_per_group_cth_SUITE,group1,'$proplist','_',[]]}},
{?eh,cth,{'_',terminate,[[]]}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,{end_per_group,group1,[]},ok}}],
-
+
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,end_per_suite}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
@@ -592,10 +638,10 @@ test_events(scope_per_suite_state_cth) ->
{?eh,tc_done,{ct_scope_per_suite_state_cth_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_scope_per_suite_state_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[test]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[test]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_per_suite_state_cth_SUITE,test_case,'$proplist',[test]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_per_suite_state_cth_SUITE,test_case,'$proplist',ok,[test]]}},
{?eh,tc_done,{ct_scope_per_suite_state_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_per_suite_state_cth_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,
[ct_scope_per_suite_state_cth_SUITE,'$proplist',[test]]}},
@@ -618,10 +664,10 @@ test_events(scope_suite_state_cth) ->
{?eh,tc_done,{ct_scope_suite_state_cth_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_scope_suite_state_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[test]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[test]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_suite_state_cth_SUITE,test_case,'$proplist',[test]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_suite_state_cth_SUITE,test_case,'$proplist',ok,[test]]}},
{?eh,tc_done,{ct_scope_suite_state_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_suite_state_cth_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,[ct_scope_suite_state_cth_SUITE,'$proplist',[test]]}},
{?eh,cth,{'_',post_end_per_suite,[ct_scope_suite_state_cth_SUITE,'$proplist','_',[test]]}},
@@ -641,20 +687,20 @@ test_events(scope_per_group_state_cth) ->
[{?eh,tc_start,{ct_scope_per_group_state_cth_SUITE,{init_per_group,group1,[]}}},
{?eh,cth,{'_',id,[[test]]}},
{?eh,cth,{'_',init,['_',[test]]}},
- {?eh,cth,{'_',post_init_per_group,[group1,'$proplist','$proplist',[test]]}},
+ {?eh,cth,{'_',post_init_per_group,[ct_scope_per_group_state_cth_SUITE,group1,'$proplist','$proplist',[test]]}},
{?eh,tc_done,{ct_scope_per_group_state_cth_SUITE,{init_per_group,group1,[]},ok}},
-
+
{?eh,tc_start,{ct_scope_per_group_state_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[test]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[test]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_per_group_state_cth_SUITE,test_case,'$proplist',[test]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_per_group_state_cth_SUITE,test_case,'$proplist',ok,[test]]}},
{?eh,tc_done,{ct_scope_per_group_state_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_per_group_state_cth_SUITE,{end_per_group,group1,[]}}},
- {?eh,cth,{'_',pre_end_per_group,[group1,'$proplist',[test]]}},
- {?eh,cth,{'_',post_end_per_group,[group1,'$proplist','_',[test]]}},
+ {?eh,cth,{'_',pre_end_per_group,[ct_scope_per_group_state_cth_SUITE,group1,'$proplist',[test]]}},
+ {?eh,cth,{'_',post_end_per_group,[ct_scope_per_group_state_cth_SUITE,group1,'$proplist','_',[test]]}},
{?eh,cth,{'_',terminate,[[test]]}},
{?eh,tc_done,{ct_scope_per_group_state_cth_SUITE,{end_per_group,group1,[]},ok}}],
-
+
{?eh,tc_start,{ct_scope_per_group_state_cth_SUITE,end_per_suite}},
{?eh,tc_done,{ct_scope_per_group_state_cth_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
@@ -666,7 +712,7 @@ test_events(fail_pre_suite_cth) ->
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,cth,{'_',init,['_',[]]}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
{?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist',
@@ -674,27 +720,27 @@ test_events(fail_pre_suite_cth) ->
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,
{failed, {error,"Test failure"}}}},
{?eh,cth,{'_',on_tc_fail,
- [init_per_suite,{failed,"Test failure"},[]]}},
+ [ct_cth_empty_SUITE,init_per_suite,"Test failure",[]]}},
+
-
{?eh,tc_auto_skip,{ct_cth_empty_SUITE,test_case,
{failed,{ct_cth_empty_SUITE,init_per_suite,
{failed,"Test failure"}}}}},
{?eh,cth,{'_',on_tc_skip,
- [test_case, {tc_auto_skip,
+ [ct_cth_empty_SUITE,test_case, {tc_auto_skip,
{failed, {ct_cth_empty_SUITE, init_per_suite,
{failed, "Test failure"}}}},[]]}},
-
+
{?eh,tc_auto_skip, {ct_cth_empty_SUITE, end_per_suite,
{failed, {ct_cth_empty_SUITE, init_per_suite,
{failed, "Test failure"}}}}},
{?eh,cth,{'_',on_tc_skip,
- [end_per_suite, {tc_auto_skip,
+ [ct_cth_empty_SUITE,end_per_suite, {tc_auto_skip,
{failed, {ct_cth_empty_SUITE, init_per_suite,
{failed, "Test failure"}}}},[]]}},
-
+
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,cth, {'_',terminate,[[]]}},
{?eh,stop_logging,[]}
@@ -727,17 +773,17 @@ test_events(fail_post_suite_cth) ->
{?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,
{failed,{error,"Test failure"}}}},
- {?eh,cth,{'_',on_tc_fail,[init_per_suite, {failed,"Test failure"}, []]}},
+ {?eh,cth,{'_',on_tc_fail,[ct_cth_empty_SUITE,init_per_suite, "Test failure", []]}},
{?eh,tc_auto_skip,{ct_cth_empty_SUITE,test_case,
{failed,{ct_cth_empty_SUITE,init_per_suite,
{failed,"Test failure"}}}}},
- {?eh,cth,{'_',on_tc_skip,[test_case,{tc_auto_skip,'_'},[]]}},
-
+ {?eh,cth,{'_',on_tc_skip,[ct_cth_empty_SUITE,test_case,{tc_auto_skip,'_'},[]]}},
+
{?eh,tc_auto_skip, {ct_cth_empty_SUITE, end_per_suite,
{failed, {ct_cth_empty_SUITE, init_per_suite,
{failed, "Test failure"}}}}},
- {?eh,cth,{'_',on_tc_skip,[end_per_suite,{tc_auto_skip,'_'},[]]}},
+ {?eh,cth,{'_',on_tc_skip,[ct_cth_empty_SUITE,end_per_suite,{tc_auto_skip,'_'},[]]}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,cth, {'_',terminate,[[]]}},
@@ -754,11 +800,11 @@ test_events(skip_pre_suite_cth) ->
{?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist',{skip,"Test skip"},[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,{skipped,"Test skip"}}},
{?eh,cth,{'_',on_tc_skip,
- [init_per_suite,{tc_user_skip,{skipped,"Test skip"}},[]]}},
+ [ct_cth_empty_SUITE,init_per_suite,{tc_user_skip,"Test skip"},[]]}},
{?eh,tc_user_skip,{ct_cth_empty_SUITE,test_case,"Test skip"}},
- {?eh,cth,{'_',on_tc_skip,[test_case,{tc_user_skip,"Test skip"},[]]}},
-
+ {?eh,cth,{'_',on_tc_skip,[ct_cth_empty_SUITE,test_case,{tc_user_skip,"Test skip"},[]]}},
+
{?eh,tc_user_skip, {ct_cth_empty_SUITE, end_per_suite,"Test skip"}},
{?eh,test_done,{'DEF','STOP_TIME'}},
@@ -772,31 +818,33 @@ test_events(skip_pre_end_cth) ->
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,init_per_suite}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,init_per_suite,ok}},
-
+
[{?eh,tc_start,{ct_scope_per_group_cth_SUITE,{init_per_group,group1,[]}}},
{?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
- {?eh,cth,{'_',post_init_per_group,[group1,'$proplist','$proplist',[]]}},
+ {?eh,cth,{'_',post_init_per_group,[ct_scope_per_group_cth_SUITE,group1,'$proplist','$proplist',[]]}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,{init_per_group,group1,[]},ok}},
-
+
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_scope_per_group_cth_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_scope_per_group_cth_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,{end_per_group,group1,[]}}},
- {?eh,cth,{'_',pre_end_per_group,[group1,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_group,[group1,'$proplist','_',[]]}},
+ {?eh,cth,{'_',pre_end_per_group,[ct_scope_per_group_cth_SUITE,group1,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_group,[ct_scope_per_group_cth_SUITE,group1,'$proplist','_',[]]}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,{end_per_group,group1,[]},
{skipped,"Test skip"}}}],
- {?eh,cth,{'_',on_tc_skip,[{end_per_group,group1},
- {tc_user_skip,{skipped,"Test skip"}},
+ {?eh,cth,{'_',on_tc_skip,[ct_scope_per_group_cth_SUITE,
+ {end_per_group,group1},
+ {tc_user_skip,"Test skip"},
[]]}},
{?eh,tc_start,{ct_scope_per_group_cth_SUITE,end_per_suite}},
{?eh,tc_done,{ct_scope_per_group_cth_SUITE,end_per_suite,
{skipped,"Test skip"}}},
- {?eh,cth,{'_',on_tc_skip,[end_per_suite,
- {tc_user_skip,{skipped,"Test skip"}},
+ {?eh,cth,{'_',on_tc_skip,[ct_scope_per_group_cth_SUITE,
+ end_per_suite,
+ {tc_user_skip,"Test skip"},
[]]}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,cth,{'_',terminate,[[]]}},
@@ -808,24 +856,59 @@ test_events(skip_post_suite_cth) ->
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,cth,{'_',init,['_',[]]}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
{?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,{skipped,"Test skip"}}},
{?eh,cth,{'_',on_tc_skip,
- [init_per_suite,{tc_user_skip,{skipped,"Test skip"}},[]]}},
+ [ct_cth_empty_SUITE,init_per_suite,{tc_user_skip,"Test skip"},[]]}},
{?eh,tc_user_skip,{ct_cth_empty_SUITE,test_case,"Test skip"}},
- {?eh,cth,{'_',on_tc_skip,[test_case,{tc_user_skip,"Test skip"},[]]}},
-
+ {?eh,cth,{'_',on_tc_skip,[ct_cth_empty_SUITE,test_case,{tc_user_skip,"Test skip"},[]]}},
+
{?eh,tc_user_skip, {ct_cth_empty_SUITE, end_per_suite,"Test skip"}},
-
+
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,cth,{'_',terminate,[[]]}},
{?eh,stop_logging,[]}
];
+test_events(skip_pre_init_tc_cth) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,init,['_',[]]}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [ct_cth_empty_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [ct_cth_empty_SUITE,test_case,'$proplist',
+ {skip,"Skipped in pre_init_per_testcase"},
+ []]}},
+ {?eh,tc_done,{ct_cth_empty_SUITE,test_case,
+ {skipped,"Skipped in pre_init_per_testcase"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [ct_cth_empty_SUITE,test_case,
+ {tc_user_skip,"Skipped in pre_init_per_testcase"},
+ []]}},
+ {?eh,test_stats,{0,0,{1,0}}},
+ {?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [ct_cth_empty_SUITE,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_cth_empty_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(recover_post_suite_cth) ->
Suite = ct_cth_fail_per_suite_SUITE,
[
@@ -840,11 +923,11 @@ test_events(recover_post_suite_cth) ->
{?eh,tc_start,{Suite,test_case}},
{?eh,cth,{'_',pre_init_per_testcase,
- [test_case, not_contains([tc_status]),[]]}},
+ [Suite,test_case, not_contains([tc_status]),[]]}},
{?eh,cth,{'_',post_end_per_testcase,
- [test_case, contains([tc_status]),'_',[]]}},
+ [Suite,test_case, contains([tc_status]),'_',[]]}},
{?eh,tc_done,{Suite,test_case,ok}},
-
+
{?eh,tc_start,{Suite,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,
[Suite,not_contains([tc_status]),[]]}},
@@ -861,7 +944,7 @@ test_events(update_config_cth) ->
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,cth,{'_',init,['_',[]]}},
-
+
{?eh,tc_start,{ct_update_config_SUITE,init_per_suite}},
{?eh,cth,{'_',pre_init_per_suite,
[ct_update_config_SUITE,contains([]),[]]}},
@@ -876,13 +959,15 @@ test_events(update_config_cth) ->
{?eh,tc_start,{ct_update_config_SUITE, {init_per_group,group1,[]}}},
{?eh,cth,{'_',pre_init_per_group,
- [group1,contains(
+ [ct_update_config_SUITE,
+ group1,contains(
[post_init_per_suite,
init_per_suite,
pre_init_per_suite]),
[]]}},
{?eh,cth,{'_',post_init_per_group,
- [group1,
+ [ct_update_config_SUITE,
+ group1,
contains(
[post_init_per_suite,
init_per_suite,
@@ -898,7 +983,8 @@ test_events(update_config_cth) ->
{?eh,tc_start,{ct_update_config_SUITE,test_case}},
{?eh,cth,{'_',pre_init_per_testcase,
- [test_case,contains(
+ [ct_update_config_SUITE,
+ test_case,contains(
[post_init_per_group,
init_per_group,
pre_init_per_group,
@@ -907,7 +993,8 @@ test_events(update_config_cth) ->
pre_init_per_suite]),
[]]}},
{?eh,cth,{'_',post_end_per_testcase,
- [test_case,contains(
+ [ct_update_config_SUITE,
+ test_case,contains(
[init_per_testcase,
pre_init_per_testcase,
post_init_per_group,
@@ -921,7 +1008,8 @@ test_events(update_config_cth) ->
{?eh,tc_start,{ct_update_config_SUITE, {end_per_group,group1,[]}}},
{?eh,cth,{'_',pre_end_per_group,
- [group1,contains(
+ [ct_update_config_SUITE,
+ group1,contains(
[post_init_per_group,
init_per_group,
pre_init_per_group,
@@ -930,7 +1018,8 @@ test_events(update_config_cth) ->
pre_init_per_suite]),
[]]}},
{?eh,cth,{'_',post_end_per_group,
- [group1,
+ [ct_update_config_SUITE,
+ group1,
contains(
[pre_end_per_group,
post_init_per_group,
@@ -941,7 +1030,7 @@ test_events(update_config_cth) ->
pre_init_per_suite]),
ok,[]]}},
{?eh,tc_done,{ct_update_config_SUITE,{end_per_group,group1,[]},ok}},
-
+
{?eh,tc_start,{ct_update_config_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,
[ct_update_config_SUITE,contains(
@@ -974,7 +1063,7 @@ test_events(state_update_cth) ->
{?eh,cth,{'_',init,['_',[]]}},
{?eh,cth,{'_',init,['_',[]]}},
{?eh,tc_start,{'_',init_per_suite}},
-
+
{?eh,tc_done,{'_',end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,cth,{'_',terminate,[contains(
@@ -1018,10 +1107,10 @@ test_events(options_cth) ->
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}},
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
- {?eh,cth,{empty_cth,pre_init_per_testcase,[test_case,'$proplist',[test]]}},
- {?eh,cth,{empty_cth,post_end_per_testcase,[test_case,'$proplist','_',[test]]}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[test]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist','_',[test]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
{?eh,cth,{empty_cth,pre_end_per_suite,
[ct_cth_empty_SUITE,'$proplist',[test]]}},
@@ -1051,14 +1140,14 @@ test_events(same_id_cth) ->
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}}},
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
{negative,
- {?eh,cth,{'_',pre_init_per_testcase,[test_case,'$proplist',[]]}},
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}}},
+ {?eh,cth,{'_',pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',ok,[]]}}},
{negative,
- {?eh,cth,{'_',post_end_per_testcase,[test_case,'$proplist',ok,[]]}},
+ {?eh,cth,{'_',post_end_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}}},
-
+
{?eh,tc_start,{ct_cth_empty_SUITE,end_per_suite}},
{?eh,cth,{'_',pre_end_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}},
{negative,
@@ -1094,11 +1183,13 @@ test_events(fail_n_skip_with_minimal_cth) ->
{?eh,tc_done,{ct_cth_fail_one_skip_one_SUITE,test_case2,{skipped,"skip it"}}},
{?eh,tc_start,{ct_cth_fail_one_skip_one_SUITE,test_case3}},
{?eh,tc_done,{ct_cth_fail_one_skip_one_SUITE,test_case3,{skipped,"skip it"}}},
- {?eh,cth,{empty_cth,on_tc_skip,[{test_case2,group2},
- {tc_user_skip,{skipped,"skip it"}},
+ {?eh,cth,{empty_cth,on_tc_skip,[ct_cth_fail_one_skip_one_SUITE,
+ {test_case2,group2},
+ {tc_user_skip,"skip it"},
[]]}},
- {?eh,cth,{empty_cth,on_tc_skip,[{test_case3,group2},
- {tc_user_skip,{skipped,"skip it"}},
+ {?eh,cth,{empty_cth,on_tc_skip,[ct_cth_fail_one_skip_one_SUITE,
+ {test_case3,group2},
+ {tc_user_skip,"skip it"},
[]]}},
{?eh,tc_start,{ct_cth_fail_one_skip_one_SUITE,{end_per_group,
group2,[parallel]}}},
@@ -1115,17 +1206,25 @@ test_events(fail_n_skip_with_minimal_cth) ->
];
test_events(prio_cth) ->
-
- GenPre = fun(Func,States) ->
- [{?eh,cth,{'_',Func,['_','_',State]}} ||
+ GenPre = fun(Func,States) when Func==pre_init_per_suite;
+ Func==pre_end_per_suite ->
+ [{?eh,cth,{'_',Func,['_','_',State]}} ||
+ State <- States];
+ (Func,States) ->
+ [{?eh,cth,{'_',Func,['_','_','_',State]}} ||
State <- States]
end,
- GenPost = fun(Func,States) ->
- [{?eh,cth,{'_',Func,['_','_','_',State]}} ||
+ GenPost = fun(Func,States) when Func==post_init_per_suite;
+ Func==post_end_per_suite ->
+ [{?eh,cth,{'_',Func,['_','_','_',State]}} ||
+ State <- States];
+ (Func,States) ->
+ [{?eh,cth,{'_',Func,['_','_','_','_',State]}} ||
State <- States]
- end,
-
+
+ end,
+
[{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}] ++
@@ -1136,7 +1235,7 @@ test_events(prio_cth) ->
[[1100,100],[600,200],[600,600],[700],[800],[900],[1000],
[1200,1050],[1100],[1200]]) ++
[{?eh,tc_done,{ct_cth_prio_SUITE,init_per_suite,ok}},
-
+
[{?eh,tc_start,{ct_cth_prio_SUITE,{init_per_group,'_',[]}}}] ++
GenPre(pre_init_per_group,
@@ -1147,7 +1246,7 @@ test_events(prio_cth) ->
[900],[900,900],[500,900],[1000],[1200,1050],
[1100],[1200]]) ++
[{?eh,tc_done,{ct_cth_prio_SUITE,{init_per_group,'_',[]},ok}}] ++
-
+
[{?eh,tc_start,{ct_cth_prio_SUITE,test_case}}] ++
GenPre(pre_init_per_testcase,
[[1100,100],[600,200],[600,600],[600],[700],[800],
@@ -1161,7 +1260,7 @@ test_events(prio_cth) ->
[{?eh,tc_done,{ct_cth_prio_SUITE,test_case,ok}},
{?eh,tc_start,{ct_cth_prio_SUITE,{end_per_group,'_',[]}}}] ++
- GenPre(pre_end_per_group,
+ GenPre(pre_end_per_group,
lists:reverse(
[[1100,100],[600,200],[600,600],[600],[700],[800],
[900],[900,900],[500,900],[1000],[1200,1050],
@@ -1200,30 +1299,30 @@ test_events(no_config) ->
{?eh,tc_done,{ct_framework,init_per_suite,ok}},
{?eh,tc_start,{ct_no_config_SUITE,test_case_1}},
{?eh,cth,{empty_cth,pre_init_per_testcase,
- [test_case_1,'$proplist',[]]}},
+ [ct_no_config_SUITE,test_case_1,'$proplist',[]]}},
{?eh,cth,{empty_cth,post_end_per_testcase,
- [test_case_1,'$proplist',ok,[]]}},
+ [ct_no_config_SUITE,test_case_1,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_no_config_SUITE,test_case_1,ok}},
{?eh,test_stats,{1,0,{0,0}}},
[{?eh,tc_start,{ct_framework,{init_per_group,test_group,'$proplist'}}},
{?eh,cth,{empty_cth,pre_init_per_group,
- [test_group,'$proplist',[]]}},
+ [ct_no_config_SUITE,test_group,'$proplist',[]]}},
{?eh,cth,{empty_cth,post_init_per_group,
- [test_group,'$proplist','$proplist',[]]}},
+ [ct_no_config_SUITE,test_group,'$proplist','$proplist',[]]}},
{?eh,tc_done,{ct_framework,
{init_per_group,test_group,'$proplist'},ok}},
{?eh,tc_start,{ct_no_config_SUITE,test_case_2}},
{?eh,cth,{empty_cth,pre_init_per_testcase,
- [test_case_2,'$proplist',[]]}},
+ [ct_no_config_SUITE,test_case_2,'$proplist',[]]}},
{?eh,cth,{empty_cth,post_end_per_testcase,
- [test_case_2,'$proplist',ok,[]]}},
+ [ct_no_config_SUITE,test_case_2,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_no_config_SUITE,test_case_2,ok}},
{?eh,test_stats,{2,0,{0,0}}},
{?eh,tc_start,{ct_framework,{end_per_group,test_group,'$proplist'}}},
{?eh,cth,{empty_cth,pre_end_per_group,
- [test_group,'$proplist',[]]}},
+ [ct_no_config_SUITE,test_group,'$proplist',[]]}},
{?eh,cth,{empty_cth,post_end_per_group,
- [test_group,'$proplist',ok,[]]}},
+ [ct_no_config_SUITE,test_group,'$proplist',ok,[]]}},
{?eh,tc_done,{ct_framework,{end_per_group,test_group,'$proplist'},ok}}],
{?eh,tc_start,{ct_framework,end_per_suite}},
{?eh,cth,{empty_cth,pre_end_per_suite,
@@ -1236,6 +1335,166 @@ test_events(no_config) ->
{?eh,stop_logging,[]}
];
+test_events(no_init_suite_config) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,tc_start,{ct_no_init_suite_config_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [ct_no_init_suite_config_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [ct_no_init_suite_config_SUITE,'$proplist','_',[]]}},
+ {?eh,tc_done,{ct_no_init_suite_config_SUITE,init_per_suite,
+ {failed,{error,{undef,'_'}}}}},
+ {?eh,cth,{empty_cth,on_tc_fail,[ct_no_init_suite_config_SUITE,
+ init_per_suite,
+ {undef,'_'},[]]}},
+ {?eh,tc_auto_skip,{ct_no_init_suite_config_SUITE,test_case,
+ {failed,{ct_no_init_suite_config_SUITE,init_per_suite,
+ {'EXIT',{undef,'_'}}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [ct_no_init_suite_config_SUITE,
+ test_case,
+ {tc_auto_skip,
+ {failed,{ct_no_init_suite_config_SUITE,init_per_suite,
+ {'EXIT',{undef,'_'}}}}},
+ []]}},
+ {?eh,test_stats,{0,0,{0,1}}},
+ {?eh,tc_auto_skip,{ct_no_init_suite_config_SUITE,end_per_suite,
+ {failed,{ct_no_init_suite_config_SUITE,init_per_suite,
+ {'EXIT',{undef,'_'}}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [ct_no_init_suite_config_SUITE,
+ end_per_suite,
+ {tc_auto_skip,
+ {failed,{ct_no_init_suite_config_SUITE,init_per_suite,
+ {'EXIT',{undef,'_'}}}}},
+ []]}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(no_init_config) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{1,1,2}},
+ {?eh,tc_start,{ct_no_init_config_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [ct_no_init_config_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [ct_no_init_config_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_no_init_config_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{ct_no_init_config_SUITE,test_case_1}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [ct_no_init_config_SUITE,test_case_1,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [ct_no_init_config_SUITE,test_case_1,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_no_init_config_SUITE,test_case_1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ [{?eh,tc_start,{ct_no_init_config_SUITE,{init_per_group,test_group,[]}}},
+ {?eh,cth,{empty_cth,pre_init_per_group,
+ [ct_no_init_config_SUITE,test_group,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_group,
+ [ct_no_init_config_SUITE,test_group,'$proplist','_',[]]}},
+ {?eh,tc_done,{ct_no_init_config_SUITE,{init_per_group,test_group,[]},
+ {failed,{error,{undef,'_'}}}}},
+ {?eh,cth,{empty_cth,on_tc_fail,[ct_no_init_config_SUITE,
+ {init_per_group,test_group},
+ {undef,'_'},[]]}},
+ {?eh,tc_auto_skip,{ct_no_init_config_SUITE,{test_case_2,test_group},
+ {failed,{ct_no_init_config_SUITE,init_per_group,
+ {'EXIT',{undef,'_'}}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,[ct_no_init_config_SUITE,
+ {test_case_2,test_group},
+ {tc_auto_skip,
+ {failed,
+ {ct_no_init_config_SUITE,init_per_group,
+ {'EXIT',{undef,'_'}}}}},
+ []]}},
+ {?eh,test_stats,{1,0,{0,1}}},
+ {?eh,tc_auto_skip,{ct_no_init_config_SUITE,{end_per_group,test_group},
+ {failed,{ct_no_init_config_SUITE,init_per_group,
+ {'EXIT',{undef,'_'}}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,[ct_no_init_config_SUITE,
+ {end_per_group,test_group},
+ {tc_auto_skip,
+ {failed,
+ {ct_no_init_config_SUITE,init_per_group,
+ {'EXIT',{undef,'_'}}}}},
+ []]}}],
+ {?eh,tc_start,{ct_no_init_config_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,
+ [ct_no_init_config_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [ct_no_init_config_SUITE,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_no_init_config_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(no_end_config) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{1,1,2}},
+ {?eh,tc_start,{ct_no_end_config_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [ct_no_end_config_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [ct_no_end_config_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_no_end_config_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{ct_no_end_config_SUITE,test_case_1}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [ct_no_end_config_SUITE,test_case_1,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [ct_no_end_config_SUITE,test_case_1,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_no_end_config_SUITE,test_case_1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ [{?eh,tc_start,{ct_no_end_config_SUITE,
+ {init_per_group,test_group,'$proplist'}}},
+ {?eh,cth,{empty_cth,pre_init_per_group,
+ [ct_no_end_config_SUITE,test_group,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_group,
+ [ct_no_end_config_SUITE,test_group,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_no_end_config_SUITE,
+ {init_per_group,test_group,'$proplist'},ok}},
+ {?eh,tc_start,{ct_no_end_config_SUITE,test_case_2}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [ct_no_end_config_SUITE,test_case_2,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [ct_no_end_config_SUITE,test_case_2,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_no_end_config_SUITE,test_case_2,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ {?eh,tc_start,{ct_no_end_config_SUITE,
+ {end_per_group,test_group,'$proplist'}}},
+ {?eh,cth,{empty_cth,pre_end_per_group,
+ [ct_no_end_config_SUITE,test_group,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_group,
+ [ct_no_end_config_SUITE,test_group,'$proplist','_',[]]}},
+ {?eh,tc_done,{ct_no_end_config_SUITE,{end_per_group,test_group,[]},
+ {failed,{error,{undef,'_'}}}}},
+ {?eh,cth,{empty_cth,on_tc_fail,[ct_no_end_config_SUITE,
+ {end_per_group,test_group},
+ {undef,'_'},[]]}}],
+ {?eh,tc_start,{ct_no_end_config_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,
+ [ct_no_end_config_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [ct_no_end_config_SUITE,'$proplist','_',[]]}},
+ {?eh,tc_done,{ct_no_end_config_SUITE,end_per_suite,
+ {failed,{error,{undef,'_'}}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(data_dir) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
@@ -1250,30 +1509,30 @@ test_events(data_dir) ->
{?eh,tc_done,{ct_framework,init_per_suite,ok}},
{?eh,tc_start,{ct_data_dir_SUITE,test_case_1}},
{?eh,cth,{empty_cth,pre_init_per_testcase,
- [test_case_1,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_case_1,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,cth,{empty_cth,post_end_per_testcase,
- [test_case_1,'$proplist',ok,[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_case_1,'$proplist',ok,[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,tc_done,{ct_data_dir_SUITE,test_case_1,ok}},
{?eh,test_stats,{1,0,{0,0}}},
[{?eh,tc_start,{ct_framework,{init_per_group,test_group,'$proplist'}}},
{?eh,cth,{empty_cth,pre_init_per_group,
- [test_group,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_group,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,cth,{empty_cth,post_init_per_group,
- [test_group,'$proplist','$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_group,'$proplist','$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,tc_done,{ct_framework,
{init_per_group,test_group,'$proplist'},ok}},
{?eh,tc_start,{ct_data_dir_SUITE,test_case_2}},
{?eh,cth,{empty_cth,pre_init_per_testcase,
- [test_case_2,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_case_2,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,cth,{empty_cth,post_end_per_testcase,
- [test_case_2,'$proplist',ok,[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_case_2,'$proplist',ok,[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,tc_done,{ct_data_dir_SUITE,test_case_2,ok}},
{?eh,test_stats,{2,0,{0,0}}},
{?eh,tc_start,{ct_framework,{end_per_group,test_group,'$proplist'}}},
{?eh,cth,{empty_cth,pre_end_per_group,
- [test_group,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_group,'$proplist',[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,cth,{empty_cth,post_end_per_group,
- [test_group,'$proplist',ok,[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
+ [ct_data_dir_SUITE,test_group,'$proplist',ok,[{data_dir_name,"ct_data_dir_SUITE_data"}]]}},
{?eh,tc_done,{ct_framework,{end_per_group,test_group,'$proplist'},ok}}],
{?eh,tc_start,{ct_framework,end_per_suite}},
{?eh,cth,{empty_cth,pre_end_per_suite,
@@ -1300,16 +1559,654 @@ test_events(cth_log) ->
[{suite,cth_log_SUITE},parallel]}}},
{?eh,tc_done,{ct_framework,{end_per_group,g1,
[{suite,cth_log_SUITE},parallel]},ok}}]},
-
+
{?eh,tc_done,{cth_log_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]}
];
+test_events(fallback) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,tc_start,{all_hook_callbacks_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [all_hook_callbacks_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [all_hook_callbacks_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{all_hook_callbacks_SUITE,init_per_suite,ok}},
+
+ [{?eh,tc_start,{ct_framework,{init_per_group,test_group,'$proplist'}}},
+ {?eh,cth,{empty_cth,pre_init_per_group,
+ [fallback_nosuite,test_group,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_group,
+ [fallback_nosuite,test_group,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_framework,
+ {init_per_group,test_group,'$proplist'},ok}},
+ {?eh,tc_start,{all_hook_callbacks_SUITE,test_case}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [fallback_nosuite,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [fallback_nosuite,test_case,'$proplist',ok,[]]}},
+ {?eh,tc_done,{all_hook_callbacks_SUITE,test_case,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{ct_framework,{end_per_group,test_group,'$proplist'}}},
+ {?eh,cth,{empty_cth,pre_end_per_group,
+ [fallback_nosuite,test_group,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_group,
+ [fallback_nosuite,test_group,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_framework,{end_per_group,test_group,'$proplist'},ok}}],
+ {?eh,tc_start,{all_hook_callbacks_SUITE,test_case}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [fallback_nosuite,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [fallback_nosuite,test_case,'$proplist','_',[]]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,
+ [fallback_nosuite,test_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [fallback_nosuite,test_case,'$proplist','_',[]]}},
+ {?eh,tc_done,{all_hook_callbacks_SUITE,test_case,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ {?eh,tc_start,{all_hook_callbacks_SUITE,skip_case}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [fallback_nosuite,skip_case,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [fallback_nosuite,skip_case,'$proplist',
+ {skip,"Skipped in init_per_testcase/2"},[]]}},
+ {?eh,tc_done,{all_hook_callbacks_SUITE,skip_case,
+ {skipped,"Skipped in init_per_testcase/2"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [fallback_nosuite,skip_case,
+ {tc_user_skip,"Skipped in init_per_testcase/2"},
+ []]}},
+ {?eh,test_stats,{2,0,{1,0}}},
+ {?eh,tc_start,{all_hook_callbacks_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,
+ [all_hook_callbacks_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [all_hook_callbacks_SUITE,'$proplist','_',[]]}},
+ {?eh,tc_done,{all_hook_callbacks_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(callbacks_on_skip) ->
+ %% skip_cth.erl will send a 'cth_error' event if a hook is
+ %% erroneously called. Therefore, all Events are changed to
+ %% {negative,{?eh,cth_error,'_'},Event}
+ %% at the end of this function.
+ Events =
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{6,6,15}},
+
+ %% all_hook_callbacks_SUITE is skipped in spec
+ %% Only the on_tc_skip callback shall be called
+ {?eh,tc_user_skip,{all_hook_callbacks_SUITE,all,"Skipped in spec"}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [all_hook_callbacks_SUITE,all,
+ {tc_user_skip,"Skipped in spec"},
+ []]}},
+ {?eh,test_stats,{0,0,{1,0}}},
+
+ %% skip_init_SUITE is skipped in its init_per_suite function
+ %% No group- or testcase-functions shall be called.
+ {?eh,tc_start,{skip_init_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [skip_init_SUITE,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [skip_init_SUITE,
+ '$proplist',
+ {skip,"Skipped in init_per_suite/1"},
+ []]}},
+ {?eh,tc_done,{skip_init_SUITE,init_per_suite,
+ {skipped,"Skipped in init_per_suite/1"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_init_SUITE,init_per_suite,
+ {tc_user_skip,"Skipped in init_per_suite/1"},
+ []]}},
+ {?eh,tc_user_skip,{skip_init_SUITE,test_case,"Skipped in init_per_suite/1"}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_init_SUITE,test_case,
+ {tc_user_skip,"Skipped in init_per_suite/1"},
+ []]}},
+ {?eh,test_stats,{0,0,{2,0}}},
+ {?eh,tc_user_skip,{skip_init_SUITE,end_per_suite,
+ "Skipped in init_per_suite/1"}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_init_SUITE,end_per_suite,
+ {tc_user_skip,"Skipped in init_per_suite/1"},
+ []]}},
+
+ %% skip_req_SUITE is auto-skipped since a 'require' statement
+ %% returned by suite/0 is not fulfilled.
+ %% No group- or testcase-functions shall be called.
+ {?eh,tc_start,{skip_req_SUITE,init_per_suite}},
+ {?eh,tc_done,{skip_req_SUITE,init_per_suite,
+ {auto_skipped,{require_failed_in_suite0,
+ {not_available,whatever}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_req_SUITE,init_per_suite,
+ {tc_auto_skip,{require_failed_in_suite0,
+ {not_available,whatever}}},
+ []]}},
+ {?eh,tc_auto_skip,{skip_req_SUITE,test_case,{require_failed_in_suite0,
+ {not_available,whatever}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_req_SUITE,test_case,
+ {tc_auto_skip,{require_failed_in_suite0,
+ {not_available,whatever}}},
+ []]}},
+ {?eh,test_stats,{0,0,{2,1}}},
+ {?eh,tc_auto_skip,{skip_req_SUITE,end_per_suite,
+ {require_failed_in_suite0,
+ {not_available,whatever}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_req_SUITE,end_per_suite,
+ {tc_auto_skip,{require_failed_in_suite0,
+ {not_available,whatever}}},
+ []]}},
+
+ %% skip_fail_SUITE is auto-skipped since the suite/0 function
+ %% retuns a faluty format.
+ %% No group- or testcase-functions shall be called.
+ {?eh,tc_start,{skip_fail_SUITE,init_per_suite}},
+ {?eh,tc_done,{skip_fail_SUITE,init_per_suite,
+ {failed,{error,{suite0_failed,bad_return_value}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_fail_SUITE,init_per_suite,
+ {tc_auto_skip,
+ {failed,{error,{suite0_failed,bad_return_value}}}},
+ []]}},
+ {?eh,tc_auto_skip,{skip_fail_SUITE,test_case,
+ {failed,{error,{suite0_failed,bad_return_value}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_fail_SUITE,test_case,
+ {tc_auto_skip,
+ {failed,{error,{suite0_failed,bad_return_value}}}},
+ []]}},
+ {?eh,test_stats,{0,0,{2,2}}},
+ {?eh,tc_auto_skip,{skip_fail_SUITE,end_per_suite,
+ {failed,{error,{suite0_failed,bad_return_value}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_fail_SUITE,end_per_suite,
+ {tc_auto_skip,
+ {failed,{error,{suite0_failed,bad_return_value}}}},
+ []]}},
+
+ %% skip_group_SUITE
+ {?eh,tc_start,{skip_group_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [skip_group_SUITE,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [skip_group_SUITE,
+ '$proplist',
+ '_',
+ []]}},
+ {?eh,tc_done,{skip_group_SUITE,init_per_suite,ok}},
+
+ %% test_group_1 - auto_skip due to require failed
+ [{?eh,tc_start,{skip_group_SUITE,{init_per_group,test_group_1,[]}}},
+ {?eh,tc_done,
+ {skip_group_SUITE,{init_per_group,test_group_1,[]},
+ {auto_skipped,{require_failed,{not_available,whatever}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {init_per_group,test_group_1},
+ {tc_auto_skip,{require_failed,{not_available,whatever}}},
+ []]}},
+ {?eh,tc_auto_skip,{skip_group_SUITE,{test_case,test_group_1},
+ {require_failed,{not_available,whatever}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {test_case,test_group_1},
+ {tc_auto_skip,{require_failed,{not_available,whatever}}},
+ []]}},
+ {?eh,test_stats,{0,0,{2,3}}},
+ {?eh,tc_auto_skip,{skip_group_SUITE,{end_per_group,test_group_1},
+ {require_failed,{not_available,whatever}}}}],
+ %% The following appears to be outside of the group, but
+ %% that's only an implementation detail in
+ %% ct_test_support.erl - it does not know about events from
+ %% test suite specific hooks and regards the group ended with
+ %% the above tc_auto_skip-event for end_per_group.
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {end_per_group,test_group_1},
+ {tc_auto_skip,{require_failed,{not_available,whatever}}},
+ []]}},
+
+ %% test_group_2 - auto_skip due to failed return from group/1
+ [{?eh,tc_start,{skip_group_SUITE,{init_per_group,test_group_2,[]}}},
+ {?eh,tc_done,
+ {skip_group_SUITE,{init_per_group,test_group_2,[]},
+ {auto_skipped,{group0_failed,bad_return_value}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {init_per_group,test_group_2},
+ {tc_auto_skip,{group0_failed,bad_return_value}},
+ []]}},
+ {?eh,tc_auto_skip,{skip_group_SUITE,{test_case,test_group_2},
+ {group0_failed,bad_return_value}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {test_case,test_group_2},
+ {tc_auto_skip,{group0_failed,bad_return_value}},
+ []]}},
+ {?eh,test_stats,{0,0,{2,4}}},
+ {?eh,tc_auto_skip,{skip_group_SUITE,{end_per_group,test_group_2},
+ {group0_failed,bad_return_value}}}],
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {end_per_group,test_group_2},
+ {tc_auto_skip,{group0_failed,bad_return_value}},
+ []]}},
+ %% test_group_3 - user_skip in init_per_group/2
+ [{?eh,tc_start,
+ {skip_group_SUITE,{init_per_group,test_group_3,[]}}},
+ {?eh,cth,{empty_cth,pre_init_per_group,
+ [skip_group_SUITE,test_group_3,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_group,
+ [skip_group_SUITE,test_group_3,'$proplist',
+ {skip,"Skipped in init_per_group/2"},
+ []]}},
+ {?eh,tc_done,{skip_group_SUITE,
+ {init_per_group,test_group_3,[]},
+ {skipped,"Skipped in init_per_group/2"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {init_per_group,test_group_3},
+ {tc_user_skip,"Skipped in init_per_group/2"},
+ []]}},
+ {?eh,tc_user_skip,{skip_group_SUITE,
+ {test_case,test_group_3},
+ "Skipped in init_per_group/2"}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {test_case,test_group_3},
+ {tc_user_skip,"Skipped in init_per_group/2"},
+ []]}},
+ {?eh,test_stats,{0,0,{3,4}}},
+ {?eh,tc_user_skip,{skip_group_SUITE,
+ {end_per_group,test_group_3},
+ "Skipped in init_per_group/2"}}],
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_group_SUITE,
+ {end_per_group,test_group_3},
+ {tc_user_skip,"Skipped in init_per_group/2"},
+ []]}},
+
+ {?eh,tc_start,{skip_group_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,
+ [skip_group_SUITE,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [skip_group_SUITE,
+ '$proplist',
+ ok,[]]}},
+ {?eh,tc_done,{skip_group_SUITE,end_per_suite,ok}},
+
+
+ %% skip_case_SUITE has 4 test cases which are all skipped in
+ %% different ways
+ {?eh,tc_start,{skip_case_SUITE,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [skip_case_SUITE,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [skip_case_SUITE,
+ '$proplist',
+ '_',
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,init_per_suite,ok}},
+
+ %% Skip in spec -> only on_tc_skip shall be called
+ {?eh,tc_user_skip,{skip_case_SUITE,skip_in_spec,"Skipped in spec"}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,skip_in_spec,
+ {tc_user_skip,"Skipped in spec"},
+ []]}},
+ {?eh,test_stats,{0,0,{4,4}}},
+
+ %% Skip in init_per_testcase -> pre/post_end_per_testcase
+ %% shall not be called
+ {?eh,tc_start,{skip_case_SUITE,skip_in_init}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [skip_case_SUITE,skip_in_init,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [skip_case_SUITE,skip_in_init,
+ '$proplist',
+ {skip,"Skipped in init_per_testcase/2"},
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,skip_in_init,
+ {skipped,"Skipped in init_per_testcase/2"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,skip_in_init,
+ {tc_user_skip,"Skipped in init_per_testcase/2"},
+ []]}},
+ {?eh,test_stats,{0,0,{5,4}}},
+
+ %% Fail in init_per_testcase -> pre/post_end_per_testcase
+ %% shall not be called
+ {?eh,tc_start,{skip_case_SUITE,fail_in_init}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [skip_case_SUITE,fail_in_init,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [skip_case_SUITE,fail_in_init,
+ '$proplist',
+ {skip,{failed,'_'}},
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,fail_in_init,
+ {auto_skipped,{failed,'_'}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,fail_in_init,
+ {tc_auto_skip,{failed,'_'}},
+ []]}},
+ {?eh,test_stats,{0,0,{5,5}}},
+
+ %% Exit in init_per_testcase -> pre/post_end_per_testcase
+ %% shall not be called
+ {?eh,tc_start,{skip_case_SUITE,exit_in_init}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [skip_case_SUITE,exit_in_init,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [skip_case_SUITE,exit_in_init,
+ '$proplist',
+ {skip,{failed,'_'}},
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,exit_in_init,
+ {auto_skipped,{failed,'_'}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,exit_in_init,
+ {tc_auto_skip,{failed,'_'}},
+ []]}},
+ {?eh,test_stats,{0,0,{5,6}}},
+
+ %% Fail in end_per_testcase -> all hooks shall be called and
+ %% test shall succeed.
+ {?eh,tc_start,{skip_case_SUITE,fail_in_end}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [skip_case_SUITE,fail_in_end,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [skip_case_SUITE,fail_in_end,
+ '$proplist',
+ ok,
+ []]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,
+ [skip_case_SUITE,fail_in_end,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [skip_case_SUITE,fail_in_end,
+ '$proplist',
+ {failed,
+ {skip_case_SUITE,end_per_testcase,
+ {'EXIT',
+ {test_case_failed,"Failed in end_per_testcase/2"}}}},
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,fail_in_end,
+ {failed,
+ {skip_case_SUITE,end_per_testcase,
+ {'EXIT',
+ {test_case_failed,"Failed in end_per_testcase/2"}}}}}},
+ {?eh,test_stats,{1,0,{5,6}}},
+
+ %% Exit in end_per_testcase -> all hooks shall be called and
+ %% test shall succeed.
+ {?eh,tc_start,{skip_case_SUITE,exit_in_end}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [skip_case_SUITE,exit_in_end,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [skip_case_SUITE,exit_in_end,
+ '$proplist',
+ ok,
+ []]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,
+ [skip_case_SUITE,exit_in_end,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [skip_case_SUITE,exit_in_end,
+ '$proplist',
+ {failed,
+ {skip_case_SUITE,end_per_testcase,
+ {'EXIT',"Exit in end_per_testcase/2"}}},
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,exit_in_end,
+ {failed,
+ {skip_case_SUITE,end_per_testcase,
+ {'EXIT',"Exit in end_per_testcase/2"}}}}},
+ {?eh,test_stats,{2,0,{5,6}}},
+
+ %% Skip in testcase function -> all callbacks shall be called
+ {?eh,tc_start,{skip_case_SUITE,skip_in_case}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [skip_case_SUITE,skip_in_case,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [skip_case_SUITE,skip_in_case,
+ '$proplist',
+ ok,[]]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,
+ [skip_case_SUITE,skip_in_case,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [skip_case_SUITE,skip_in_case,
+ '$proplist',
+ {skip,"Skipped in test case function"},
+ []]}},
+ {?eh,tc_done,{skip_case_SUITE,skip_in_case,
+ {skipped,"Skipped in test case function"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,skip_in_case,
+ {tc_user_skip,"Skipped in test case function"},
+ []]}},
+ {?eh,test_stats,{2,0,{6,6}}},
+
+ %% Auto skip due to failed 'require' -> only the on_tc_skip
+ %% callback shall be called
+ {?eh,tc_start,{skip_case_SUITE,req_auto_skip}},
+ {?eh,tc_done,{skip_case_SUITE,req_auto_skip,
+ {auto_skipped,{require_failed,{not_available,whatever}}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,req_auto_skip,
+ {tc_auto_skip,{require_failed,{not_available,whatever}}},
+ []]}},
+ {?eh,test_stats,{2,0,{6,7}}},
+
+ %% Auto skip due to failed testcase/0 function -> only the
+ %% on_tc_skip callback shall be called
+ {?eh,tc_start,{skip_case_SUITE,fail_auto_skip}},
+ {?eh,tc_done,{skip_case_SUITE,fail_auto_skip,
+ {auto_skipped,{testcase0_failed,bad_return_value}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [skip_case_SUITE,fail_auto_skip,
+ {tc_auto_skip,{testcase0_failed,bad_return_value}},
+ []]}},
+ {?eh,test_stats,{2,0,{6,8}}},
+
+ {?eh,tc_start,{skip_case_SUITE,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,
+ [skip_case_SUITE,
+ '$proplist',
+ []]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [skip_case_SUITE,
+ '$proplist',
+ ok,[]]}},
+ {?eh,tc_done,{skip_case_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ],
+ %% Make sure no 'cth_error' events are received!
+ [{negative,{?eh,cth_error,'_'},E} || E <- Events];
+
+test_events(failed_sequence) ->
+ %% skip_cth.erl will send a 'cth_error' event if a hook is
+ %% erroneously called. Therefore, all Events are changed to
+ %% {negative,{?eh,cth_error,'_'},Event}
+ %% at the end of this function.
+ Events =
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{1,1,2}},
+ {?eh,tc_start,{ct_framework,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,[seq_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [seq_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_framework,init_per_suite,ok}},
+ {?eh,tc_start,{seq_SUITE,test_case_1}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [seq_SUITE,test_case_1,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [seq_SUITE,test_case_1,'$proplist',ok,[]]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,
+ [seq_SUITE,test_case_1,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [seq_SUITE,test_case_1,'$proplist',
+ {error,failed_on_purpose},[]]}},
+ {?eh,tc_done,{seq_SUITE,test_case_1,{failed,{error,failed_on_purpose}}}},
+ {?eh,cth,{empty_cth,on_tc_fail,
+ [seq_SUITE,test_case_1,failed_on_purpose,[]]}},
+ {?eh,test_stats,{0,1,{0,0}}},
+ {?eh,tc_start,{seq_SUITE,test_case_2}},
+ {?eh,tc_done,{seq_SUITE,test_case_2,
+ {auto_skipped,{sequence_failed,seq1,test_case_1}}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [seq_SUITE,test_case_2,
+ {tc_auto_skip,{sequence_failed,seq1,test_case_1}},
+ []]}},
+ {?eh,test_stats,{0,1,{0,1}}},
+ {?eh,tc_start,{ct_framework,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,[seq_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,[seq_SUITE,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_framework,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ],
+ %% Make sure no 'cth_error' events are received!
+ [{negative,{?eh,cth_error,'_'},E} || E <- Events];
+
+test_events(repeat_force_stop) ->
+ %% skip_cth.erl will send a 'cth_error' event if a hook is
+ %% erroneously called. Therefore, all Events are changed to
+ %% {negative,{?eh,cth_error,'_'},Event}
+ %% at the end of this function.
+ Events=
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{1,1,2}},
+ {?eh,tc_start,{ct_framework,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,[repeat_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [repeat_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_framework,init_per_suite,ok}},
+ {?eh,tc_start,{repeat_SUITE,test_case_1}},
+ {?eh,cth,{empty_cth,pre_init_per_testcase,
+ [repeat_SUITE,test_case_1,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_testcase,
+ [repeat_SUITE,test_case_1,'$proplist',ok,[]]}},
+ {?eh,cth,{empty_cth,pre_end_per_testcase,
+ [repeat_SUITE,test_case_1,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_testcase,
+ [repeat_SUITE,test_case_1,'$proplist',ok,[]]}},
+ {?eh,tc_done,{repeat_SUITE,test_case_1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{repeat_SUITE,test_case_2}},
+ {?eh,tc_done,{repeat_SUITE,test_case_2,
+ {auto_skipped,
+ "Repeated test stopped by force_stop option"}}},
+ {?eh,cth,{empty_cth,on_tc_skip,
+ [repeat_SUITE,test_case_2,
+ {tc_auto_skip,"Repeated test stopped by force_stop option"},
+ []]}},
+ {?eh,test_stats,{1,0,{0,1}}},
+ {?eh,tc_start,{ct_framework,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,[repeat_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [repeat_SUITE,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_framework,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ],
+ %% Make sure no 'cth_error' events are received!
+ [{negative,{?eh,cth_error,'_'},E} || E <- Events];
+
+test_events(config_clash) ->
+ %% skip_cth.erl will send a 'cth_error' event if a hook is
+ %% erroneously called. Therefore, all Events are changed to
+ %% {negative,{?eh,cth_error,'_'},Event}
+ %% at the end of this function.
+ Events =
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,tc_start,{ct_framework,init_per_suite}},
+ {?eh,cth,{empty_cth,pre_init_per_suite,
+ [config_clash_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_init_per_suite,
+ [config_clash_SUITE,'$proplist','$proplist',[]]}},
+ {?eh,tc_done,{ct_framework,init_per_suite,ok}},
+ {?eh,tc_start,{config_clash_SUITE,test_case_1}},
+ {?eh,tc_done,{config_clash_SUITE,test_case_1,
+ {failed,{error,{config_name_already_in_use,[aa]}}}}},
+ {?eh,cth,{empty_cth,on_tc_fail,
+ [config_clash_SUITE,test_case_1,
+ {config_name_already_in_use,[aa]},
+ []]}},
+ {?eh,test_stats,{0,1,{0,0}}},
+ {?eh,tc_start,{ct_framework,end_per_suite}},
+ {?eh,cth,{empty_cth,pre_end_per_suite,
+ [config_clash_SUITE,'$proplist',[]]}},
+ {?eh,cth,{empty_cth,post_end_per_suite,
+ [config_clash_SUITE,'$proplist',ok,[]]}},
+ {?eh,tc_done,{ct_framework,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ],
+ %% Make sure no 'cth_error' events are received!
+ [{negative,{?eh,cth_error,'_'},E} || E <- Events];
+
test_events(ok) ->
ok.
-
%% test events help functions
contains(List) ->
fun(Proplist) when is_list(Proplist) ->
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_hook_callbacks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_hook_callbacks_SUITE.erl
new file mode 100644
index 0000000000..af8a85cd75
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_hook_callbacks_SUITE.erl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(all_hook_callbacks_SUITE).
+
+-suite_defaults([{timetrap, {minutes, 10}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+%% Test server callback functions
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(Config) ->
+ Config.
+
+end_per_group(_Config) ->
+ ok.
+
+init_per_testcase(skip_case, Config) ->
+ {skip,"Skipped in init_per_testcase/2"};
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [{group,test_group},test_case,skip_case].
+
+groups() ->
+ [{test_group,[test_case]}].
+
+%% Test cases starts here.
+test_case(Config) ->
+ ok.
+
+skip_case(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/config_clash_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/config_clash_SUITE.erl
new file mode 100644
index 0000000000..3853dc29da
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/config_clash_SUITE.erl
@@ -0,0 +1,43 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(config_clash_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ [{require,aa,yy},{default_config,yy,"this is a default value"}].
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [test_case_1].
+
+%% Test cases starts here.
+test_case_1() ->
+ [{require,aa,xx}].
+test_case_1(_Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_end_config_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_end_config_SUITE.erl
new file mode 100644
index 0000000000..0b6cabead3
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_end_config_SUITE.erl
@@ -0,0 +1,51 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_no_end_config_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+%%% This suite is used to verify that all pre/post_end_per_* callbacks
+%%% are called with correct SuiteName even if no end_per_* config
+%%% function exist in the suite, and that the non-exported config
+%%% functions fail with 'undef'.
+
+init_per_suite(Config) ->
+ Config.
+
+init_per_group(_Group,Config) ->
+ Config.
+
+init_per_testcase(_TC,Config) ->
+ Config.
+
+all() ->
+ [test_case_1, {group,test_group}].
+
+groups() ->
+ [{test_group,[],[test_case_2]}].
+
+test_case_1(Config) ->
+ ok.
+
+test_case_2(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_config_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_config_SUITE.erl
new file mode 100644
index 0000000000..29cdc21ee4
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_config_SUITE.erl
@@ -0,0 +1,54 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_no_init_config_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+%%% This suite is used to verify that all
+%%% pre/post_init_per_group/testcase callbacks are called with correct
+%%% SuiteName even if no init_per_group/testcase function exist in the
+%%% suite, and that the non-exported config functions fail with 'undef'.
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ Config.
+
+end_per_group(_Group,Config) ->
+ Config.
+
+end_per_testcase(_TC,Config) ->
+ Config.
+
+all() ->
+ [test_case_1, {group,test_group}].
+
+groups() ->
+ [{test_group,[],[test_case_2]}].
+
+test_case_1(Config) ->
+ ok.
+
+test_case_2(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_suite_config_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_suite_config_SUITE.erl
new file mode 100644
index 0000000000..d6daff9792
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_no_init_suite_config_SUITE.erl
@@ -0,0 +1,39 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_no_init_suite_config_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+%%% This suite is used to verify that pre/post_init_per_suite
+%%% callbacks are called with correct SuiteName even if no
+%%% init_per_suite function exist in the suite, and that the
+%%% non-exported config function fails with 'undef'.
+
+end_per_suite(Config) ->
+ Config.
+
+all() ->
+ [test_case].
+
+test_case(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
index c00eb5cf93..961ea68d2d 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,18 +44,18 @@
-export([pre_end_per_suite/3]).
-export([post_end_per_suite/4]).
--export([pre_init_per_group/3]).
--export([post_init_per_group/4]).
--export([pre_end_per_group/3]).
--export([post_end_per_group/4]).
+-export([pre_init_per_group/4]).
+-export([post_init_per_group/5]).
+-export([pre_end_per_group/4]).
+-export([post_end_per_group/5]).
--export([pre_init_per_testcase/3]).
--export([post_init_per_testcase/4]).
--export([pre_end_per_testcase/3]).
--export([post_end_per_testcase/4]).
+-export([pre_init_per_testcase/4]).
+-export([post_init_per_testcase/5]).
+-export([pre_end_per_testcase/4]).
+-export([post_end_per_testcase/5]).
--export([on_tc_fail/3]).
--export([on_tc_skip/3]).
+-export([on_tc_fail/4]).
+-export([on_tc_skip/4]).
-export([terminate/1]).
@@ -154,150 +154,160 @@ post_end_per_suite(Suite,Config,Return,State) ->
%% @doc Called before each init_per_group.
%% You can change the config in this function.
--spec pre_init_per_group(Group :: atom(),
- Config :: config(),
- State :: #state{}) ->
+-spec pre_init_per_group(Suite :: atom(),
+ Group :: atom(),
+ Config :: config(),
+ State :: #state{}) ->
{config() | skip_or_fail(), NewState :: #state{}}.
-pre_init_per_group(Group,Config,State) ->
+pre_init_per_group(Suite,Group,Config,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, pre_init_per_group,
- [Group,Config,State]}}),
- ct:log("~w:pre_init_per_group(~w) called", [?MODULE,Group]),
+ [Suite,Group,Config,State]}}),
+ ct:log("~w:pre_init_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Config, State}.
%% @doc Called after each init_per_group.
%% You can change the return value in this function.
--spec post_init_per_group(Group :: atom(),
+-spec post_init_per_group(Suite :: atom(),
+ Group :: atom(),
Config :: config(),
Return :: config() | skip_or_fail(),
State :: #state{}) ->
{config() | skip_or_fail(), NewState :: #state{}}.
-post_init_per_group(Group,Config,Return,State) ->
+post_init_per_group(Suite,Group,Config,Return,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, post_init_per_group,
- [Group,Config,Return,State]}}),
- ct:log("~w:post_init_per_group(~w) called", [?MODULE,Group]),
+ [Suite,Group,Config,Return,State]}}),
+ ct:log("~w:post_init_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Return, State}.
%% @doc Called after each end_per_group. The config/state can be changed here,
%% though it will only affect the *end_per_group functions.
--spec pre_end_per_group(Group :: atom(),
+-spec pre_end_per_group(Suite :: atom(),
+ Group :: atom(),
Config :: config() | skip_or_fail(),
State :: #state{}) ->
{ok | skip_or_fail(), NewState :: #state{}}.
-pre_end_per_group(Group,Config,State) ->
+pre_end_per_group(Suite,Group,Config,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, pre_end_per_group,
- [Group,Config,State]}}),
- ct:log("~w:pre_end_per_group(~w) called", [?MODULE,Group]),
+ [Suite,Group,Config,State]}}),
+ ct:log("~w:pre_end_per_group(~w~w) called", [?MODULE,Suite,Group]),
{Config, State}.
%% @doc Called after each end_per_group. Note that the config cannot be
%% changed here, only the status of the group.
--spec post_end_per_group(Group :: atom(),
+-spec post_end_per_group(Suite :: atom(),
+ Group :: atom(),
Config :: config(),
Return :: term(),
State :: #state{}) ->
{ok | skip_or_fail(), NewState :: #state{}}.
-post_end_per_group(Group,Config,Return,State) ->
+post_end_per_group(Suite,Group,Config,Return,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, post_end_per_group,
- [Group,Config,Return,State]}}),
- ct:log("~w:post_end_per_group(~w) called", [?MODULE,Group]),
+ [Suite,Group,Config,Return,State]}}),
+ ct:log("~w:post_end_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Return, State}.
%% @doc Called before init_per_testcase/2 for each test case.
%% You can change the config in this function.
--spec pre_init_per_testcase(TC :: atom(),
- Config :: config(),
- State :: #state{}) ->
+-spec pre_init_per_testcase(Suite :: atom(),
+ TC :: atom(),
+ Config :: config(),
+ State :: #state{}) ->
{config() | skip_or_fail(), NewState :: #state{}}.
-pre_init_per_testcase(TC,Config,State) ->
+pre_init_per_testcase(Suite,TC,Config,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, pre_init_per_testcase,
- [TC,Config,State]}}),
- ct:log("~w:pre_init_per_testcase(~w) called", [?MODULE,TC]),
+ [Suite,TC,Config,State]}}),
+ ct:log("~w:pre_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Config, State}.
%% @doc Called after init_per_testcase/2, and before the test case.
--spec post_init_per_testcase(TC :: atom(),
+-spec post_init_per_testcase(Suite :: atom(),
+ TC :: atom(),
Config :: config(),
Return :: config() | skip_or_fail(),
State :: #state{}) ->
{config() | skip_or_fail(), NewState :: #state{}}.
-post_init_per_testcase(TC,Config,Return,State) ->
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, post_init_per_testcase,
- [TC,Config,Return,State]}}),
- ct:log("~w:post_init_per_testcase(~w) called", [?MODULE,TC]),
+ [Suite,TC,Config,Return,State]}}),
+ ct:log("~w:post_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Return, State}.
%% @doc Called before end_per_testacse/2. No skip or fail allowed here,
%% only config additions.
--spec pre_end_per_testcase(TC :: atom(),
- Config :: config(),
- State :: #state{}) ->
+-spec pre_end_per_testcase(Suite :: atom(),
+ TC :: atom(),
+ Config :: config(),
+ State :: #state{}) ->
{config(), NewState :: #state{}}.
-pre_end_per_testcase(TC,Config,State) ->
+pre_end_per_testcase(Suite,TC,Config,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, pre_end_per_testcase,
- [TC,Config,State]}}),
- ct:log("~w:pre_end_per_testcase(~w) called", [?MODULE,TC]),
+ [Suite,TC,Config,State]}}),
+ ct:log("~w:pre_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Config, State}.
%% @doc Called after end_per_testcase/2 for each test case. Note that
%% the config cannot be changed here, only the status of the test case.
--spec post_end_per_testcase(TC :: atom(),
+-spec post_end_per_testcase(Suite :: atom(),
+ TC :: atom(),
Config :: config(),
Return :: term(),
State :: #state{}) ->
{ok | skip_or_fail(), NewState :: #state{}}.
-post_end_per_testcase(TC,Config,Return,State) ->
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, post_end_per_testcase,
- [TC,Config,Return,State]}}),
- ct:log("~w:post_end_per_testcase(~w) called", [?MODULE,TC]),
+ [Suite,TC,Config,Return,State]}}),
+ ct:log("~w:post_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Return, State}.
%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_tc if the suite, group or test case failed.
%% This function should be used for extra cleanup which might be needed.
%% It is not possible to modify the config or the status of the test run.
--spec on_tc_fail(TC :: init_per_suite | end_per_suite |
+-spec on_tc_fail(Suite :: atom(),
+ TC :: init_per_suite | end_per_suite |
init_per_group | end_per_group | atom() |
{Function :: atom(), GroupName :: atom()},
Reason :: term(), State :: #state{}) -> NewState :: #state{}.
-on_tc_fail(TC, Reason, State) ->
+on_tc_fail(Suite, TC, Reason, State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, on_tc_fail,
- [TC,Reason,State]}}),
- ct:log("~w:on_tc_fail(~w) called", [?MODULE,TC]),
+ [Suite,TC,Reason,State]}}),
+ ct:log("~w:on_tc_fail(~w,~w) called", [?MODULE,Suite,TC]),
State.
%% @doc Called when a test case is skipped by either user action
%% or due to an init function failing. Test case can be
%% end_per_suite, init_per_group, end_per_group and the actual test cases.
--spec on_tc_skip(TC :: end_per_suite |
+-spec on_tc_skip(Suite :: atom(),
+ TC :: end_per_suite |
init_per_group | end_per_group | atom() |
{Function :: atom(), GroupName :: atom()},
{tc_auto_skip, {failed, {Mod :: atom(), Function :: atom(), Reason :: term()}}} |
{tc_user_skip, {skipped, Reason :: term()}},
State :: #state{}) -> NewState :: #state{}.
-on_tc_skip(TC, Reason, State) ->
+on_tc_skip(Suite, TC, Reason, State) ->
gen_event:notify(
?CT_EVMGR_REF, #event{ name = cth, node = node(),
data = {?MODULE, on_tc_skip,
- [TC,Reason,State]}}),
- ct:log("~w:on_tc_skip(~w) called", [?MODULE,TC]),
+ [Suite,TC,Reason,State]}}),
+ ct:log("~w:on_tc_skip(~w,~w) called", [?MODULE,Suite,TC]),
State.
%% @doc Called when the scope of the CTH is done, this depends on
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_suite_cth.erl
index 559b22bc9f..7cb2d19414 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_suite_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_post_suite_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,29 +45,29 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl
index 51202443bf..ebe6014127 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,35 +45,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fallback_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fallback_cth.erl
new file mode 100644
index 0000000000..665efd659a
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fallback_cth.erl
@@ -0,0 +1,81 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(fallback_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+
+%% CT Hooks
+-compile(export_all).
+
+id(Opts) ->
+ empty_cth:id(Opts).
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts).
+
+pre_init_per_suite(Suite, Config, State) ->
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Group,Config,State) ->
+ empty_cth:pre_init_per_group(fallback_nosuite,Group,Config,State).
+
+post_init_per_group(Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(fallback_nosuite,Group,Config,Return,State).
+
+pre_end_per_group(Group,Config,State) ->
+ empty_cth:pre_end_per_group(fallback_nosuite,Group,Config,State).
+
+post_end_per_group(Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(fallback_nosuite,Group,Config,Return,State).
+
+pre_init_per_testcase(TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(fallback_nosuite,TC,Config,State).
+
+post_init_per_testcase(TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(fallback_nosuite,TC,Config,Return,State).
+
+pre_end_per_testcase(TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(fallback_nosuite,TC,Config,State).
+
+post_end_per_testcase(TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(fallback_nosuite,TC,Config,Return,State).
+
+on_tc_fail(TC, Reason, State) ->
+ empty_cth:on_tc_fail(fallback_nosuite,TC,Reason,State).
+
+on_tc_skip(TC, Reason, State) ->
+ empty_cth:on_tc_skip(fallback_nosuite,TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl
index b49cbe7fb4..f5d215c69d 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,13 +29,13 @@
%% CT Hooks
-export([init/2]).
-export([terminate/1]).
--export([on_tc_skip/3]).
+-export([on_tc_skip/4]).
init(Id, Opts) ->
empty_cth:init(Id, Opts).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite, TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl
index a687743641..d462e5e071 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,35 +47,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl
index 4d9c60f1ca..f67d152cf1 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,35 +47,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/repeat_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/repeat_SUITE.erl
new file mode 100644
index 0000000000..a1849839c9
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/repeat_SUITE.erl
@@ -0,0 +1,42 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(repeat_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [test_case_1, test_case_2].
+
+%% Test cases starts here.
+test_case_1(_Config) ->
+ timer:sleep(10000),
+ ok.
+
+test_case_2(_Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl
index 494f398fc1..a4105f5829 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,35 +48,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/seq_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/seq_SUITE.erl
new file mode 100644
index 0000000000..30eebb272a
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/seq_SUITE.erl
@@ -0,0 +1,45 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(seq_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [{sequence,seq1}].
+
+sequences() ->
+ [{seq1,[test_case_1,test_case_2]}].
+
+%% Test cases starts here.
+test_case_1(_Config) ->
+ exit(failed_on_purpose).
+
+test_case_2(_Config) ->
+ ct:fail("This test shall never be run since test_case_1 fails "
+ "and they are run in sequence").
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip.spec b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip.spec
new file mode 100644
index 0000000000..a271c5e8b2
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip.spec
@@ -0,0 +1,8 @@
+{suites,".",[all_hook_callbacks_SUITE,
+ skip_init_SUITE,
+ skip_req_SUITE,
+ skip_fail_SUITE,
+ skip_group_SUITE,
+ skip_case_SUITE]}.
+{skip_suites,".",all_hook_callbacks_SUITE,"Skipped in spec"}.
+{skip_cases,".",skip_case_SUITE,skip_in_spec,"Skipped in spec"}.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_case_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_case_SUITE.erl
new file mode 100644
index 0000000000..3c2275d55f
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_case_SUITE.erl
@@ -0,0 +1,106 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(skip_case_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ ok.
+
+init_per_group(_,Config) ->
+ Config.
+
+end_per_group(_,_) ->
+ ok.
+
+init_per_testcase(skip_in_init,Config) ->
+ {skip,"Skipped in init_per_testcase/2"};
+init_per_testcase(fail_in_init,Config) ->
+ ct:fail("Failed in init_per_testcase/2");
+init_per_testcase(exit_in_init,Config) ->
+ exit(self(),"Exit in init_per_testcase/2");
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(fail_in_end,_) ->
+ ct:fail("Failed in end_per_testcase/2");
+end_per_testcase(exit_in_end,_) ->
+ exit(self(),"Exit in end_per_testcase/2");
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [skip_in_spec,
+ skip_in_init,
+ fail_in_init,
+ exit_in_init,
+ fail_in_end,
+ exit_in_end,
+ skip_in_case,
+ req_auto_skip,
+ fail_auto_skip
+ ].
+
+%% Test cases starts here.
+skip_in_spec(Config) ->
+ ct:fail("This test shall never be run. "
+ "It shall be skipped in the test spec.").
+
+skip_in_init(Config) ->
+ ct:fail("This test shall never be run. "
+ "It shall be skipped in init_per_testcase/2.").
+
+fail_in_init(Config) ->
+ ct:fail("This test shall never be run. "
+ "It shall fail in init_per_testcase/2.").
+
+exit_in_init(Config) ->
+ ct:fail("This test shall never be run. "
+ "It shall exit in init_per_testcase/2.").
+
+fail_in_end(Config) ->
+ ok.
+
+exit_in_end(Config) ->
+ ok.
+
+skip_in_case(Config) ->
+ {skip,"Skipped in test case function"}.
+
+req_auto_skip() ->
+ [{require,whatever}].
+req_auto_skip(Config) ->
+ ct:fail("This test shall never be run due to "
+ "failed require").
+
+fail_auto_skip() ->
+ faulty_return_value.
+fail_auto_skip(Config) ->
+ ct:fail("This test shall never be run due to "
+ "faulty return from info function").
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_cth.erl
new file mode 100644
index 0000000000..7b5e93f836
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_cth.erl
@@ -0,0 +1,182 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(skip_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+%% Send a cth_error event if a callback is called with unexpected arguments
+-define(fail(Info),
+ gen_event:notify(
+ ?CT_EVMGR_REF,
+ #event{ name = cth_error,
+ node = node(),
+ data = {illegal_hook_callback,{?MODULE,?FUNCTION_NAME,Info}}})).
+
+%% CT Hooks
+-compile(export_all).
+
+id(Opts) ->
+ empty_cth:id(Opts).
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts).
+
+pre_init_per_suite(Suite, Config, State) ->
+ Suite==skip_init_SUITE
+ orelse Suite==skip_group_SUITE
+ orelse Suite==skip_case_SUITE
+ orelse Suite==seq_SUITE
+ orelse Suite==repeat_SUITE
+ orelse Suite==config_clash_SUITE
+ orelse ?fail(Suite),
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ Suite==skip_init_SUITE
+ orelse Suite==skip_group_SUITE
+ orelse Suite==skip_case_SUITE
+ orelse Suite==seq_SUITE
+ orelse Suite==repeat_SUITE
+ orelse Suite==config_clash_SUITE
+ orelse ?fail(Suite),
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ Suite==skip_case_SUITE
+ orelse Suite==skip_group_SUITE
+ orelse Suite==seq_SUITE
+ orelse Suite==repeat_SUITE
+ orelse Suite==config_clash_SUITE
+ orelse ?fail(Suite),
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ Suite==skip_case_SUITE
+ orelse Suite==skip_group_SUITE
+ orelse Suite==seq_SUITE
+ orelse Suite==repeat_SUITE
+ orelse Suite==config_clash_SUITE
+ orelse ?fail(Suite),
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Suite,Group,Config,State) ->
+ (Suite==skip_group_SUITE andalso Group==test_group_3)
+ orelse ?fail({Suite,Group}),
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
+
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ (Suite==skip_group_SUITE andalso Group==test_group_3)
+ orelse ?fail({Suite,Group}),
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
+
+pre_end_per_group(Suite,Group,Config,State) ->
+ ?fail({Suite,Group}),
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
+
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ ?fail({Suite,Group}),
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
+
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ (Suite==skip_case_SUITE andalso (TC==skip_in_init
+ orelse TC==fail_in_init
+ orelse TC==exit_in_init
+ orelse TC==fail_in_end
+ orelse TC==exit_in_end
+ orelse TC==skip_in_case))
+ orelse (Suite==seq_SUITE andalso TC==test_case_1)
+ orelse (Suite==repeat_SUITE andalso TC==test_case_1)
+ orelse ?fail({Suite,TC}),
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
+
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ (Suite==skip_case_SUITE andalso (TC==skip_in_init
+ orelse TC==fail_in_init
+ orelse TC==exit_in_init
+ orelse TC==fail_in_end
+ orelse TC==exit_in_end
+ orelse TC==skip_in_case))
+ orelse (Suite==seq_SUITE andalso TC==test_case_1)
+ orelse (Suite==repeat_SUITE andalso TC==test_case_1)
+ orelse ?fail({Suite,TC}),
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
+
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ (Suite==skip_case_SUITE andalso (TC==skip_in_case
+ orelse TC==fail_in_end
+ orelse TC==exit_in_end))
+ orelse (Suite==seq_SUITE andalso TC==test_case_1)
+ orelse (Suite==repeat_SUITE andalso TC==test_case_1)
+ orelse ?fail({Suite,TC}),
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
+
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ (Suite==skip_case_SUITE andalso (TC==skip_in_case
+ orelse TC==fail_in_end
+ orelse TC==exit_in_end))
+ orelse (Suite==seq_SUITE andalso TC==test_case_1)
+ orelse (Suite==repeat_SUITE andalso TC==test_case_1)
+ orelse ?fail({Suite,TC}),
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
+
+on_tc_fail(Suite,TC,Reason,State) ->
+ (Suite==seq_SUITE andalso TC==test_case_1)
+ orelse (Suite==config_clash_SUITE andalso TC==test_case_1)
+ orelse ?fail({Suite,TC}),
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
+
+on_tc_skip(all_hook_callbacks_SUITE=Suite,all=TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State);
+on_tc_skip(Suite,TC,Reason,State)
+ when (Suite==skip_init_SUITE
+ orelse Suite==skip_req_SUITE
+ orelse Suite==skip_fail_SUITE)
+ andalso
+ (TC==init_per_suite
+ orelse TC==test_case
+ orelse TC==end_per_suite) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State);
+on_tc_skip(skip_group_SUITE=Suite,TC={C,G},Reason,State)
+ when (C==init_per_group orelse C==test_case orelse C==end_per_group) andalso
+ (G==test_group_1 orelse G==test_group_2 orelse G==test_group_3) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State);
+on_tc_skip(skip_case_SUITE=Suite,TC,Reason,State)
+ when TC==skip_in_spec;
+ TC==skip_in_init;
+ TC==fail_in_init;
+ TC==exit_in_init;
+ TC==skip_in_case;
+ TC==req_auto_skip;
+ TC==fail_auto_skip ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State);
+on_tc_skip(Suite,TC,Reason,State)
+ when (Suite==seq_SUITE andalso TC==test_case_2)
+ orelse (Suite==repeat_SUITE andalso TC==test_case_2) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State);
+on_tc_skip(Suite,TC,Reason,State) ->
+ ?fail({Suite,TC}),
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_fail_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_fail_SUITE.erl
new file mode 100644
index 0000000000..df8835598e
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_fail_SUITE.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(skip_fail_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ faulty_return_value.
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ ok.
+
+init_per_group(_,Config) ->
+ Config.
+
+end_per_group(_,_) ->
+ ok.
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [test_case].
+
+%% Test cases starts here.
+test_case(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_group_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_group_SUITE.erl
new file mode 100644
index 0000000000..8d25701a22
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_group_SUITE.erl
@@ -0,0 +1,64 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(skip_group_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ ok.
+
+group(test_group_1) ->
+ [{require,whatever}];
+group(test_group_2) ->
+ faulty_return_value;
+group(_) ->
+ [].
+
+init_per_group(test_group_3,Config) ->
+ {skip,"Skipped in init_per_group/2"};
+init_per_group(_,Config) ->
+ ct:fail("This shall never be run due to auto_skip from group/1").
+
+end_per_group(_,_) ->
+ ct:fail("This shall never be run").
+
+all() ->
+ [{group,test_group_1},
+ {group,test_group_2},
+ {group,test_group_3}].
+
+groups() ->
+ [{test_group_1,[test_case]},
+ {test_group_2,[test_case]},
+ {test_group_3,[test_case]}].
+
+%% Test cases starts here.
+test_case(_Config) ->
+ ct:fail("This test case shall never be run due to skip on group level").
+
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_init_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_init_SUITE.erl
new file mode 100644
index 0000000000..7d01ff58a9
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_init_SUITE.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(skip_init_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ [].
+
+init_per_suite(Config) ->
+ {skip,"Skipped in init_per_suite/1"}.
+
+end_per_suite(Config) ->
+ ok.
+
+init_per_group(_,Config) ->
+ Config.
+
+end_per_group(_,_) ->
+ ok.
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [test_case].
+
+%% Test cases starts here.
+test_case(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl
index d5b347e723..b3b5db23fb 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,35 +45,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl
index 36abac0bf8..525c376830 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,36 +46,36 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State),
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State),
{{skip, "Test skip"}, State}.
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_init_tc_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_init_tc_cth.erl
new file mode 100644
index 0000000000..459608ac07
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_init_tc_cth.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(skip_pre_init_tc_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+
+%% CT Hooks
+-compile(export_all).
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts).
+
+pre_init_per_suite(Suite, Config, State) ->
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
+
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
+
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
+
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
+
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State),
+ {{skip, "Skipped in pre_init_per_testcase"}, State}.
+
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
+
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
+
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
+
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
+
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl
index fa510b2d54..1e6cab04ed 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,35 +46,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_req_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_req_SUITE.erl
new file mode 100644
index 0000000000..c6e67d978e
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_req_SUITE.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(skip_req_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ [{require,whatever}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ ok.
+
+init_per_group(_,Config) ->
+ Config.
+
+end_per_group(_,_) ->
+ ok.
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [test_case].
+
+%% Test cases starts here.
+test_case(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl
index 7ec0d458b6..2b37116cb2 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,44 +48,44 @@ post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State),
{Return, [post_end_per_suite|State]}.
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State),
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State),
{Config, [pre_init_per_group|State]}.
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State),
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State),
{Return, [post_init_per_group|State]}.
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State),
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State),
{Config, [pre_end_per_group|State]}.
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State),
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State),
{Return, [post_end_per_group|State]}.
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State),
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State),
{Config, [pre_init_per_testcase|State]}.
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State),
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State),
{Return, [post_init_per_testcase|State]}.
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State),
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State),
{Config, [pre_end_per_testcase|State]}.
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State),
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State),
{Return, [post_end_per_testcase|State]}.
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State),
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State),
[on_tc_fail|State].
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State),
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State),
[on_tc_skip|State].
terminate(State) ->
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl
index 2b9e726819..ac7b74539a 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,35 +44,35 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl
index d48981f667..7b0c1f599f 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,43 +50,43 @@ post_end_per_suite(Suite,Config,Return,State) ->
NewConfig = [{post_end_per_suite,?now}|Config],
{NewConfig,NewConfig}.
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State),
+pre_init_per_group(Suite, Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State),
{[{pre_init_per_group,?now}|Config],State}.
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State),
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State),
{[{post_init_per_group,?now}|Return],State}.
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State),
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State),
{[{pre_end_per_group,?now}|Config],State}.
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State),
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State),
{[{post_end_per_group,?now}|Config],State}.
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State),
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State),
{[{pre_init_per_testcase,?now}|Config],State}.
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State),
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State),
{[{post_init_per_testcase,?now}|Config],State}.
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State),
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State),
{[{pre_end_per_testcase,?now}|Config],State}.
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State),
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State),
{[{post_end_per_testcase,?now}|Config],State}.
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl
index 71d84781e0..44e7c7c29d 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -60,37 +60,37 @@ post_end_per_suite(Suite,Config,Return,State) ->
ct_no_config_SUITE = ct:get_config(suite_cfg),
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
+pre_init_per_group(Suite,Group,Config,State) ->
true = ?val(post_init_per_suite, Config),
ct_no_config_SUITE = ct:get_config(suite_cfg),
test_group = ct:get_config(group_cfg),
- empty_cth:pre_init_per_group(Group,
+ empty_cth:pre_init_per_group(Suite,Group,
[{pre_init_per_group,true} | Config],
State).
-post_init_per_group(Group,Config,Return,State) ->
+post_init_per_group(Suite,Group,Config,Return,State) ->
true = ?val(pre_init_per_group, Return),
test_group = ct:get_config(group_cfg),
- empty_cth:post_init_per_group(Group,
+ empty_cth:post_init_per_group(Suite,Group,
Config,
[{post_init_per_group,true} | Return],
State).
-pre_end_per_group(Group,Config,State) ->
+pre_end_per_group(Suite,Group,Config,State) ->
true = ?val(post_init_per_group, Config),
ct_no_config_SUITE = ct:get_config(suite_cfg),
test_group = ct:get_config(group_cfg),
- empty_cth:pre_end_per_group(Group,
+ empty_cth:pre_end_per_group(Suite,Group,
[{pre_end_per_group,true} | Config],
State).
-post_end_per_group(Group,Config,Return,State) ->
+post_end_per_group(Suite,Group,Config,Return,State) ->
true = ?val(pre_end_per_group, Config),
ct_no_config_SUITE = ct:get_config(suite_cfg),
test_group = ct:get_config(group_cfg),
- empty_cth:post_end_per_group(Group,Config,Return,State).
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
+pre_init_per_testcase(Suite,TC,Config,State) ->
true = ?val(post_init_per_suite, Config),
case ?val(name, ?val(tc_group_properties, Config)) of
undefined ->
@@ -102,19 +102,19 @@ pre_init_per_testcase(TC,Config,State) ->
ct_no_config_SUITE = ct:get_config(suite_cfg),
CfgKey = list_to_atom(atom_to_list(TC) ++ "_cfg"),
TC = ct:get_config(CfgKey),
- empty_cth:pre_init_per_testcase(TC,
+ empty_cth:pre_init_per_testcase(Suite,TC,
[{pre_init_per_testcase,true} | Config],
State).
%%! TODO: Verify Config also in post_init and pre_end!
-post_init_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
- empty_cth:pre_end_per_testcase(TC,Config,State).
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
true = ?val(post_init_per_suite, Config),
true = ?val(pre_init_per_testcase, Config),
case ?val(name, ?val(tc_group_properties, Config)) of
@@ -127,13 +127,13 @@ post_end_per_testcase(TC,Config,Return,State) ->
ct_no_config_SUITE = ct:get_config(suite_cfg),
CfgKey = list_to_atom(atom_to_list(TC) ++ "_cfg"),
TC = ct:get_config(CfgKey),
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl
index 9abd2e5e83..bde6744433 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,43 +62,43 @@ post_end_per_suite(Suite,Config,Return,State) ->
check_dirs(State,Config),
empty_cth:post_end_per_suite(Suite,Config,Return,State).
-pre_init_per_group(Group,Config,State) ->
+pre_init_per_group(Suite,Group,Config,State) ->
check_dirs(State,Config),
- empty_cth:pre_init_per_group(Group,Config,State).
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
-post_init_per_group(Group,Config,Return,State) ->
+post_init_per_group(Suite,Group,Config,Return,State) ->
check_dirs(State,Return),
- empty_cth:post_init_per_group(Group,Config,Return,State).
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
-pre_end_per_group(Group,Config,State) ->
+pre_end_per_group(Suite,Group,Config,State) ->
check_dirs(State,Config),
- empty_cth:pre_end_per_group(Group,Config,State).
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
-post_end_per_group(Group,Config,Return,State) ->
+post_end_per_group(Suite,Group,Config,Return,State) ->
check_dirs(State,Config),
- empty_cth:post_end_per_group(Group,Config,Return,State).
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
-pre_init_per_testcase(TC,Config,State) ->
+pre_init_per_testcase(Suite,TC,Config,State) ->
check_dirs(State,Config),
- empty_cth:pre_init_per_testcase(TC,Config,State).
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
-post_init_per_testcase(TC,Config,Return,State) ->
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
check_dirs(State,Config),
- empty_cth:post_init_per_testcase(TC,Config,Return,State).
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
-pre_end_per_testcase(TC,Config,State) ->
+pre_end_per_testcase(Suite,TC,Config,State) ->
check_dirs(State,Config),
- empty_cth:pre_end_per_testcase(TC,Config,State).
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
-post_end_per_testcase(TC,Config,Return,State) ->
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
check_dirs(State,Config),
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
terminate(State) ->
empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl
index 9bdd44cbdf..93affda398 100644
--- a/lib/common_test/test/ct_log_SUITE.erl
+++ b/lib/common_test/test/ct_log_SUITE.erl
@@ -86,18 +86,7 @@ print(Config) ->
io:format("5. Printing a pid: ~w~n", [Pid]),
io:format("6. Printing HTML: <pre>~s</pre>~n", [String]),
- %% --- API ---
- %% pal(Format) ->
- %% = ct:pal(default, 50, Format, []).
- %% pal(X1, X2) -> ok
- %% X1 = Category | Importance | Format
- %% X2 = Format | FormatArgs
- %% pal(X1, X2, X3) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs
- %% pal(Category, Importance, Format, FormatArgs) -> ok
- %% ------
+ %% ct:pal
ct:pal("1. Printing nothing"),
ct:pal("2. Printing nothing", []),
ct:pal("3. Printing a string: ~s", [String]),
@@ -111,23 +100,16 @@ print(Config) ->
ct:pal(50, "11. Printing with ~s", ["importance"]),
ct:pal(ct_internal, 50, "12. Printing with ~s", ["category and importance"]),
- %% --- API ---
- %% log(Format) -> ok
- %% = ct:log(default, 50, Format, [], []).
- %% log(X1, X2) -> ok
- %% X1 = Category | Importance | Format
- %% X2 = Format | FormatArgs
- %% log(X1, X2, X3) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs | Opts
- %% log(X1, X2, X3, X4) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs
- %% X4 = FormatArgs | Opts
- %% log(Category, Importance, Format, FormatArgs, Opts) -> ok
- %% ------
+ ct:pal("13. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(ct_internal, "14. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(50, "15. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(ct_internal, 50, "16. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
+ %% ct:log
ct:log("1. Printing nothing"),
ct:log("2. Printing nothing", []),
ct:log("3. Printing a string: ~s", [String]),
@@ -153,8 +135,37 @@ print(Config) ->
ct:log(ct_internal, 50, "21. Printing a pid escaped with ~s, no_css: ~w",
["category and importance",Pid], [esc_chars,no_css]),
+ ct:log("22. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(ct_internal, "23. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(50, "24. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(ct_internal, 50, "25. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
%% END mark
ct:log("LOGGING END", [], [no_css]),
+
+
+ %% ct:print
+ ct:print("1. Does this show??"),
+ ct:print("2. Does this ~s", ["show??"]),
+ ct:print("3. Is this a non-html pid?? ~w", [self()]),
+ ct:print(ct_internal, "4. Printing with category"),
+ ct:print(ct_internal, "5. Printing with ~s", ["category"]),
+ ct:print(50, "6. Printing with importance"),
+ ct:print(50, "7. Printing with ~s", ["importance"]),
+ ct:print(ct_internal, 50, "8. Printing with ~s", ["category and importance"]),
+ ct:print("9. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(ct_internal, "10. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(50, "11. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(ct_internal, 50, "12. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
{save_config,[{the_logfile,TcLogFile},{the_pid,Pid},{the_string,String}]}.
@@ -169,6 +180,8 @@ verify(Config) ->
{ok,Dev} = file:open(TcLogFile, [read]),
ok = read_until(Dev, "LOGGING START\n"),
+ ct:pal("VERIFYING LOG ENTRIES...", []),
+
%% io:format
match_line(Dev, "1. Printing nothing", []),
read_nl(Dev),
@@ -182,6 +195,7 @@ verify(Config) ->
read_nl(Dev),
match_line(Dev, "6. Printing HTML: &lt;pre&gt;~s&lt;/pre&gt;", [String]),
read_nl(Dev),
+
%% ct:pal
read_header(Dev),
match_line(Dev, "1. Printing nothing", []),
@@ -219,6 +233,19 @@ verify(Config) ->
read_header(Dev, "\"ct_internal\""),
match_line(Dev, "12. Printing with ~s", ["category and importance"]),
read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "13. Printing with heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "14. Printing with category and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "15. Printing with importance and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "16. Printing with category, importance and heading", []),
+ read_footer(Dev),
+
%% ct:log
read_header(Dev),
match_line(Dev, "1. Printing nothing", []),
@@ -275,7 +302,18 @@ verify(Config) ->
read_footer(Dev),
match_line(Dev, "21. Printing a pid escaped with ~s, no_css: ~s",
["category and importance",EscPid]),
-
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "22. Printing with heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "23. Printing with category and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "24. Printing with importance and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "25. Printing with category, importance and heading", []),
+ read_footer(Dev),
file:close(Dev),
ok.
@@ -298,29 +336,51 @@ read_until(Dev, Pat) ->
match_line(Dev, Format, Args) ->
Pat = lists:flatten(io_lib:format(Format, Args)),
Line = element(2, file:read_line(Dev)),
+
+ %% for debugging purposes:
+ ct:pal("L: ~tp", [Line], [no_css]),
+
case re:run(Line, Pat) of
{match,_} ->
ok;
nomatch ->
- ct:pal("ERROR! No match for ~p.\nLine = ~p", [Pat,Line]),
+ ct:pal("ERROR! No match for ~p", [Pat]),
file:close(Dev),
ct:fail({mismatch,Pat,Line})
end.
read_header(Dev) ->
- read_header(Dev, "\"default\"").
+ read_header(Dev, "\"default\"", "User").
read_header(Dev, Cat) ->
+ read_header(Dev, Cat, "User").
+
+read_header(Dev, Cat, Heading) ->
file:read_line(Dev), % \n
"</pre>\n" = element(2, file:read_line(Dev)),
- {match,_} =
- re:run(element(2, file:read_line(Dev)), "<div class="++Cat++"><pre><b>"
- "\\*\\*\\* User \\d{4}-\\d{2}-\\d{2} "
- "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>").
+ {ok,Hd} = file:read_line(Dev),
+
+ %% for debugging purposes:
+ ct:pal("H: ~tp", [Hd], [no_css]),
+
+ Pat = "<div class="++Cat++"><pre><b>"++
+ "\\*\\*\\* "++Heading++" \\d{4}-\\d{2}-\\d{2} "++
+ "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>",
+
+ case re:run(Hd, Pat) of
+ {match,_} ->
+ ok;
+ _ ->
+ ct:pal("ERROR! No match for ~p", [Pat]),
+ file:close(Dev),
+ ct:fail({mismatch,Pat,Hd})
+ end.
read_footer(Dev) ->
"</pre></div>\n" = element(2, file:read_line(Dev)),
- "<pre>\n" = element(2, file:read_line(Dev)).
+ "<pre>\n" = element(2, file:read_line(Dev)),
+ %% for debugging purposes:
+ ct:pal("F: </pre></div><pre>", [], [no_css]).
read_nl(Dev) ->
file:read_line(Dev).
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl
index a65275da43..f2580ad8e9 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl
@@ -83,7 +83,9 @@ end_per_suite(Config) ->
%% Running the netconf server in a remote node, test that the client
%% process terminates if the remote node goes down.
remote_crash(Config) ->
- {ok,Node} = ct_slave:start(nc_remote_crash),
+ {ok,Node} = ct_slave:start(nc_remote_crash,[{boot_timeout,15},
+ {init_timeout,15},
+ {startup_timeout,15}]),
Pa = filename:dirname(code:which(?NS)),
true = rpc:call(Node,code,add_patha,[Pa]),
rpc:call(Node,code,load_file,[crypto]),
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
index e62bc617fa..2412ea6aba 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
@@ -302,10 +302,14 @@ table_trans(Fun,Args) ->
S ->
apply(Fun,Args);
Pid ->
+ Ref = erlang:monitor(process,Pid),
Pid ! {table_trans,Fun,Args,self()},
receive
{table_trans_done,Result} ->
- Result
+ erlang:demonitor(Ref,[flush]),
+ Result;
+ {'DOWN',Ref,process,Pid,Reason} ->
+ exit({main_ns_proc_died,Reason})
after 20000 ->
exit(table_trans_timeout)
end
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
index f8b6a379f6..9382e4c011 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -363,14 +363,17 @@ skip_first_tc1(Suite) ->
{?eh,tc_start,{Suite,tc1}},
{?eh,tc_done,{Suite,tc1,ok}},
{?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,tc2}},
{?eh,tc_done,{Suite,tc2,?skipped}},
{?eh,test_stats,{'_',0,{0,1}}},
+ {?eh,tc_start,{Suite,{init_per_group,g,[]}}},
{?eh,tc_done,{Suite,{init_per_group,g,[]},?skipped}},
{?eh,tc_auto_skip,{Suite,{tc1,g},?skip_reason}},
{?eh,test_stats,{'_',0,{0,2}}},
{?eh,tc_auto_skip,{Suite,{tc2,g},?skip_reason}},
{?eh,test_stats,{'_',0,{0,3}}},
{?eh,tc_auto_skip,{Suite,{end_per_group,g},?skip_reason}},
+ {?eh,tc_start,{Suite,tc2}},
{?eh,tc_done,{Suite,tc2,?skipped}},
{?eh,test_stats,{'_',0,{0,4}}},
{?eh,tc_start,{Suite,end_per_suite}},
@@ -390,10 +393,12 @@ skip_tc1_in_group(Suite) ->
{?eh,tc_start,{Suite,tc1}},
{?eh,tc_done,{Suite,tc1,ok}},
{?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,tc2}},
{?eh,tc_done,{Suite,tc2,?skipped}},
{?eh,test_stats,{'_',0,{0,1}}},
{?eh,tc_start,{Suite,{end_per_group,g,[]}}},
{?eh,tc_done,{Suite,{end_per_group,g,[]},ok}}],
+ {?eh,tc_start,{Suite,tc2}},
{?eh,tc_done,{Suite,tc2,?skipped}},
{?eh,test_stats,{'_',0,{0,2}}},
{?eh,tc_start,{Suite,end_per_suite}},
diff --git a/lib/common_test/test/ct_surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE.erl
index 42ec685c16..832e105517 100644
--- a/lib/common_test/test/ct_surefire_SUITE.erl
+++ b/lib/common_test/test/ct_surefire_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -73,7 +73,9 @@ all() ->
relative_path,
url,
logdir,
- fail_pre_init_per_suite
+ fail_pre_init_per_suite,
+ skip_case_in_spec,
+ skip_suite_in_spec
].
%%--------------------------------------------------------------------
@@ -119,6 +121,18 @@ fail_pre_init_per_suite(Config) when is_list(Config) ->
run(fail_pre_init_per_suite,[fail_pre_init_per_suite,
{cth_surefire,[{path,Path}]}],Path,Config,[],Suites).
+skip_case_in_spec(Config) ->
+ DataDir = ?config(data_dir,Config),
+ Spec = filename:join(DataDir,"skip_one_case.spec"),
+ Path = "skip_case_in_spec.xml",
+ run_spec(skip_case_in_spec,[{cth_surefire,[{path,Path}]}],Path,Config,Spec).
+
+skip_suite_in_spec(Config) ->
+ DataDir = ?config(data_dir,Config),
+ Spec = filename:join(DataDir,"skip_one_suite.spec"),
+ Path = "skip_suite_in_spec.xml",
+ run_spec(skip_suite_in_spec,[{cth_surefire,[{path,Path}]}],Path,Config,Spec).
+
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
@@ -129,8 +143,15 @@ run(Case,CTHs,Report,Config,ExtraOpts) ->
Suite = filename:join(DataDir, "surefire_SUITE"),
run(Case,CTHs,Report,Config,ExtraOpts,Suite).
run(Case,CTHs,Report,Config,ExtraOpts,Suite) ->
- {Opts,ERPid} = setup([{suite,Suite},{ct_hooks,CTHs},{label,Case}|ExtraOpts],
- Config),
+ Test = [{suite,Suite},{ct_hooks,CTHs},{label,Case}|ExtraOpts],
+ do_run(Case, Report, Test, Config).
+
+run_spec(Case,CTHs,Report,Config,Spec) ->
+ Test = [{spec,Spec},{ct_hooks,CTHs},{label,Case}],
+ do_run(Case, Report, Test, Config).
+
+do_run(Case, Report, Test, Config) ->
+ {Opts,ERPid} = setup(Test, Config),
ok = execute(Case, Opts, ERPid, Config),
LogDir =
case lists:keyfind(logdir,1,Opts) of
@@ -201,7 +222,10 @@ test_suite_events(pass_SUITE) ->
{?eh,test_stats,{1,0,{0,0}}},
{?eh,tc_start,{ct_framework,end_per_suite}},
{?eh,tc_done,{ct_framework,end_per_suite,ok}}];
-test_suite_events(_) ->
+test_suite_events(skip_all_surefire_SUITE) ->
+ [{?eh,tc_user_skip,{skip_all_surefire_SUITE,all,"skipped in spec"}},
+ {?eh,test_stats,{0,0,{1,0}}}];
+test_suite_events(Test) ->
[{?eh,tc_start,{surefire_SUITE,init_per_suite}},
{?eh,tc_done,{surefire_SUITE,init_per_suite,ok}},
{?eh,tc_start,{surefire_SUITE,tc_ok}},
@@ -210,46 +234,55 @@ test_suite_events(_) ->
{?eh,tc_start,{surefire_SUITE,tc_fail}},
{?eh,tc_done,{surefire_SUITE,tc_fail,
{failed,{error,{test_case_failed,"this test should fail"}}}}},
- {?eh,test_stats,{1,1,{0,0}}},
- {?eh,tc_start,{surefire_SUITE,tc_skip}},
- {?eh,tc_done,{surefire_SUITE,tc_skip,{skipped,"this test is skipped"}}},
- {?eh,test_stats,{1,1,{1,0}}},
- {?eh,tc_start,{surefire_SUITE,tc_autoskip_require}},
- {?eh,tc_done,{surefire_SUITE,tc_autoskip_require,
- {auto_skipped,{require_failed,'_'}}}},
- {?eh,test_stats,{1,1,{1,1}}},
- [{?eh,tc_start,{surefire_SUITE,{init_per_group,g,[]}}},
- {?eh,tc_done,{surefire_SUITE,{init_per_group,g,[]},ok}},
- {?eh,tc_start,{surefire_SUITE,tc_ok}},
- {?eh,tc_done,{surefire_SUITE,tc_ok,ok}},
- {?eh,test_stats,{2,1,{1,1}}},
- {?eh,tc_start,{surefire_SUITE,tc_fail}},
- {?eh,tc_done,{surefire_SUITE,tc_fail,
- {failed,{error,{test_case_failed,"this test should fail"}}}}},
- {?eh,test_stats,{2,2,{1,1}}},
- {?eh,tc_start,{surefire_SUITE,tc_skip}},
- {?eh,tc_done,{surefire_SUITE,tc_skip,{skipped,"this test is skipped"}}},
- {?eh,test_stats,{2,2,{2,1}}},
- {?eh,tc_start,{surefire_SUITE,tc_autoskip_require}},
- {?eh,tc_done,{surefire_SUITE,tc_autoskip_require,
- {auto_skipped,{require_failed,'_'}}}},
- {?eh,test_stats,{2,2,{2,2}}},
- {?eh,tc_start,{surefire_SUITE,{end_per_group,g,[]}}},
- {?eh,tc_done,{surefire_SUITE,{end_per_group,g,[]},ok}}],
- [{?eh,tc_start,{surefire_SUITE,{init_per_group,g_fail,[]}}},
- {?eh,tc_done,{surefire_SUITE,{init_per_group,g_fail,[]},
- {failed,{error,all_cases_should_be_skipped}}}},
- {?eh,tc_auto_skip,{surefire_SUITE,{tc_ok,g_fail},
- {failed,
- {surefire_SUITE,init_per_group,
- {'EXIT',all_cases_should_be_skipped}}}}},
- {?eh,test_stats,{2,2,{2,3}}},
- {?eh,tc_auto_skip,{surefire_SUITE,{end_per_group,g_fail},
- {failed,
- {surefire_SUITE,init_per_group,
- {'EXIT',all_cases_should_be_skipped}}}}}],
- {?eh,tc_start,{surefire_SUITE,end_per_suite}},
- {?eh,tc_done,{surefire_SUITE,end_per_suite,ok}}].
+ {?eh,test_stats,{1,1,{0,0}}}] ++
+ tc_skip_events(Test,undefined) ++
+ [{?eh,test_stats,{1,1,{1,0}}},
+ {?eh,tc_start,{surefire_SUITE,tc_autoskip_require}},
+ {?eh,tc_done,{surefire_SUITE,tc_autoskip_require,
+ {auto_skipped,{require_failed,'_'}}}},
+ {?eh,test_stats,{1,1,{1,1}}},
+ [{?eh,tc_start,{surefire_SUITE,{init_per_group,g,[]}}},
+ {?eh,tc_done,{surefire_SUITE,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{surefire_SUITE,tc_ok}},
+ {?eh,tc_done,{surefire_SUITE,tc_ok,ok}},
+ {?eh,test_stats,{2,1,{1,1}}},
+ {?eh,tc_start,{surefire_SUITE,tc_fail}},
+ {?eh,tc_done,{surefire_SUITE,tc_fail,
+ {failed,{error,{test_case_failed,"this test should fail"}}}}},
+ {?eh,test_stats,{2,2,{1,1}}}] ++
+ tc_skip_events(Test,g) ++
+ [{?eh,test_stats,{2,2,{2,1}}},
+ {?eh,tc_start,{surefire_SUITE,tc_autoskip_require}},
+ {?eh,tc_done,{surefire_SUITE,tc_autoskip_require,
+ {auto_skipped,{require_failed,'_'}}}},
+ {?eh,test_stats,{2,2,{2,2}}},
+ {?eh,tc_start,{surefire_SUITE,{end_per_group,g,[]}}},
+ {?eh,tc_done,{surefire_SUITE,{end_per_group,g,[]},ok}}],
+ [{?eh,tc_start,{surefire_SUITE,{init_per_group,g_fail,[]}}},
+ {?eh,tc_done,{surefire_SUITE,{init_per_group,g_fail,[]},
+ {failed,{error,all_cases_should_be_skipped}}}},
+ {?eh,tc_auto_skip,{surefire_SUITE,{tc_ok,g_fail},
+ {failed,
+ {surefire_SUITE,init_per_group,
+ {'EXIT',all_cases_should_be_skipped}}}}},
+ {?eh,test_stats,{2,2,{2,3}}},
+ {?eh,tc_auto_skip,{surefire_SUITE,{end_per_group,g_fail},
+ {failed,
+ {surefire_SUITE,init_per_group,
+ {'EXIT',all_cases_should_be_skipped}}}}}],
+ {?eh,tc_start,{surefire_SUITE,end_per_suite}},
+ {?eh,tc_done,{surefire_SUITE,end_per_suite,ok}}].
+
+tc_skip_events(skip_case_in_spec,Group) ->
+ [{?eh,tc_user_skip,{surefire_SUITE,tc_skip_name(Group),"skipped in spec"}}];
+tc_skip_events(_Test,_Group) ->
+ [{?eh,tc_start,{surefire_SUITE,tc_skip}},
+ {?eh,tc_done,{surefire_SUITE,tc_skip,{skipped,"this test is skipped"}}}].
+
+tc_skip_name(undefined) ->
+ tc_skip;
+tc_skip_name(Group) ->
+ {tc_skip,Group}.
test_events(fail_pre_init_per_suite) ->
[{?eh,start_logging,{'DEF','RUNDIR'}},
@@ -257,6 +290,10 @@ test_events(fail_pre_init_per_suite) ->
test_suite_events(pass_SUITE) ++
test_suite_events(fail_SUITE, {1,0,{0,1}}) ++
[{?eh,stop_logging,[]}];
+test_events(skip_suite_in_spec) ->
+ [{?eh,start_logging,'_'},{?eh,start_info,{1,1,0}}] ++
+ test_suite_events(skip_all_surefire_SUITE) ++
+ [{?eh,stop_logging,[]}];
test_events(Test) ->
[{?eh,start_logging,'_'}, {?eh,start_info,{1,1,9}}] ++
test_suite_events(Test) ++
@@ -364,6 +401,8 @@ failed_or_skipped([]) ->
events_to_result(E) ->
events_to_result(E, []).
+events_to_result([{?eh,tc_user_skip,{_Suite,all,_}}|E], Result) ->
+ events_to_result(E, [[[s]]|Result]);
events_to_result([{?eh,tc_auto_skip,{_Suite,init_per_suite,_}}|E], Result) ->
{Suite,Rest} = events_to_result1(E),
events_to_result(Rest, [[[s]|Suite]|Result]);
@@ -382,7 +421,7 @@ events_to_result1([{?eh,tc_done,{_Suite, end_per_suite,R}}|E]) ->
events_to_result1([{?eh,tc_done,{_Suite,_Case,R}}|E]) ->
{Suite,Rest} = events_to_result1(E),
{[result(R)|Suite],Rest};
-events_to_result1([{?eh,tc_auto_skip,_}|E]) ->
+events_to_result1([{?eh,Skip,_}|E]) when Skip==tc_auto_skip; Skip==tc_user_skip ->
{Suite,Rest} = events_to_result1(E),
{[[s]|Suite],Rest};
events_to_result1([_|E]) ->
diff --git a/lib/common_test/test/ct_surefire_SUITE_data/skip_one_case.spec b/lib/common_test/test/ct_surefire_SUITE_data/skip_one_case.spec
new file mode 100644
index 0000000000..42df8a7d1a
--- /dev/null
+++ b/lib/common_test/test/ct_surefire_SUITE_data/skip_one_case.spec
@@ -0,0 +1,2 @@
+{suites,".",surefire_SUITE}.
+{skip_cases,".",surefire_SUITE,tc_skip,"skipped in spec"}.
diff --git a/lib/common_test/test/ct_surefire_SUITE_data/skip_one_suite.spec b/lib/common_test/test/ct_surefire_SUITE_data/skip_one_suite.spec
new file mode 100644
index 0000000000..57966328ab
--- /dev/null
+++ b/lib/common_test/test/ct_surefire_SUITE_data/skip_one_suite.spec
@@ -0,0 +1,2 @@
+{suites,".",[skip_all_surefire_SUITE]}.
+{skip_suites,".",skip_all_surefire_SUITE,"skipped in spec"}.
diff --git a/lib/common_test/test/ct_test_server_if_1_SUITE.erl b/lib/common_test/test/ct_test_server_if_1_SUITE.erl
index 228d900545..0455313669 100644
--- a/lib/common_test/test/ct_test_server_if_1_SUITE.erl
+++ b/lib/common_test/test/ct_test_server_if_1_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -161,6 +161,7 @@ test_events(ts_if_1) ->
{?eh,tc_start,{ts_if_1_SUITE,tc4}},
{?eh,tc_done,{ts_if_1_SUITE,tc4,{failed,{error,failed_on_purpose}}}},
{?eh,test_stats,{1,2,{0,1}}},
+ {?eh,tc_start,{ts_if_1_SUITE,tc5}},
{?eh,tc_done,{ts_if_1_SUITE,tc5,{auto_skipped,{sequence_failed,seq1,tc4}}}},
{?eh,test_stats,{1,2,{0,2}}},
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index e926abd885..de4eb00686 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -765,23 +765,23 @@ locate({parallel,TEvs}, Node, Evs, Config) ->
{Done,RemEvs2,length(RemEvs2)}
end;
%% end_per_group auto- or user skipped
- (TEv={TEH,AutoOrUserSkip,{M,end_per_group,R}}, {Done,RemEvs,_RemSize})
+ (TEv={TEH,AutoOrUserSkip,{M,{end_per_group,G},R}}, {Done,RemEvs,_RemSize})
when AutoOrUserSkip == tc_auto_skip;
AutoOrUserSkip == tc_user_skip ->
RemEvs1 =
lists:dropwhile(
fun({EH,#event{name=tc_auto_skip,
node=EvNode,
- data={Mod,end_per_group,Reason}}}) when
- EH == TEH, EvNode == Node, Mod == M ->
+ data={Mod,{end_per_group,EvGroupName},Reason}}}) when
+ EH == TEH, EvNode == Node, Mod == M, EvGroupName == G ->
case match_data(R, Reason) of
match -> false;
_ -> true
end;
({EH,#event{name=tc_user_skip,
node=EvNode,
- data={Mod,end_per_group,Reason}}}) when
- EH == TEH, EvNode == Node, Mod == M ->
+ data={Mod,{end_per_group,EvGroupName},Reason}}}) when
+ EH == TEH, EvNode == Node, Mod == M, EvGroupName == G ->
case match_data(R, Reason) of
match -> false;
_ -> true
@@ -1008,20 +1008,20 @@ locate({shuffle,TEvs}, Node, Evs, Config) ->
{Done,RemEvs2,length(RemEvs2)}
end;
%% end_per_group auto-or user skipped
- (TEv={TEH,AutoOrUserSkip,{M,end_per_group,R}}, {Done,RemEvs,_RemSize})
+ (TEv={TEH,AutoOrUserSkip,{M,{end_per_group,G},R}}, {Done,RemEvs,_RemSize})
when AutoOrUserSkip == tc_auto_skip;
AutoOrUserSkip == tc_user_skip ->
RemEvs1 =
lists:dropwhile(
fun({EH,#event{name=tc_auto_skip,
node=EvNode,
- data={Mod,end_per_group,Reason}}}) when
- EH == TEH, EvNode == Node, Mod == M, Reason == R ->
+ data={Mod,{end_per_group,EvGroupName},Reason}}}) when
+ EH == TEH, EvNode == Node, Mod == M, EvGroupName == G, Reason == R ->
false;
({EH,#event{name=tc_user_skip,
node=EvNode,
- data={Mod,end_per_group,Reason}}}) when
- EH == TEH, EvNode == Node, Mod == M, Reason == R ->
+ data={Mod,{end_per_group,EvGroupName},Reason}}}) when
+ EH == TEH, EvNode == Node, Mod == M, EvGroupName == G, Reason == R ->
false;
({EH,#event{name=stop_logging,
node=EvNode,data=_}}) when
@@ -1264,10 +1264,10 @@ log_events1([E={_EH,tc_done,{_M,{end_per_group,_GrName,Props},_R}} | Evs], Dev,
io:format(Dev, "~s~p]},~n", [Ind,E]),
log_events1(Evs, Dev, Ind--" ")
end;
-log_events1([E={_EH,tc_auto_skip,{_M,end_per_group,_Reason}} | Evs], Dev, Ind) ->
+log_events1([E={_EH,tc_auto_skip,{_M,{end_per_group,_GrName},_Reason}} | Evs], Dev, Ind) ->
io:format(Dev, "~s~p],~n", [Ind,E]),
log_events1(Evs, Dev, Ind--" ");
-log_events1([E={_EH,tc_user_skip,{_M,end_per_group,_Reason}} | Evs], Dev, Ind) ->
+log_events1([E={_EH,tc_user_skip,{_M,{end_per_group,_GrName},_Reason}} | Evs], Dev, Ind) ->
io:format(Dev, "~s~p],~n", [Ind,E]),
log_events1(Evs, Dev, Ind--" ");
log_events1([E], Dev, Ind) ->
diff --git a/lib/common_test/test/ct_testspec_2_SUITE.erl b/lib/common_test/test/ct_testspec_2_SUITE.erl
index 1a941df185..1bab80942a 100644
--- a/lib/common_test/test/ct_testspec_2_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_2_SUITE.erl
@@ -220,7 +220,24 @@ basic_compatible_no_nodes(_Config) ->
{tc2,{skip,"skipped"}}]}]}],
merge_tests = true},
- verify_result(Verify,ListResult,FileResult).
+ verify_result(Verify,ListResult,FileResult),
+
+ {ok,Tests} = ct_testspec:get_tests([SpecFile]),
+ ct:pal("ct_testspec:get_tests/1:~n~p~n", [Tests]),
+ [{[SpecFile],[{Node,Run,Skip}]}] = Tests,
+ [{Alias1V,x_SUITE,all},
+ {Alias1V,y_SUITE,[{g1,all},{g2,all},tc1,tc2]},
+ {Alias1V,z_SUITE,all},
+ {Alias2V,x_SUITE,all},
+ {Alias2V,y_SUITE,all}] = lists:sort(Run),
+ [{Alias1V,z_SUITE,"skipped"},
+ {Alias2V,x_SUITE,{g1,all},"skipped"},
+ {Alias2V,x_SUITE,{g2,all},"skipped"},
+ {Alias2V,y_SUITE,tc1,"skipped"},
+ {Alias2V,y_SUITE,tc2,"skipped"}] = lists:sort(Skip),
+
+ ok.
+
%%%-----------------------------------------------------------------
%%%
@@ -346,7 +363,25 @@ basic_compatible_nodes(_Config) ->
{tc2,{skip,"skipped"}}]}]}],
merge_tests = true},
- verify_result(Verify,ListResult,FileResult).
+ verify_result(Verify,ListResult,FileResult),
+
+ {ok,Tests} = ct_testspec:get_tests([SpecFile]),
+ ct:pal("ct_testspec:get_tests/1:~n~p~n", [Tests]),
+ [{[SpecFile],[{Node,[],[]},
+ {Node1,Run1,Skip1},
+ {Node2,Run2,Skip2}]}] = Tests,
+ [{TO1V,x_SUITE,all},
+ {TO1V,y_SUITE,[{g1,all},{g2,all},tc1,tc2]},
+ {TO1V,z_SUITE,all}] = lists:sort(Run1),
+ [{TO2V,x_SUITE,all},
+ {TO2V,y_SUITE,all}] = lists:sort(Run2),
+ [{TO1V,z_SUITE,"skipped"}] = lists:sort(Skip1),
+ [{TO2V,x_SUITE,{g1,all},"skipped"},
+ {TO2V,x_SUITE,{g2,all},"skipped"},
+ {TO2V,y_SUITE,tc1,"skipped"},
+ {TO2V,y_SUITE,tc2,"skipped"}] = lists:sort(Skip2),
+
+ ok.
%%%-----------------------------------------------------------------
%%%
@@ -439,7 +474,28 @@ no_merging(_Config) ->
[{y_SUITE,[{tc1,{skip,"skipped"}},
{tc2,{skip,"skipped"}}]}]}]},
- verify_result(Verify,ListResult,FileResult).
+ verify_result(Verify,ListResult,FileResult),
+
+ {ok,Tests} = ct_testspec:get_tests([SpecFile]),
+ ct:pal("ct_testspec:get_tests/1:~n~p~n", [Tests]),
+ [{[SpecFile],[{Node,[],[]},
+ {Node1,Run1,Skip1},
+ {Node2,Run2,Skip2}]}] = Tests,
+ [{TO1V,x_SUITE,all},
+ {TO1V,y_SUITE,[tc1,tc2]},
+ {TO1V,y_SUITE,[{g1,all},{g2,all}]},
+ {TO1V,z_SUITE,all}] = lists:sort(Run1),
+ [{TO2V,x_SUITE,all},
+ {TO2V,x_SUITE,[{skipped,g1,all},{skipped,g2,all}]},
+ {TO2V,y_SUITE,all},
+ {TO2V,y_SUITE,[{skipped,tc1},{skipped,tc2}]}] = lists:sort(Run2),
+ [{TO1V,z_SUITE,"skipped"}] = lists:sort(Skip1),
+ [{TO2V,x_SUITE,{g1,all},"skipped"},
+ {TO2V,x_SUITE,{g2,all},"skipped"},
+ {TO2V,y_SUITE,tc1,"skipped"},
+ {TO2V,y_SUITE,tc2,"skipped"}] = lists:sort(Skip2),
+
+ ok.
%%%-----------------------------------------------------------------
%%%
@@ -510,7 +566,25 @@ multiple_specs(_Config) ->
{y_SUITE,[all,{tc1,{skip,"skipped"}},
{tc2,{skip,"skipped"}}]}]}]},
- verify_result(Verify,FileResult,FileResult).
+ verify_result(Verify,FileResult,FileResult),
+
+ {ok,Tests} = ct_testspec:get_tests([[SpecFile1,SpecFile2]]),
+ ct:pal("ct_testspec:get_tests/1:~n~p~n", [Tests]),
+ [{[SpecFile1,SpecFile2],[{Node,[],[]},
+ {Node1,Run1,Skip1},
+ {Node2,Run2,Skip2}]}] = Tests,
+ [{TO1V,x_SUITE,all},
+ {TO1V,y_SUITE,[{g1,all},{g2,all},tc1,tc2]},
+ {TO1V,z_SUITE,all}] = lists:sort(Run1),
+ [{TO2V,x_SUITE,all},
+ {TO2V,y_SUITE,all}] = lists:sort(Run2),
+ [{TO1V,z_SUITE,"skipped"}] = lists:sort(Skip1),
+ [{TO2V,x_SUITE,{g1,all},"skipped"},
+ {TO2V,x_SUITE,{g2,all},"skipped"},
+ {TO2V,y_SUITE,tc1,"skipped"},
+ {TO2V,y_SUITE,tc2,"skipped"}] = lists:sort(Skip2),
+
+ ok.
%%%-----------------------------------------------------------------
%%%
diff --git a/lib/common_test/test_server/ts_run.erl b/lib/common_test/test_server/ts_run.erl
index 66db1ff9a7..82ae44ec06 100644
--- a/lib/common_test/test_server/ts_run.erl
+++ b/lib/common_test/test_server/ts_run.erl
@@ -258,7 +258,7 @@ make_command(Vars, Spec, State) ->
run_batch(Vars, _Spec, State) ->
process_flag(trap_exit, true),
- Command = State#state.command ++ " -noinput -s erlang halt",
+ Command = State#state.command ++ " -noinput -eval \"erlang:halt(0,[{flush,false}]).\"",
ts_lib:progress(Vars, 1, "Command: ~ts~n", [Command]),
io:format(user, "Command: ~ts~n",[Command]),
Port = open_port({spawn, Command}, [stream, in, eof, exit_status]),
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index c68750886a..e6ae8b2e7a 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.12.2
+COMMON_TEST_VSN = 1.14
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 61e214294e..9ac16af814 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -136,7 +136,7 @@
(see
<seealso marker="erts:absform">The Abstract Format</seealso>
in ERTS User's Guide) in the compiled beam module. Tools
- such as <c>Debugger</c>, <c>Xref</c>, and <c>Cover</c> require
+ such as Debugger, Xref, and Cover require
the debug information to be included.</p>
<p><em>Warning</em>: Source code can be reconstructed from
@@ -544,7 +544,7 @@ module.beam: module.erl \
compiler to be deprecated. Notice that the compiler does not know
about attribute <c>-deprecated()</c>, but uses an
assembled list of deprecated functions in Erlang/OTP. To
- do a more general check, the <c>Xref</c> tool can be used.
+ do a more general check, the Xref tool can be used.
See also
<seealso marker="tools:xref#deprecated_function">xref(3)</seealso>
and the function
@@ -669,7 +669,7 @@ module.beam: module.erl \
<fsummary>Compiles a list of forms.</fsummary>
<desc>
<p>Is the same as
- <c>forms(File, [verbose,report_errors,report_warnings])</c>.
+ <c>forms(Forms, [verbose,report_errors,report_warnings])</c>.
</p>
</desc>
</func>
@@ -846,7 +846,7 @@ pi() -> 3.1416.
<section>
<title>Inlining of List Functions</title>
<p>The compiler can also inline various list manipulation functions
- from the module <c>list</c> in <c>STDLIB</c>.</p>
+ from the module <c>list</c> in STDLIB.</p>
<p>This feature must be explicitly enabled with a compiler option or a
<c>-compile()</c> attribute in the source module.</p>
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index e25cdc580c..db50cba094 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,128 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.0.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fail labels on guard BIFs weren't taken into account
+ during an optimization pass, and a bug in the validation
+ pass sometimes prevented this from being noticed when a
+ fault occurred.</p>
+ <p>
+ Own Id: OTP-14522 Aux Id: ERIERL-48 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor internal changes. A typo in the documentation was
+ also fixed.</p>
+ <p>
+ Own Id: OTP-14240</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a compiler crash when maps were matched.</p>
+ <p>
+ Own Id: OTP-13931 Aux Id: ERL-266 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a compiler crash having to with the delayed
+ sub-creation optimization. (Thanks to Jose Valim for
+ reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13947 Aux Id: ERL-268 </p>
+ </item>
+ <item>
+ <p>The compiler option <c>inline_list_funcs</c>
+ accidentally turned off some other optimizations.</p>
+ <p>
+ Own Id: OTP-13985</p>
+ </item>
+ <item>
+ <p>The compiler could sometimes generate spurious
+ warnings when inlining was enabled.</p>
+ <p>
+ Own Id: OTP-14040 Aux Id: ERL-301 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If the compiler fails to write the BEAM file, it will now
+ report the reason of the error for the write operation.</p>
+ <p>
+ Own Id: OTP-13701</p>
+ </item>
+ <item>
+ <p>
+ Fixed an internal compiler error. (Thanks to Svilen
+ Ivanov for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13780 Aux Id: ERL-202 </p>
+ </item>
+ <item>
+ <p>
+ The compiler could crash when trying to compile a
+ complicated expression with multiple catches all on one
+ line . (Thanks to Thomas Arts for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13804 Aux Id: ERL-209 </p>
+ </item>
+ <item>
+ <p>
+ Eliminated a few internal compiler failures.</p>
+ <p>
+ Own Id: OTP-13863</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A literal binary matching regression was introduced in
+ 19.0 where a match could fail to resolve to the right
+ clause. This has now been fixed.</p>
+ <p>
+ Own Id: OTP-13738</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -263,7 +385,7 @@
<item>
<p>
The <c>cerl</c> and <c>cerl_trees</c> modules in the
- <c>compiler</c> application are now documented.</p>
+ Compiler application are now documented.</p>
<p>
Own Id: OTP-11978</p>
</item>
@@ -1965,7 +2087,7 @@
<c>RightExpr</c> or vice versa. The evaluation order is
only important if the expressions contains and/or depends
on operations with side-effects, such as message passing
- or <c>ets</c> operations.</p>
+ or ETS operations.</p>
<p>
Own Id: OTP-7206</p>
</item>
diff --git a/lib/compiler/doc/src/ref_man.xml b/lib/compiler/doc/src/ref_man.xml
index f5466553c0..c32c499008 100644
--- a/lib/compiler/doc/src/ref_man.xml
+++ b/lib/compiler/doc/src/ref_man.xml
@@ -30,7 +30,7 @@
<file>application.sgml</file>
</header>
<description>
- <p>The <c>Compiler</c> application compiles Erlang
+ <p>The Compiler application compiles Erlang
code to byte-code. The highly compact byte-code is executed by
the Erlang emulator.</p>
</description>
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 85d332c56e..6a35191f6e 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -58,13 +58,6 @@ blockify(Is) ->
blockify([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_Lbl},{label,Fail}|Is], Acc) ->
%% Useless instruction sequence.
blockify(Is, Acc);
-blockify([{get_map_elements,F,S,{list,Gets}}|Is0], Acc) ->
- %% A get_map_elements instruction is only safe at the beginning of
- %% a block because of the failure label.
- {Ss,Ds} = beam_utils:split_even(Gets),
- I = {set,Ds,[S|Ss],{get_map_elements,F}},
- {Block,Is} = collect_block(Is0, [I]),
- blockify(Is, [{block,Block}|Acc]);
blockify([I|Is0]=IsAll, Acc) ->
case collect(I) of
error -> blockify(Is0, [I|Acc]);
@@ -159,14 +152,43 @@ find_fixpoint(OptFun, Is0) ->
end.
%% move_allocates(Is0) -> Is
-%% Move allocate instructions upwards in the instruction stream, in the
-%% hope of getting more possibilities for optimizing away moves later.
+%% Move allocate instructions upwards in the instruction stream
+%% (within the same block), in the hope of getting more possibilities
+%% for optimizing away moves later.
%%
-%% NOTE: Moving allocation instructions is only safe because it is done
-%% immediately after code generation so that we KNOW that if {x,X} is
-%% initialized, all x registers with lower numbers are also initialized.
-%% That assumption may not be true after other optimizations, such as
-%% the beam_utils:live_opt/1 optimization.
+%% For example, we can transform the following instructions:
+%%
+%% get_tuple_element x(1) Element => x(2)
+%% allocate_zero StackSize 3 %% x(0), x(1), x(2) are live
+%%
+%% to the following instructions:
+%%
+%% allocate_zero StackSize 2 %% x(0) and x(1) are live
+%% get_tuple_element x(1) Element => x(2)
+%%
+%% NOTE: Since the beam_reorder pass has been run, it is no longer
+%% safe to assume that if x(N) is initialized, then all lower-numbered
+%% x registers are also initialized.
+%%
+%% For example, in general it is not safe to transform the following
+%% instructions:
+%%
+%% get_tuple_element x(0) Element => x(1)
+%% allocate_zero StackSize 3 %x(0), x(1), x(2) are live
+%%
+%% to the following instructions:
+%%
+%% allocate_zero StackSize 3
+%% get_tuple_element x(0) Element => x(1)
+%%
+%% The transformation is safe if and only if x(1) has been
+%% initialized previously. Unfortunately, beam_reorder may have moved
+%% a get_tuple_element instruction so that x(1) is not always
+%% initialized when this code is reached. To find whether or not x(1)
+%% is initialized, we would need to analyze all code preceding these
+%% two instructions (across branches). Since we currently don't have
+%% any practical mechanism for doing that, we will have to
+%% conservatively assume that the transformation is unsafe.
move_allocates([{block,Bl0}|Is]) ->
Bl = move_allocates_1(reverse(Bl0), []),
@@ -175,38 +197,26 @@ move_allocates([I|Is]) ->
[I|move_allocates(Is)];
move_allocates([]) -> [].
-move_allocates_1([{set,[],[],{alloc,_,_}=Alloc}|Is0], Acc0) ->
- {Is,Acc} = move_allocates_2(Alloc, Is0, Acc0),
- move_allocates_1(Is, Acc);
+move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info}}|Acc]=Acc0) ->
+ case {alloc_may_pass(I),alloc_live_regs(I, Live0)} of
+ {false,_} ->
+ move_allocates_1(Is, [I|Acc0]);
+ {true,not_possible} ->
+ move_allocates_1(Is, [I|Acc0]);
+ {true,Live} when is_integer(Live) ->
+ A = {set,[],[],{alloc,Live,Info}},
+ move_allocates_1(Is, [A,I|Acc])
+ end;
move_allocates_1([I|Is], Acc) ->
move_allocates_1(Is, [I|Acc]);
-move_allocates_1([], Is) -> Is.
-
-move_allocates_2({alloc,Live,Info}, [{set,[],[],{alloc,Live0,Info0}}|Is], Acc) ->
- Live = Live0, % Assertion.
- Alloc = {alloc,Live,combine_alloc(Info0, Info)},
- move_allocates_2(Alloc, Is, Acc);
-move_allocates_2({alloc,Live,Info}=Alloc0, [I|Is]=Is0, Acc) ->
- case alloc_may_pass(I) of
- false ->
- {Is0,[{set,[],[],Alloc0}|Acc]};
- true ->
- Alloc = {alloc,alloc_live_regs(I, Live),Info},
- move_allocates_2(Alloc, Is, [I|Acc])
- end;
-move_allocates_2(Alloc, [], Acc) ->
- {[],[{set,[],[],Alloc}|Acc]}.
+move_allocates_1([], Acc) -> Acc.
alloc_may_pass({set,_,_,{alloc,_,_}}) -> false;
alloc_may_pass({set,_,_,{set_tuple_element,_}}) -> false;
-alloc_may_pass({set,_,_,{get_map_elements,_}}) -> false;
alloc_may_pass({set,_,_,put_list}) -> false;
alloc_may_pass({set,_,_,put}) -> false;
alloc_may_pass({set,_,_,_}) -> true.
-combine_alloc({_,Ns,Nh1,Init}, {_,nostack,Nh2,[]}) ->
- {zero,Ns,beam_utils:combine_heap_needs(Nh1, Nh2),Init}.
-
%% opt([Instruction]) -> [Instruction]
%% Optimize the instruction stream inside a basic block.
@@ -217,8 +227,6 @@ opt([{set,_,_,{line,_}}=Line1,
{set,[D2],[{integer,Idx2},Reg],{bif,element,{f,0}}}=I2|Is])
when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg ->
opt([Line2,I2,Line1,I1|Is]);
-opt([{set,[_|_],_Ss,{get_map_elements,_F}}=I|Is]) ->
- [I|opt(Is)];
opt([{set,Ds0,Ss,Op}|Is0]) ->
{Ds,Is} = opt_moves(Ds0, Is0),
[{set,Ds,Ss,Op}|opt(Is)];
@@ -393,10 +401,19 @@ eliminate_use_of_from_reg([I]=Is, From, _To, Acc) ->
%% opt_alloc(Instructions) -> Instructions'
%% Optimises all allocate instructions.
+opt_alloc([{set,[],[],{alloc,Live0,Info0}},
+ {set,[],[],{alloc,Live,Info}}|Is]) ->
+ Live = Live0, %Assertion.
+ Alloc = combine_alloc(Info0, Info),
+ I = {set,[],[],{alloc,Live,Alloc}},
+ opt_alloc([I|Is]);
opt_alloc([{set,[],[],{alloc,R,{_,Ns,Nh,[]}}}|Is]) ->
[{set,[],[],opt_alloc(Is, Ns, Nh, R)}|Is];
opt_alloc([I|Is]) -> [I|opt_alloc(Is)];
opt_alloc([]) -> [].
+
+combine_alloc({_,Ns,Nh1,Init}, {_,nostack,Nh2,[]}) ->
+ {zero,Ns,beam_utils:combine_heap_needs(Nh1, Nh2),Init}.
%% opt_alloc(Instructions, FrameSize, HeapNeed, LivingRegs) -> [Instr]
%% Generates the optimal sequence of instructions for
@@ -445,13 +462,14 @@ count_ones(Bits, Acc) ->
alloc_live_regs({set,Ds,Ss,_}, Regs0) ->
Rset = x_live(Ss, x_dead(Ds, (1 bsl Regs0)-1)),
- live_regs(Rset).
+ live_regs(0, Rset).
-live_regs(Regs) ->
- live_regs_1(0, Regs).
-
-live_regs_1(N, 0) -> N;
-live_regs_1(N, Regs) -> live_regs_1(N+1, Regs bsr 1).
+live_regs(N, 0) ->
+ N;
+live_regs(N, Regs) when Regs band 1 =:= 1 ->
+ live_regs(N+1, Regs bsr 1);
+live_regs(_, _) ->
+ not_possible.
x_dead([{x,N}|Rs], Regs) -> x_dead(Rs, Regs band (bnot (1 bsl N)));
x_dead([_|Rs], Regs) -> x_dead(Rs, Regs);
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 286307a4be..ae1b34ba49 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -205,8 +205,15 @@ btb_reaches_match_1(Is, Regs, D) ->
btb_reaches_match_2([{block,Bl}|Is], Regs0, D) ->
Regs = btb_reaches_match_block(Bl, Regs0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs, D) ->
- btb_call(Arity, Lbl, Regs, Is, D);
+btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs0, D) ->
+ case is_tail_call(Is) of
+ true ->
+ Regs1 = btb_kill_not_live(Arity, Regs0),
+ Regs = btb_kill_yregs(Regs1),
+ btb_tail_call(Lbl, Regs, D);
+ false ->
+ btb_call(Arity, Lbl, Regs0, Is, D)
+ end;
btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
btb_call(Arity+2, apply, Regs, Is, D);
btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
@@ -360,6 +367,10 @@ btb_reaches_match_2([{line,_}|Is], Regs, D) ->
btb_reaches_match_2([I|_], Regs, _) ->
btb_error({btb_context_regs(Regs),I,not_handled}).
+is_tail_call([{deallocate,_}|_]) -> true;
+is_tail_call([return|_]) -> true;
+is_tail_call(_) -> false.
+
btb_call(Arity, Lbl, Regs0, Is, D0) ->
Regs = btb_kill_not_live(Arity, Regs0),
case btb_are_x_registers_empty(Regs) of
@@ -369,15 +380,15 @@ btb_call(Arity, Lbl, Regs0, Is, D0) ->
D = btb_tail_call(Lbl, Regs, D0),
%% No problem so far (the called function can handle a
- %% match context). Now we must make sure that the rest
- %% of this function following the call does not attempt
- %% to use the match context in case there is a copy
- %% tucked away in a y register.
+ %% match context). Now we must make sure that we don't
+ %% have any copies of the match context tucked away in an
+ %% y register.
RegList = btb_context_regs(Regs),
- YRegs = [R || {y,_}=R <- RegList],
- case btb_are_all_unused(YRegs, Is, D) of
- true -> D;
- false -> btb_error({multiple_uses,RegList})
+ case [R || {y,_}=R <- RegList] of
+ [] ->
+ D;
+ [_|_] ->
+ btb_error({multiple_uses,RegList})
end;
true ->
%% No match context in any x register. It could have been
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
index b01f58f683..6f6d742293 100644
--- a/lib/compiler/src/beam_dead.erl
+++ b/lib/compiler/src/beam_dead.erl
@@ -272,17 +272,14 @@ backward([{jump,{f,To}}=J|[{bif,Op,_,Ops,Reg}|Is]=Is0], D, Acc) ->
catch
throw:not_possible -> backward(Is0, D, [J|Acc])
end;
-backward([{test,bs_start_match2,F,Live,[R,_]=Args,Ctxt}|Is], D,
+backward([{test,bs_start_match2,F,_,[R,_],Ctxt}=I|Is], D,
[{test,bs_match_string,F,[Ctxt,Bs]},
{test,bs_test_tail2,F,[Ctxt,0]}|Acc0]=Acc) ->
- {f,To0} = F,
- To = shortcut_bs_start_match(To0, R, D),
case beam_utils:is_killed(Ctxt, Acc0, D) of
true ->
- Eq = {test,is_eq_exact,{f,To},[R,{literal,Bs}]},
+ Eq = {test,is_eq_exact,F,[R,{literal,Bs}]},
backward(Is, D, [Eq|Acc0]);
false ->
- I = {test,bs_start_match2,{f,To},Live,Args,Ctxt},
backward(Is, D, [I|Acc])
end;
backward([{test,bs_start_match2,{f,To0},Live,[Src|_]=Info,Dst}|Is], D, Acc) ->
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index 36369bd0b4..c9ff07b496 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -64,7 +64,6 @@ norm({set,[],[S,D],{set_tuple_element,I}}) -> {set_tuple_element,S,D,I};
norm({set,[D1,D2],[S],get_list}) -> {get_list,S,D1,D2};
norm({set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}}) ->
{put_map,F,Op,S,D,R,{list,Puts}};
-%% get_map_elements is always handled in beam_split (moved out of block)
norm({set,[],[],remove_message}) -> remove_message;
norm({set,[],[],fclearerror}) -> fclearerror;
norm({set,[],[],fcheckerror}) -> {fcheckerror,{f,0}}.
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 09cd3aa2d4..48b5a32814 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -167,12 +167,18 @@ share_1([{label,L}=Lbl|Is], Dict0, Seq, Acc) ->
end;
share_1([{func_info,_,_,_}=I|Is], _, [], Acc) ->
reverse(Is, [I|Acc]);
+share_1([{'catch',_,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
share_1([{'try',_,_}=I|Is], Dict0, Seq, Acc) ->
Dict = clean_non_sharable(Dict0),
share_1(Is, Dict, [I|Seq], Acc);
share_1([{try_case,_}=I|Is], Dict0, Seq, Acc) ->
Dict = clean_non_sharable(Dict0),
share_1(Is, Dict, [I|Seq], Acc);
+share_1([{catch_end,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
share_1([I|Is], Dict, Seq, Acc) ->
case is_unreachable_after(I) of
false ->
@@ -182,18 +188,18 @@ share_1([I|Is], Dict, Seq, Acc) ->
end.
clean_non_sharable(Dict) ->
- %% We are passing in or out of a 'try' block. Remove
- %% sequences that should not shared over the boundaries
- %% of a 'try' block. Since the end of the sequence must match,
- %% the only possible match between a sequence outside and
- %% a sequence inside the 'try' block is a sequence that ends
- %% with an instruction that causes an exception. Any sequence
- %% that causes an exception must contain a line/1 instruction.
+ %% We are passing in or out of a 'catch' or 'try' block. Remove
+ %% sequences that should not be shared over the boundaries of the
+ %% block. Since the end of the sequence must match, the only
+ %% possible match between a sequence outside and a sequence inside
+ %% the 'catch'/'try' block is a sequence that ends with an
+ %% instruction that causes an exception. Any sequence that causes
+ %% an exception must contain a line/1 instruction.
maps:filter(fun(K, _V) -> sharable_with_try(K) end, Dict).
sharable_with_try([{line,_}|_]) ->
%% This sequence may cause an exception and may potentially
- %% match a sequence on the other side of the 'try' block
+ %% match a sequence on the other side of the 'catch'/'try' block
%% boundary.
false;
sharable_with_try([_|Is]) ->
diff --git a/lib/compiler/src/beam_split.erl b/lib/compiler/src/beam_split.erl
index c83c686953..feeab0af50 100644
--- a/lib/compiler/src/beam_split.erl
+++ b/lib/compiler/src/beam_split.erl
@@ -56,9 +56,6 @@ split_block([{set,[D],[S|Puts],{alloc,R,{put_map,Op,{f,Lbl}=Fail}}}|Is],
Bl, Acc) when Lbl =/= 0 ->
split_block(Is, [], [{put_map,Fail,Op,S,D,R,{list,Puts}}|
make_block(Bl, Acc)]);
-split_block([{set,Ds,[S|Ss],{get_map_elements,Fail}}|Is], Bl, Acc) ->
- Gets = beam_utils:join_even(Ss,Ds),
- split_block(Is, [], [{get_map_elements,Fail,S,{list,Gets}}|make_block(Bl, Acc)]);
split_block([{set,[R],[],{try_catch,Op,L}}|Is], Bl, Acc) ->
split_block(Is, [], [{Op,R,L}|make_block(Bl, Acc)]);
split_block([{set,[],[],{line,_}=Line}|Is], Bl, Acc) ->
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index a15ecf633e..e743abc773 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -26,7 +26,7 @@
empty_label_index/0,index_label/3,index_labels/1,
code_at/2,bif_to_test/3,is_pure_test/1,
live_opt/1,delete_live_annos/1,combine_heap_needs/2,
- join_even/2,split_even/1]).
+ split_even/1]).
-import(lists, [member/2,sort/1,reverse/1,splitwith/2]).
@@ -233,11 +233,6 @@ combine_heap_needs(H1, H2) when is_integer(H1), is_integer(H2) ->
split_even(Rs) -> split_even(Rs, [], []).
-%% join_even/1
-%% {[1,3,5],[2,4,6]} -> [1,2,3,4,5,6]
-
-join_even([], []) -> [];
-join_even([S|Ss], [D|Ds]) -> [S,D|join_even(Ss, Ds)].
%%%
%%% Local functions.
@@ -753,6 +748,11 @@ live_opt([timeout=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
live_opt([{wait,_}=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
+live_opt([{get_map_elements,Fail,Src,{list,List}}=I|Is], Regs0, D, Acc) ->
+ {Ss,Ds} = split_even(List),
+ Regs1 = x_live([Src|Ss], x_dead(Ds, Regs0)),
+ Regs = live_join_label(Fail, D, Regs1),
+ live_opt(Is, Regs, D, [I|Acc]);
%% Transparent instructions - they neither use nor modify x registers.
live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
@@ -783,37 +783,46 @@ live_opt([{recv_mark,_}=I|Is], Regs, D, Acc) ->
live_opt([], _, _, Acc) -> Acc.
-live_opt_block([{set,Ds,Ss,Op}=I0|Is], Regs0, D, Acc) ->
+live_opt_block([{set,Ds,Ss,Op0}|Is], Regs0, D, Acc) ->
Regs1 = x_live(Ss, x_dead(Ds, Regs0)),
- {I,Regs} = case Op of
- {alloc,Live0,Alloc} ->
- %% The life-time analysis used by the code generator
- %% is sometimes too conservative, so it may be
- %% possible to lower the number of live registers
- %% based on the exact liveness information.
- %% The main benefit is that more optimizations that
- %% depend on liveness information (such as the
- %% beam_bool and beam_dead passes) may be applied.
- Live = live_regs(Regs1),
- true = Live =< Live0, %Assertion.
- I1 = {set,Ds,Ss,{alloc,Live,Alloc}},
- {I1,live_call(Live)};
- _ ->
- {I0,Regs1}
- end,
+ {Op, Regs} = live_opt_block_op(Op0, Regs1, D),
+ I = {set, Ds, Ss, Op},
+
case Ds of
- [{x,X}] ->
- case (not is_live(X, Regs0)) andalso Op =:= move of
- true ->
- live_opt_block(Is, Regs0, D, Acc);
- false ->
- live_opt_block(Is, Regs, D, [I|Acc])
- end;
- _ ->
- live_opt_block(Is, Regs, D, [I|Acc])
+ [{x,X}] ->
+ case (not is_live(X, Regs0)) andalso Op =:= move of
+ true ->
+ live_opt_block(Is, Regs0, D, Acc);
+ false ->
+ live_opt_block(Is, Regs, D, [I|Acc])
+ end;
+ _ ->
+ live_opt_block(Is, Regs, D, [I|Acc])
end;
live_opt_block([], Regs, _, Acc) -> {Acc,Regs}.
+live_opt_block_op({alloc,Live0,AllocOp}, Regs0, D) ->
+ Regs =
+ case AllocOp of
+ {Kind, _N, Fail} when Kind =:= gc_bif; Kind =:= put_map ->
+ live_join_label(Fail, D, Regs0);
+ _ ->
+ Regs0
+ end,
+
+ %% The life-time analysis used by the code generator is sometimes too
+ %% conservative, so it may be possible to lower the number of live
+ %% registers based on the exact liveness information. The main benefit is
+ %% that more optimizations that depend on liveness information (such as the
+ %% beam_bool and beam_dead passes) may be applied.
+ Live = live_regs(Regs),
+ true = Live =< Live0,
+ {{alloc,Live,AllocOp}, live_call(Live)};
+live_opt_block_op({bif,_N,Fail} = Op, Regs, D) ->
+ {Op, live_join_label(Fail, D, Regs)};
+live_opt_block_op(Op, Regs, _D) ->
+ {Op, Regs}.
+
live_join_labels([{f,L}|T], D, Regs0) when L =/= 0 ->
Regs = gb_trees:get(L, D) bor Regs0,
live_join_labels(T, D, Regs);
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 4c0cb6780a..69e34f76b0 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -808,9 +808,11 @@ validate_bs_skip_utf(Fail, Ctx, Live, Vst0) ->
%% A possibility for garbage collection must not occur between setelement/3 and
%% set_tuple_element/3.
%%
+%% Note that #vst.current will be 'none' if the instruction is unreachable.
+%%
val_dsetel({move,_,_}, Vst) ->
Vst;
-val_dsetel({call_ext,3,{extfunc,erlang,setelement,3}}, #vst{current=St}=Vst) ->
+val_dsetel({call_ext,3,{extfunc,erlang,setelement,3}}, #vst{current=#st{}=St}=Vst) ->
Vst#vst{current=St#st{setelem=true}};
val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=false}}) ->
error(illegal_context_for_set_tuple_element);
@@ -919,9 +921,9 @@ verify_call_match_context(Lbl, Ctx, #vst{ft=Ft}) ->
error({unsuitable_bs_start_match2,I})
end.
-allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}=St}=Vst0) ->
+allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}}=Vst0) ->
verify_live(Live, Vst0),
- Vst = prune_x_regs(Live, Vst0),
+ Vst = #vst{current=St} = prune_x_regs(Live, Vst0),
Ys = init_regs(Stk, case Zero of
true -> initialized;
false -> uninitialized
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 82ff8a95f3..e37ca31704 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,6 +43,10 @@
-type abstract_code() :: [erl_parse:abstract_form()].
+%% Internal representations used for 'from_asm' and 'from_beam' compilation can
+%% also be valid, but have no relevant types defined.
+-type forms() :: abstract_code() | cerl:c_module().
+
-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
-type err_info() :: {erl_anno:line() | 'none',
@@ -88,7 +92,7 @@ file(File, Opt) ->
forms(Forms) -> forms(Forms, ?DEFAULT_OPTIONS).
--spec forms(abstract_code(), [option()] | option()) -> comp_ret().
+-spec forms(forms(), [option()] | option()) -> comp_ret().
forms(Forms, Opts) when is_list(Opts) ->
do_compile({forms,Forms}, [binary|Opts++env_default_opts()]);
@@ -116,7 +120,7 @@ noenv_file(File, Opts) when is_list(Opts) ->
noenv_file(File, Opt) ->
noenv_file(File, [Opt|?DEFAULT_OPTIONS]).
--spec noenv_forms(abstract_code(), [option()] | option()) -> comp_ret().
+-spec noenv_forms(forms(), [option()] | option()) -> comp_ret().
noenv_forms(Forms, Opts) when is_list(Opts) ->
do_compile({forms,Forms}, [binary|Opts]);
@@ -169,17 +173,25 @@ env_default_opts() ->
do_compile(Input, Opts0) ->
Opts = expand_opts(Opts0),
- {Pid,Ref} =
- spawn_monitor(fun() ->
- exit(try
- internal(Input, Opts)
- catch
- error:Reason ->
- {error,Reason}
- end)
- end),
- receive
- {'DOWN',Ref,process,Pid,Rep} -> Rep
+ IntFun = fun() -> try
+ internal(Input, Opts)
+ catch
+ error:Reason ->
+ {error,Reason}
+ end
+ end,
+ %% Dialyzer has already spawned workers.
+ case lists:member(dialyzer, Opts) of
+ true ->
+ IntFun();
+ false ->
+ {Pid,Ref} =
+ spawn_monitor(fun() ->
+ exit(IntFun())
+ end),
+ receive
+ {'DOWN',Ref,process,Pid,Rep} -> Rep
+ end
end.
expand_opts(Opts0) ->
@@ -236,6 +248,8 @@ format_error({epp,E}) ->
epp:format_error(E);
format_error(write_error) ->
"error writing file";
+format_error({write_error, Error}) ->
+ io_lib:format("error writing file: ~ts", [file:format_error(Error)]);
format_error({rename,From,To,Error}) ->
io_lib:format("failed to rename ~ts to ~ts: ~ts",
[From,To,file:format_error(Error)]);
@@ -678,7 +692,7 @@ kernel_passes() ->
{iff,core,?pass(save_core_code)},
%% Kernel Erlang and code generation.
- {pass,v3_kernel},
+ ?pass(v3_kernel),
{iff,dkern,{listing,"kernel"}},
{iff,'to_kernel',{done,"kernel"}},
{pass,v3_life},
@@ -1206,7 +1220,7 @@ makedep_output(#compile{code=Code,options=Opts,ofile=Ofile}=St) ->
end,
{ok,St}
catch
- exit:_ ->
+ error:_ ->
%% Couldn't write to output Makefile.
Err = {St#compile.ifile,[{none,?MODULE,write_error}]},
{error,St#compile{errors=St#compile.errors++[Err]}}
@@ -1235,6 +1249,17 @@ core_fold_module_after_inlining(#compile{code=Code0,options=Opts}=St) ->
{ok,Code,_Ws} = sys_core_fold:module(Code0, Opts),
{ok,St#compile{code=Code}}.
+v3_kernel(#compile{code=Code0,options=Opts,warnings=Ws0}=St) ->
+ {ok,Code,Ws} = v3_kernel:module(Code0, Opts),
+ case Ws =:= [] orelse test_core_inliner(St) of
+ false ->
+ {ok,St#compile{code=Code,warnings=Ws0++Ws}};
+ true ->
+ %% cerl_inline may produce code that generates spurious
+ %% warnings. Ignore any such warnings.
+ {ok,St#compile{code=Code}}
+ end.
+
test_old_inliner(#compile{options=Opts}) ->
%% The point of this test is to avoid loading the old inliner
%% if we know that it will not be used.
@@ -1479,8 +1504,8 @@ save_binary_1(St) ->
end,
{error,St#compile{errors=St#compile.errors ++ Es}}
end;
- {error,_Error} ->
- Es = [{Tfile,[{none,compile,write_error}]}],
+ {error,Error} ->
+ Es = [{Tfile,[{none,compile,{write_error,Error}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
@@ -1628,8 +1653,8 @@ listing(LFun, Ext, St) ->
LFun(Lf, Code),
ok = file:close(Lf),
{ok,St};
- {error,_Error} ->
- Es = [{Lfile,[{none,compile,write_error}]}],
+ {error,Error} ->
+ Es = [{Lfile,[{none,compile,{write_error,Error}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index e0de50f3ae..4922953407 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -468,7 +468,8 @@ bitstr(#c_bitstr{val=Val,size=Size}=BinSeg, Sub) ->
%% Currently, we don't attempt to check binaries because they
%% are difficult to check.
-is_safe_simple(#c_var{}, _) -> true;
+is_safe_simple(#c_var{}=Var, _) ->
+ not cerl:is_c_fname(Var);
is_safe_simple(#c_cons{hd=H,tl=T}, Sub) ->
is_safe_simple(H, Sub) andalso is_safe_simple(T, Sub);
is_safe_simple(#c_tuple{es=Es}, Sub) -> is_safe_simple_list(Es, Sub);
@@ -733,7 +734,7 @@ call(#c_call{args=As}=Call, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) ->
false ->
case sys_core_fold_lists:call(Call, M, N, As) of
none ->
- call_1(Call, M, N, As, Sub);
+ call_1(Call, M0, N0, As, Sub);
Core ->
expr(Core, Sub)
end
@@ -1129,7 +1130,13 @@ clause_1(#c_clause{guard=G0,body=B0}=Cl, Ps1, Cexpr, Ctxt, Sub1) ->
%%
%% case A of NewVar when true -> ...
%%
- sub_set_var(Var, Cexpr, Sub2);
+ case cerl:is_c_fname(Cexpr) of
+ false ->
+ sub_set_var(Var, Cexpr, Sub2);
+ true ->
+ %% We must not copy funs, and especially not into guards.
+ Sub2
+ end;
_ ->
Sub2
end,
diff --git a/lib/compiler/test/beam_block_SUITE.erl b/lib/compiler/test/beam_block_SUITE.erl
index 4bcb252833..55d5f2dbe8 100644
--- a/lib/compiler/test/beam_block_SUITE.erl
+++ b/lib/compiler/test/beam_block_SUITE.erl
@@ -21,7 +21,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- get_map_elements/1,otp_7345/1,move_opt_across_gc_bif/1]).
+ get_map_elements/1,otp_7345/1,move_opt_across_gc_bif/1,
+ erl_202/1,repro/1]).
%% The only test for the following functions is that
%% the code compiles and is accepted by beam_validator.
@@ -37,7 +38,9 @@ groups() ->
[{p,[parallel],
[get_map_elements,
otp_7345,
- move_opt_across_gc_bif
+ move_opt_across_gc_bif,
+ erl_202,
+ repro
]}].
init_per_suite(Config) ->
@@ -135,6 +138,48 @@ positive(speaking) ->
paris([], P) -> P + 1.
+
+%% See https://bugs.erlang.org/browse/ERL-202.
+%% Test that move_allocates/1 in beam_block doesn't move allocate
+%% when it would not be safe.
+
+-record(erl_202_r1, {y}).
+-record(erl_202_r2, {x}).
+
+erl_202(_Config) ->
+ Ref = make_ref(),
+ Ref = erl_202({{1,2},Ref}, 42),
+
+ {Ref} = erl_202({7,8}, #erl_202_r1{y=#erl_202_r2{x=Ref}}),
+
+ ok.
+
+erl_202({{_, _},X}, _) ->
+ X;
+erl_202({_, _}, #erl_202_r1{y=R2}) ->
+ {R2#erl_202_r2.x}.
+
+%% See https://bugs.erlang.org/browse/ERL-266.
+%% Instructions with failure labels are not safe to include
+%% in a block. Including get_map_elements in a block would
+%% lead to unsafe code.
+
+repro(_Config) ->
+ [] = maps:to_list(repro([], #{}, #{})),
+ [{tmp1,n}] = maps:to_list(repro([{tmp1,0}], #{}, #{})),
+ [{tmp1,name}] = maps:to_list(repro([{tmp1,0}], #{}, #{0=>name})),
+ ok.
+
+repro([], TempNames, _Slots) ->
+ TempNames;
+repro([{Temp, Slot}|Xs], TempNames, Slots0) ->
+ {Name, Slots} =
+ case Slots0 of
+ #{Slot := Name0} -> {Name0, Slots0};
+ #{} -> {n, Slots0#{Slot => n}}
+ end,
+ repro(Xs, TempNames#{Temp => Name}, Slots).
+
%%%
%%% The only test of the following code is that it compiles.
%%%
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 0b13adaff2..088f63606c 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -21,7 +21,7 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- undefined_label/1]).
+ undefined_label/1,ambiguous_catch_try_state/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -32,7 +32,8 @@ all() ->
groups() ->
[{p,[parallel],
- [undefined_label
+ [undefined_label,
+ ambiguous_catch_try_state
]}].
init_per_suite(Config) ->
@@ -57,3 +58,17 @@ flights(0, [], []) when [], 0; 0.0, [], false ->
clark;
flights(_, Reproduction, introduction) when false, Reproduction ->
responsible.
+
+%% [ERL-209] beam_jump would share 'catch' blocks, causing an
+%% ambiguous_catch_try_state error in beam_validator.
+
+ambiguous_catch_try_state(_Config) ->
+ {{'EXIT',{{case_clause,song},_}},{'EXIT',{{case_clause,song},_}}} =
+ checks(42),
+ ok.
+
+river() -> song.
+
+checks(Wanted) ->
+ %% Must be one line to cause the unsafe optimization.
+ {catch case river() of sheet -> begin +Wanted, if "da" -> Wanted end end end, catch case river() of sheet -> begin + Wanted, if "da" -> Wanted end end end}.
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
index ff31f2d3bd..27ce51eec3 100644
--- a/lib/compiler/test/beam_reorder_SUITE.erl
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 69e2f1838d..492067ef00 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index f6d4a311bb..ac734a70be 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -260,6 +260,14 @@ otp_8949_b(A, B) ->
liveopt(_Config) ->
F = liveopt_fun(42, pebkac, user),
void = F(42, #alarmInfo{type=sctp,cause=pebkac,origin=user}),
+
+
+ A = {#alarmInfo{cause = {abc, def}}, ghi},
+ A = liveopt_guard_bif(A),
+
+ B = {#alarmInfo{cause = {abc}}, def},
+ {#alarmInfo{cause = {{abc}}}, def} = liveopt_guard_bif(B),
+
ok.
liveopt_fun(Peer, Cause, Origin) ->
@@ -271,6 +279,15 @@ liveopt_fun(Peer, Cause, Origin) ->
void
end.
+liveopt_guard_bif({#alarmInfo{cause=F}=R, X}=A) ->
+ %% ERIERL-48
+ if
+ is_tuple(F), tuple_size(F) == 2 -> A;
+ true ->
+ R2 = R#alarmInfo{cause={F}},
+ {R2,X}
+ end.
+
%% Thanks to QuickCheck.
coverage(_Config) ->
42+7 = merchant([[],7,false]),
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 263fd2ca7e..ca85eef688 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -32,7 +32,8 @@
bad_bin_match/1,bad_dsetel/1,
state_after_fault_in_catch/1,no_exception_in_catch/1,
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1,
- map_field_lists/1,cover_bin_opt/1]).
+ map_field_lists/1,cover_bin_opt/1,
+ val_dsetel/1]).
-include_lib("common_test/include/ct.hrl").
@@ -60,7 +61,7 @@ groups() ->
freg_state,bad_bin_match,bad_dsetel,
state_after_fault_in_catch,no_exception_in_catch,
undef_label,illegal_instruction,failing_gc_guard_bif,
- map_field_lists,cover_bin_opt]}].
+ map_field_lists,cover_bin_opt,val_dsetel]}].
init_per_suite(Config) ->
Config.
@@ -546,3 +547,23 @@ beam_val(M) ->
_ = [io:put_chars(beam_validator:format_error(E)) ||
E <- Errors],
Errors.
+
+%%%-------------------------------------------------------------------------
+
+val_dsetel(_Config) ->
+ self() ! 13,
+ {'EXIT',{{try_clause,participating},_}} = (catch night(0)),
+ ok.
+
+night(Turned) ->
+ receive
+ 13 ->
+ try participating of engine -> 16 after false end
+ end,
+ %% The setelement/3 call is unreachable.
+ Turned(setelement(#{true => Turned},
+ participating(Turned, "suit", 40, []),
+ Turned < Turned)),
+ ok.
+
+participating(_, _, _, _) -> ok.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 224abf6c29..a9bee888d9 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -38,7 +38,8 @@
no_partition/1,calling_a_binary/1,binary_in_map/1,
match_string_opt/1,select_on_integer/1,
map_and_binary/1,unsafe_branch_caching/1,
- bad_literals/1,good_literals/1,constant_propagation/1]).
+ bad_literals/1,good_literals/1,constant_propagation/1
+ ]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -768,6 +769,11 @@ multiple_uses(Config) when is_list(Config) ->
{344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
true = multiple_uses_2(<<0,0,197,18>>),
<<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1),
+
+ ok = first_after(<<>>, 42),
+ <<1>> = first_after(<<1,2,3>>, 0),
+ <<2>> = first_after(<<1,2,3>>, 1),
+
ok.
multiple_uses_1(<<X:16,Tail/binary>>) ->
@@ -789,6 +795,24 @@ multiple_uses_match(<<Y:16,Z:16>>) ->
multiple_uses_cmp(<<Y:16>>, <<Y:16>>) -> true;
multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false.
+first_after(Data, Offset) ->
+ case byte_size(Data) > Offset of
+ false ->
+ {First, Rest} = {ok, ok},
+ ok;
+ true ->
+ <<_:Offset/binary, Rest/binary>> = Data,
+ %% 'Rest' saved in y(0) before the call.
+ {First, _} = match_first(Data, Rest),
+ %% When beam_bsm sees the code, the following line
+ %% which uses y(0) has been optimized away.
+ {First, Rest} = {First, Rest},
+ First
+ end.
+
+match_first(_, <<First:1/binary, Rest/binary>>) ->
+ {First, Rest}.
+
zero_label(Config) when is_list(Config) ->
<<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>),
<<"CE">> = read_pols(<<"noFACE">>),
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 376d2c8e9a..ced0e39d06 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -26,7 +26,7 @@
unused_multiple_values_error/1,unused_multiple_values/1,
multiple_aliases/1,redundant_boolean_clauses/1,
mixed_matching_clauses/1,unnecessary_building/1,
- no_no_file/1]).
+ no_no_file/1,configuration/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -45,7 +45,7 @@ groups() ->
unused_multiple_values_error,unused_multiple_values,
multiple_aliases,redundant_boolean_clauses,
mixed_matching_clauses,unnecessary_building,
- no_no_file]}].
+ no_no_file,configuration]}].
init_per_suite(Config) ->
@@ -499,4 +499,16 @@ experiment() ->
end,
ok.
+
+%% Make sure we don't try to move a fun into a guard.
+configuration(_Config) ->
+ {'EXIT',_} = (catch configuration()),
+ ok.
+
+configuration() ->
+ [forgotten || Components <- enemy, is_tuple(fun art/0)].
+
+art() ->
+ creating.
+
id(I) -> I.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 6302f82f29..429d6b79e0 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -87,6 +87,7 @@ misc(Config) when is_list(Config) ->
{ok,buf,<<>>} = get_data({o,true,0}, 42, buf),
{ok,buf,<<>>} = get_data({o,false,0}, 0, buf),
error = get_data({o,false,0}, 42, buf),
+
ok.
@@ -343,6 +344,11 @@ complex_semicolon(Config) when is_list(Config) ->
ok = csemi7(#{a=>1}, 3, 3),
ok = csemi7(#{a=>1, b=>3}, 0, 0),
+ %% 8: Make sure that funs cannot be copied into guards.
+ ok = csemi8(true),
+ error = csemi8(false),
+ error = csemi8(42),
+
ok.
csemi1(Type, Val) when is_list(Val), Type == float;
@@ -457,6 +463,13 @@ csemi6(_, _) -> error.
csemi7(A, B, C) when A#{a:=B} > #{a=>1}; abs(C) > 2 -> ok;
csemi7(_, _, _) -> error.
+csemi8(Together) ->
+ case fun csemi8/1 of
+ Typically when Together; Typically, Together -> ok;
+ _ -> error
+ end.
+
+
comma(Config) when is_list(Config) ->
%% ',' combinations of literal true/false.
diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl
index 3cb49433ce..adb96fb87d 100644
--- a/lib/compiler/test/lc_SUITE.erl
+++ b/lib/compiler/test/lc_SUITE.erl
@@ -19,7 +19,7 @@
%%
-module(lc_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
basic/1,deeply_nested/1,no_generator/1,
@@ -32,11 +32,11 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,1}}].
-all() ->
+all() ->
test_lib:recompile(?MODULE),
[{group,p}].
-groups() ->
+groups() ->
[{p,test_lib:parallel(),
[basic,
deeply_nested,
@@ -214,6 +214,7 @@ shadow(Config) when is_list(Config) ->
ok.
effect(Config) when is_list(Config) ->
+ ct:timetrap({minutes,10}),
[{42,{a,b,c}}] =
do_effect(fun(F, L) ->
[F({V1,V2}) ||
@@ -240,7 +241,7 @@ do_effect(Lc, L) ->
lists:reverse(erase(?MODULE)).
id(I) -> I.
-
+
fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args,_}|_]}}) -> ok;
fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Arity,_}|_]}})
when length(Args) =:= Arity ->
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 31402ac717..127679ba69 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -24,7 +24,7 @@
pmatch/1,mixed/1,aliases/1,non_matching_aliases/1,
match_in_call/1,untuplify/1,shortcut_boolean/1,letify_guard/1,
selectify/1,underscore/1,match_map/1,map_vars_used/1,
- coverage/1,grab_bag/1]).
+ coverage/1,grab_bag/1,literal_binary/1]).
-include_lib("common_test/include/ct.hrl").
@@ -40,7 +40,7 @@ groups() ->
match_in_call,untuplify,
shortcut_boolean,letify_guard,selectify,
underscore,match_map,map_vars_used,coverage,
- grab_bag]}].
+ grab_bag,literal_binary]}].
init_per_suite(Config) ->
@@ -574,6 +574,15 @@ grab_bag_remove_failure([{stretch,_,Mi}=Stretch | Specs], Unit, _MaxFailure) ->
ok
end.
+%% Regression in 19.0, reported by Alexei Sholik
+literal_binary(_Config) ->
+ 3 = literal_binary_match(bar,<<"y">>),
+ ok.
+
+literal_binary_match(bar, <<"x">>) -> 1;
+literal_binary_match(_, <<"x">>) -> 2;
+literal_binary_match(_, <<"y">>) -> 3;
+literal_binary_match(_, _) -> fail.
id(I) -> I.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index f884e6e7d6..ff9bddc1e2 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -42,7 +42,7 @@
comprehensions/1,maps/1,maps_bin_opt_info/1,
redundant_boolean_clauses/1,
latin1_fallback/1,underscore/1,no_warnings/1,
- bit_syntax/1]).
+ bit_syntax/1,inlining/1]).
init_per_testcase(_Case, Config) ->
Config.
@@ -65,7 +65,7 @@ groups() ->
bin_opt_info,bin_construction,comprehensions,maps,
maps_bin_opt_info,
redundant_boolean_clauses,latin1_fallback,
- underscore,no_warnings,bit_syntax]}].
+ underscore,no_warnings,bit_syntax,inlining]}].
init_per_suite(Config) ->
Config.
@@ -823,6 +823,30 @@ bit_syntax(Config) ->
run(Config, Ts),
ok.
+inlining(Config) ->
+ %% Make sure that no spurious warnings are generated
+ %% when inlining.
+ Ts = [{inlining_1,
+ <<"-compile(inline).
+ compute1(X) -> add(X, 0).
+ add(1, 0) -> 1;
+ add(1, Y) -> 1 + Y;
+ add(X, Y) -> X + Y.
+ ">>,
+ [],
+ []},
+ {inlining_2,
+ <<"-compile({inline,[add/2]}).
+ compute1(X) -> add(X, 0).
+ add(1, 0) -> 1;
+ add(1, Y) -> 1 + Y;
+ add(X, Y) -> X + Y.
+ ">>,
+ [],
+ []}
+ ],
+ run(Config, Ts),
+ ok.
%%%
%%% End of test cases.
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 23dd4bd4b1..f3b9d3e9fd 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.0
+COMPILER_VSN = 7.0.4.1
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 7183c395ae..d4264335b6 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2017. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,9 @@
#include <openssl/opensslconf.h>
#include <openssl/crypto.h>
+#ifndef OPENSSL_NO_DES
#include <openssl/des.h>
+#endif /* #ifndef OPENSSL_NO_DES */
/* #include <openssl/idea.h> This is not supported on the openssl OTP requires */
#include <openssl/dsa.h>
#include <openssl/rsa.h>
@@ -48,14 +50,17 @@
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/objects.h>
-#include <openssl/rc4.h>
-#include <openssl/rc2.h>
+#ifndef OPENSSL_NO_RC4
+ #include <openssl/rc4.h>
+#endif /* OPENSSL_NO_RC4 */
+#ifndef OPENSSL_NO_RC2
+ #include <openssl/rc2.h>
+#endif
#include <openssl/blowfish.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
-
/* Helper macro to construct a OPENSSL_VERSION_NUMBER.
* See openssl/opensslv.h
*/
@@ -226,6 +231,7 @@ static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -296,6 +302,7 @@ static ErlNifFunc nif_funcs[] = {
{"hmac_final_nif", 2, hmac_final_nif},
{"block_crypt_nif", 5, block_crypt_nif},
{"block_crypt_nif", 4, block_crypt_nif},
+ {"aes_cfb_128_crypt_nif", 4, aes_cfb_128_crypt_nif},
{"aes_ige_crypt_nif", 4, aes_ige_crypt_nif},
{"aes_ctr_encrypt", 3, aes_ctr_encrypt},
@@ -320,7 +327,7 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_private_crypt", 4, rsa_private_crypt},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 3, dh_generate_key_nif},
+ {"dh_generate_key_nif", 4, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
{"srp_value_B_nif", 5, srp_value_B_nif},
{"srp_user_secret_nif", 7, srp_user_secret_nif},
@@ -458,16 +465,35 @@ struct cipher_type_t {
const size_t key_len; /* != 0 to also match on key_len */
};
+#ifdef OPENSSL_NO_DES
+#define COND_NO_DES_PTR(Ptr) (NULL)
+#else
+#define COND_NO_DES_PTR(Ptr) (Ptr)
+#endif
+
struct cipher_type_t cipher_types[] =
{
- {{"rc2_cbc"}, {&EVP_rc2_cbc}},
- {{"des_cbc"}, {&EVP_des_cbc}},
- {{"des_cfb"}, {&EVP_des_cfb8}},
- {{"des_ecb"}, {&EVP_des_ecb}},
- {{"des_ede3_cbc"}, {&EVP_des_ede3_cbc}},
- {{"des_ede3_cbf"},
+ {{"rc2_cbc"},
+#ifndef OPENSSL_NO_RC2
+ {&EVP_rc2_cbc}
+#else
+ {NULL}
+#endif
+ },
+ {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}},
+ {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}},
+ {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}},
+ {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}},
+ {{"des_ede3_cbf"}, /* Misspelled, retained */
+#ifdef HAVE_DES_ede3_cfb_encrypt
+ {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
+#else
+ {NULL}
+#endif
+ },
+ {{"des_ede3_cfb"},
#ifdef HAVE_DES_ede3_cfb_encrypt
- {&EVP_des_ede3_cfb8}
+ {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
#else
{NULL}
#endif
@@ -563,7 +589,7 @@ static void error_handler(void* null, const char* errstr)
}
#endif /* HAVE_DYNAMIC_CRYPTO_LIB */
-static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
+static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
#ifdef OPENSSL_THREADS
ErlNifSysInfo sys_info;
@@ -578,7 +604,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
char lib_buf[1000];
if (!verify_lib_version())
- return 0;
+ return __LINE__;
/* load_info: {301, <<"/full/path/of/this/library">>} */
if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)
@@ -588,7 +614,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
|| !enif_inspect_binary(env, tpl_array[1], &lib_bin)) {
PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info);
- return 0;
+ return __LINE__;
}
hmac_context_rtype = enif_open_resource_type(env, NULL, "hmac_context",
@@ -597,7 +623,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
NULL);
if (!hmac_context_rtype) {
PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'");
- return 0;
+ return __LINE__;
}
#if OPENSSL_VERSION_NUMBER >= OpenSSL_version_plain(1,0,0)
evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX",
@@ -606,7 +632,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
NULL);
if (!evp_md_ctx_rtype) {
PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_MD_CTX'");
- return 0;
+ return __LINE__;
}
#endif
#ifdef HAVE_EVP_AES_CTR
@@ -616,14 +642,14 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
NULL);
if (!evp_cipher_ctx_rtype) {
PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'");
- return 0;
+ return __LINE__;
}
#endif
if (library_refc > 0) {
/* Repeated loading of this library (module upgrade).
* Atoms and callbacks are already set, we are done.
*/
- return 1;
+ return 0;
}
atom_true = enif_make_atom(env,"true");
@@ -669,14 +695,14 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
void* handle;
if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) {
- return 0;
+ return __LINE__;
}
if (!(handle = enif_dlopen(lib_buf, &error_handler, NULL))) {
- return 0;
+ return __LINE__;
}
if (!(funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks",
&error_handler, NULL))) {
- return 0;
+ return __LINE__;
}
}
#else /* !HAVE_DYNAMIC_CRYPTO_LIB */
@@ -695,7 +721,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
if (!ccb || ccb->sizeof_me != sizeof(*ccb)) {
PRINTF_ERR0("Invalid 'crypto_callbacks'");
- return 0;
+ return __LINE__;
}
CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free);
@@ -709,13 +735,14 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
CRYPTO_set_dynlock_destroy_callback(ccb->dyn_destroy_function);
}
#endif /* OPENSSL_THREADS */
- return 1;
+ return 0;
}
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
- if (!init(env, load_info)) {
- return -1;
+ int errline = initialize(env, load_info);
+ if (errline) {
+ return errline;
}
*priv_data = NULL;
@@ -726,14 +753,16 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
ERL_NIF_TERM load_info)
{
+ int errline;
if (*old_priv_data != NULL) {
- return -1; /* Don't know how to do that */
+ return __LINE__; /* Don't know how to do that */
}
if (*priv_data != NULL) {
- return -1; /* Don't know how to do that */
+ return __LINE__; /* Don't know how to do that */
}
- if (!init(env, load_info)) {
- return -1;
+ errline = initialize(env, load_info);
+ if (errline) {
+ return errline;
}
library_refc++;
return 0;
@@ -749,7 +778,7 @@ static ERL_NIF_TERM algo_hash[8]; /* increase when extending the list */
static int algo_pubkey_cnt;
static ERL_NIF_TERM algo_pubkey[7]; /* increase when extending the list */
static int algo_cipher_cnt;
-static ERL_NIF_TERM algo_cipher[20]; /* increase when extending the list */
+static ERL_NIF_TERM algo_cipher[23]; /* increase when extending the list */
static void init_algorithms_types(ErlNifEnv* env)
{
@@ -785,10 +814,13 @@ static void init_algorithms_types(ErlNifEnv* env)
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
algo_cipher_cnt = 0;
+#ifndef OPENSSL_NO_DES
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbc");
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des_ede3");
#ifdef HAVE_DES_ede3_cfb_encrypt
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbf");
+ algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cfb");
+#endif
#endif
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc");
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc128");
@@ -800,14 +832,21 @@ static void init_algorithms_types(ErlNifEnv* env)
#ifdef HAVE_AES_IGE
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ige256");
#endif
+#ifndef OPENSSL_NO_DES
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cbc");
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cfb");
+ algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_ecb");
+#endif
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cbc");
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cfb64");
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ofb64");
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ecb");
+#ifndef OPENSSL_NO_RC2
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc2_cbc");
+#endif
+#ifndef OPENSSL_NO_RC4
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc4");
+#endif
#if defined(HAVE_GCM)
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_gcm");
#endif
@@ -1366,13 +1405,20 @@ static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return enif_raise_exception(env, atom_notsup);
}
- if ((argv[0] == atom_aes_cfb8 || argv[0] == atom_aes_cfb128)
+ if (argv[0] == atom_aes_cfb8
&& (key.size == 24 || key.size == 32)) {
/* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
* Fall back on low level API
*/
return aes_cfb_8_crypt(env, argc-1, argv+1);
}
+ else if (argv[0] == atom_aes_cfb128
+ && (key.size == 24 || key.size == 32)) {
+ /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
+ * Fall back on low level API
+ */
+ return aes_cfb_128_crypt_nif(env, argc-1, argv+1);
+ }
ivec_size = EVP_CIPHER_iv_length(cipher);
@@ -1446,6 +1492,31 @@ static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return ret;
}
+static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ AES_KEY aes_key;
+ unsigned char ivec_clone[16]; /* writable copy */
+ int new_ivlen = 0;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !(key.size == 16 || key.size == 24 || key.size == 32)
+ || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
+ return enif_make_badarg(env);
+ }
+
+ memcpy(ivec_clone, ivec.data, 16);
+ AES_set_encrypt_key(key.data, key.size * 8, &aes_key);
+ AES_cfb128_encrypt((unsigned char *) text.data,
+ enif_make_new_binary(env, text.size, &ret),
+ text.size, &aes_key, ivec_clone, &new_ivlen,
+ (argv[3] != atom_true));
+ CONSUME_REDS(env,text);
+ return ret;
+}
+
static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec, Data, IsEncrypt) */
#ifdef HAVE_AES_IGE
@@ -2141,7 +2212,7 @@ static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
DSA *dsa;
int i;
- if (!argv[0] == atom_sha
+ if (argv[0] != atom_sha
|| !enif_inspect_binary(env, argv[1], &digest_bin)
|| digest_bin.size != SHA_DIGEST_LENGTH
|| !enif_inspect_binary(env, argv[2], &sign_bin)
@@ -2306,6 +2377,7 @@ static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Data) */
+#ifndef OPENSSL_NO_RC4
ErlNifBinary key, data;
RC4_KEY rc4_key;
ERL_NIF_TERM ret;
@@ -2319,10 +2391,14 @@ static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
enif_make_new_binary(env, data.size, &ret));
CONSUME_REDS(env,data);
return ret;
-}
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+}
static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key) */
+#ifndef OPENSSL_NO_RC4
ErlNifBinary key;
ERL_NIF_TERM ret;
@@ -2332,11 +2408,14 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
RC4_set_key((RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &ret),
key.size, key.data);
return ret;
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
}
static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (State, Data) */
-
+#ifndef OPENSSL_NO_RC4
ErlNifBinary state, data;
RC4_KEY* rc4_key;
ERL_NIF_TERM new_state, new_data;
@@ -2352,7 +2431,10 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N
enif_make_new_binary(env, data.size, &new_data));
CONSUME_REDS(env,data);
return enif_make_tuple2(env,new_state,new_data);
-}
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+}
static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
{
@@ -2467,7 +2549,7 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
DSA* dsa;
int i;
- if (!argv[0] == atom_sha
+ if (argv[0] != atom_sha
|| !enif_inspect_binary(env, argv[1], &digest_bin)
|| digest_bin.size != SHA_DIGEST_LENGTH) {
return enif_make_badarg(env);
@@ -2678,12 +2760,13 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
}
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey, DHParams=[P,G], Mpint) */
+{/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */
DH* dh_params;
int pub_len, prv_len;
unsigned char *pub_ptr, *prv_ptr;
ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
int mpint; /* 0 or 4 */
+ unsigned long len = 0;
dh_params = DH_new();
@@ -2694,11 +2777,21 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
|| !enif_get_list_cell(env, tail, &head, &tail)
|| !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env, tail)
- || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) {
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)
+ || !enif_get_ulong(env, argv[3], &len) ) {
DH_free(dh_params);
return enif_make_badarg(env);
}
+ if (len) {
+ if (len < BN_num_bits(dh_params->p))
+ dh_params->length = len;
+ else {
+ DH_free(dh_params);
+ return enif_make_badarg(env);
+ }
+ }
+
if (DH_generate_key(dh_params)) {
pub_len = BN_num_bytes(dh_params->pub_key);
prv_len = BN_num_bytes(dh_params->priv_key);
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 5a5627747c..82e450ec21 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2016</year>
+ <year>1999</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -100,7 +100,7 @@
<code>dh_private() = key_value() </code>
- <code>dh_params() = [key_value()] = [P, G] </code>
+ <code>dh_params() = [key_value()] = [P, G] | [P, G, PrivateKeyBitLength]</code>
<code>ecdh_public() = key_value() </code>
@@ -136,7 +136,7 @@
<code>stream_cipher() = rc4 | aes_ctr </code>
<code>block_cipher() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ige256 | blowfish_cbc |
- blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | rc2_cbc </code>
+ blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc </code>
<code>aead_cipher() = aes_gcm | chacha20_poly1305 </code>
@@ -161,7 +161,7 @@
</p>
<code> cipher_algorithms() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ctr | aes_gcm |
aes_ige256 | blowfish_cbc | blowfish_cfb64 | chacha20_poly1305 | des_cbc | des_cfb |
- des3_cbc | des3_cbf | des_ede3 | rc2_cbc | rc4 </code>
+ des3_cbc | des3_cfb | des_ede3 | rc2_cbc | rc4 </code>
<code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh | ec_gf2m</code>
<p>Note that ec_gf2m is not strictly a public key algorithm, but a restriction on what curves are supported
with ecdsa and ecdh.
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 7d3a85326f..887aeca680 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,106 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 3.7.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a bug with AES CFB 128 for 192 and 256 bit keys.
+ Thanks to kellymclaughlin !</p>
+ <p>
+ Own Id: OTP-14313 Aux Id: PR-1393 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 3.7.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The implementation of the key exchange algorithms
+ diffie-hellman-group-exchange-sha* are optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest)
+ group size.</p>
+ <p>
+ Own Id: OTP-14169 Aux Id: seq-13261 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 3.7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The crypto application has been fixed to not use RC2
+ against OpenSSL built with RC2 disabled.</p>
+ <p>
+ Own Id: OTP-13895 Aux Id: PR-1163 </p>
+ </item>
+ <item>
+ <p>
+ The crypto application has been fixed to not use RC4
+ against OpenSSL built with RC4 disabled.</p>
+ <p>
+ Own Id: OTP-13896 Aux Id: PR-1169 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ To ease troubleshooting, <c>erlang:load_nif/2</c> now
+ includes the return value from a failed call to
+ load/reload/upgrade in the text part of the error tuple.
+ The <c>crypto</c> NIF makes use of this feature by
+ returning the source line where/if the initialization
+ fails.</p>
+ <p>
+ Own Id: OTP-13951</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 3.7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Crypto has been fixed to work against OpenSSL versions
+ with disabled DES ciphers. Correct spelling of cipher
+ algorithm 'des3_cfb' has been introduced; the previous
+ misspeling still works.</p>
+ <p>
+ Own Id: OTP-13783 Aux Id: ERL-203 </p>
+ </item>
+ <item>
+ <p>
+ The size of an internal array in crypto has been fixed to
+ not segfault when having all possible ciphers. Bug fix by
+ Duncan Overbruck.</p>
+ <p>
+ Own Id: OTP-13789 Aux Id: PR-1140 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 3.7</title>
<section><title>Improvements and New Features</title>
@@ -815,7 +915,7 @@
also been extended. </item><item> The <c>configure</c>
scripts of <c>erl_interface</c> and <c>odbc</c> now
search for thread libraries and thread library quirks the
- same way as <c>erts</c> do. </item><item> The
+ same way as ERTS do. </item><item> The
<c>configure</c> script of the <c>odbc</c> application
now also looks for odbc libraries in <c>lib64</c> and
<c>lib/64</c> directories when building on a 64-bit
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 025d57e9c5..60e0affda0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -274,13 +274,14 @@ hmac_final_n(Context, HashLen) ->
%% Ecrypt/decrypt %%%
-spec block_encrypt(des_cbc | des_cfb |
- des3_cbc | des3_cbf | des_ede3 |
+ des3_cbc | des3_cbf | des3_cfb | des_ede3 |
blowfish_cbc | blowfish_cfb64 | blowfish_ofb64 |
aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_cbc256 | aes_ige256 |
- aes_cbc |
+ aes_cbc |
rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary();
- (aes_gcm | chacha20_poly1305, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata()}) -> {binary(), binary()}.
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary();
+ (aes_gcm | chacha20_poly1305, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata()}) -> {binary(), binary()};
+ (aes_gcm, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata(), TagLength::1..16}) -> {binary(), binary()}.
block_encrypt(Type, Key, Ivec, Data) when Type =:= des_cbc;
Type =:= des_cfb;
@@ -301,6 +302,9 @@ block_encrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
block_encrypt(des3_cbf, Key0, Ivec, Data) ->
Key = check_des3_key(Key0),
block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, true);
+block_encrypt(des3_cfb, Key0, Ivec, Data) ->
+ Key = check_des3_key(Key0),
+ block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, true);
block_encrypt(aes_ige256, Key, Ivec, Data) ->
aes_ige_crypt_nif(Key, Ivec, Data, true);
block_encrypt(aes_gcm, Key, Ivec, {AAD, Data}) ->
@@ -311,7 +315,7 @@ block_encrypt(chacha20_poly1305, Key, Ivec, {AAD, Data}) ->
chacha20_poly1305_encrypt(Key, Ivec, AAD, Data).
-spec block_decrypt(des_cbc | des_cfb |
- des3_cbc | des3_cbf | des_ede3 |
+ des3_cbc | des3_cbf | des3_cfb | des_ede3 |
blowfish_cbc | blowfish_cfb64 | blowfish_ofb64 |
aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_cbc256 | aes_ige256 |
aes_cbc |
@@ -338,6 +342,9 @@ block_decrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
block_decrypt(des3_cbf, Key0, Ivec, Data) ->
Key = check_des3_key(Key0),
block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, false);
+block_decrypt(des3_cfb, Key0, Ivec, Data) ->
+ Key = check_des3_key(Key0),
+ block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, false);
block_decrypt(aes_ige256, Key, Ivec, Data) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
block_decrypt(aes_gcm, Key, Ivec, {AAD, Data, Tag}) ->
@@ -540,9 +547,15 @@ exor(Bin1, Bin2) ->
generate_key(Type, Params) ->
generate_key(Type, Params, undefined).
-generate_key(dh, DHParameters, PrivateKey) ->
+generate_key(dh, DHParameters0, PrivateKey) ->
+ {DHParameters, Len} =
+ case DHParameters0 of
+ [P,G,L] -> {[P,G], L};
+ [P,G] -> {[P,G], 0}
+ end,
dh_generate_key_nif(ensure_int_as_bin(PrivateKey),
- map_ensure_int_as_bin(DHParameters), 0);
+ map_ensure_int_as_bin(DHParameters),
+ 0, Len);
generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg)
when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) ->
@@ -809,6 +822,8 @@ sha_mac_96(Key, Data) -> hmac(sha, Key, Data, 12).
block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
block_crypt_nif(_Type, _Key, _Text, _IsEncrypt) -> ?nif_stub.
+aes_cfb_128_crypt_nif(_Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
+
check_des3_key(Key) ->
case lists:map(fun erlang:iolist_to_binary/1, Key) of
ValidKey = [B1, B2, B3] when byte_size(B1) =:= 8,
@@ -857,10 +872,10 @@ des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
binary().
des3_cfb_encrypt(Key1, Key2, Key3, IVec, Data) ->
- block_encrypt(des3_cbf, [Key1, Key2, Key3], IVec, Data).
+ block_encrypt(des3_cfb, [Key1, Key2, Key3], IVec, Data).
des3_cfb_decrypt(Key1, Key2, Key3, IVec, Data) ->
- block_decrypt(des3_cbf, [Key1, Key2, Key3], IVec, Data).
+ block_decrypt(des3_cfb, [Key1, Key2, Key3], IVec, Data).
%%
%% Blowfish
@@ -902,7 +917,9 @@ blowfish_ofb64_encrypt(Key, IVec, Data) ->
-spec aes_cfb_128_decrypt(iodata(), binary(), iodata()) -> binary().
aes_cfb_128_encrypt(Key, IVec, Data) ->
- block_encrypt(aes_cfb128, Key, IVec, Data).
+ %% block_encrypt(aes_cfb128, Key, IVec, Data).
+ aes_cfb_128_crypt_nif(Key, IVec, Data, true).
+
aes_cfb_128_decrypt(Key, IVec, Data) ->
block_decrypt(aes_cfb128, Key, IVec, Data).
@@ -1194,11 +1211,11 @@ dh_check([_Prime,_Gen]) -> ?nif_stub.
{binary(),binary()}.
dh_generate_key(DHParameters) ->
- dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4).
+ dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4, 0).
dh_generate_key(PrivateKey, DHParameters) ->
- dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4).
+ dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4, 0).
-dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub.
+dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint, _Length) -> ?nif_stub.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
%% MyPrivKey, OthersPublicKey = mpint()
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6732f27824..dbd335c693 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -50,6 +50,7 @@ all() ->
{group, des_cfb},
{group, des3_cbc},
{group, des3_cbf},
+ {group, des3_cfb},
{group, des_ede3},
{group, blowfish_cbc},
{group, blowfish_ecb},
@@ -94,6 +95,7 @@ groups() ->
{des3_cbc,[], [block]},
{des_ede3,[], [block]},
{des3_cbf,[], [block]},
+ {des3_cfb,[], [block]},
{rc2_cbc,[], [block]},
{aes_cbc128,[], [block]},
{aes_cfb8,[], [block]},
@@ -356,6 +358,16 @@ block_cipher({Type, Key, PlainText}) ->
ct:fail({{crypto, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}})
end;
+block_cipher({aes_cfb128, Key, IV, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ CipherText = crypto:aes_cfb_128_encrypt(Key, IV, PlainText),
+ case crypto:block_decrypt(aes_cfb128, Key, IV, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [aes_cfb128, Key, IV, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+
block_cipher({Type, Key, IV, PlainText}) ->
Plain = iolist_to_binary(PlainText),
CipherText = crypto:block_encrypt(Type, Key, IV, PlainText),
@@ -381,11 +393,8 @@ block_cipher({Type, Key, IV, PlainText, CipherText}) ->
ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other1}})
end.
-block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc;
- Type == des3_cbc;
- Type == aes_cbc;
- Type == des_cbf
- ->
+block_cipher_increment({Type, Key, IV, PlainTexts})
+ when Type == des_cbc; Type == aes_cbc; Type == des3_cbc ->
block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), []);
block_cipher_increment({Type, Key, IV, PlainTexts, _CipherText}) when Type == aes_cbc ->
Plain = iolist_to_binary(PlainTexts),
@@ -582,6 +591,8 @@ do_block_iolistify({des3_cbc = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({des3_cbf = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({des3_cfb = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({des_ede3 = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({Type, Key, PlainText}) ->
@@ -792,6 +803,9 @@ group_config(des3_cbc, Config) ->
group_config(des3_cbf, Config) ->
Block = des3_cbf(),
[{block, Block} | Config];
+group_config(des3_cfb, Config) ->
+ Block = des3_cfb(),
+ [{block, Block} | Config];
group_config(des_ede3, Config) ->
Block = des_ede3(),
[{block, Block} | Config];
@@ -1193,7 +1207,16 @@ des_ede3() ->
des3_cbf() ->
[{des3_cbf,
- [hexstr2bin("0123456789abcdef"),
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+des3_cfb() ->
+ [{des3_cfb,
+ [hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
hexstr2bin("0f2d4b6987a5c3e1")],
hexstr2bin("1234567890abcdef"),
diff --git a/lib/crypto/test/old_crypto_SUITE.erl b/lib/crypto/test/old_crypto_SUITE.erl
index 0d97290d10..324ed39c6d 100644
--- a/lib/crypto/test/old_crypto_SUITE.erl
+++ b/lib/crypto/test/old_crypto_SUITE.erl
@@ -58,6 +58,7 @@
des_cfb_iter/1,
des_ecb/1,
des3_cbc/1,
+ des3_cbf/1,
des3_cfb/1,
rc2_cbc/1,
aes_cfb/1,
@@ -102,7 +103,7 @@ groups() ->
hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
hmac_rfc4231_sha384, hmac_rfc4231_sha512,
des_cbc, aes_cfb, aes_cbc,
- des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
+ des_cfb, des_cfb_iter, des3_cbc, des3_cbf, des3_cfb, rc2_cbc,
aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
@@ -969,6 +970,9 @@ des_cbc(doc) ->
des_cbc(suite) ->
[];
des_cbc(Config) when is_list(Config) ->
+ if_supported(des_cbc, fun des_cbc_do/0).
+
+des_cbc_do() ->
?line Key = hexstr2bin("0123456789abcdef"),
?line IVec = hexstr2bin("1234567890abcdef"),
?line Plain = "Now is the time for all ",
@@ -992,6 +996,9 @@ des_cbc_iter(doc) ->
des_cbc_iter(suite) ->
[];
des_cbc_iter(Config) when is_list(Config) ->
+ if_supported(des_cbc, fun des_cbc_iter_do/0).
+
+des_cbc_iter_do() ->
?line Key = hexstr2bin("0123456789abcdef"),
?line IVec = hexstr2bin("1234567890abcdef"),
?line Plain1 = "Now is the time ",
@@ -1011,6 +1018,9 @@ des_cfb(doc) ->
des_cfb(suite) ->
[];
des_cfb(Config) when is_list(Config) ->
+ if_supported(des_cfb, fun des_cfb_do/0).
+
+des_cfb_do() ->
?line Key = hexstr2bin("0123456789abcdef"),
?line IVec = hexstr2bin("1234567890abcdef"),
?line Plain = "Now is the",
@@ -1027,6 +1037,9 @@ des_cfb_iter(doc) ->
des_cfb_iter(suite) ->
[];
des_cfb_iter(Config) when is_list(Config) ->
+ if_supported(des_cfb, fun des_cfb_iter_do/0).
+
+des_cfb_iter_do() ->
?line Key = hexstr2bin("0123456789abcdef"),
?line IVec = hexstr2bin("1234567890abcdef"),
?line Plain1 = "Now i",
@@ -1045,6 +1058,9 @@ des_ecb(doc) ->
des_ecb(suite) ->
[];
des_ecb(Config) when is_list(Config) ->
+ if_supported(des_ecb, fun des_ecb_do/0).
+
+des_ecb_do() ->
?line Key = hexstr2bin("0123456789abcdef"),
?line Cipher1 = crypto:des_ecb_encrypt(Key, "Now is t"),
?line m(Cipher1, hexstr2bin("3fa40e8a984d4815")),
@@ -1064,7 +1080,9 @@ rc2_cbc(doc) ->
"Encrypt and decrypt according to RC2 CBC and check the result. "
"Example stripped out from public_key application test";
rc2_cbc(Config) when is_list(Config) ->
-
+ if_supported(rc2_cbc, fun rc2_cbc_do/0).
+
+rc2_cbc_do() ->
Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
IV = <<72,91,135,182,25,42,35,210>>,
@@ -1081,6 +1099,9 @@ des3_cbc(doc) ->
des3_cbc(suite) ->
[];
des3_cbc(Config) when is_list(Config) ->
+ if_supported(des3_cbc, fun des3_cbc_do/0).
+
+des3_cbc_do() ->
?line Key1 = hexstr2bin("0123456789abcdef"),
?line Key2 = hexstr2bin("fedcba9876543210"),
?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
@@ -1112,6 +1133,19 @@ des3_cbc(Config) when is_list(Config) ->
%%
%%
+des3_cbf(doc) ->
+ "Encrypt and decrypt according to CFB 3DES, and check the result.";
+des3_cbf(suite) ->
+ [];
+des3_cbf(Config) when is_list(Config) ->
+ case openssl_version() of
+ V when V < 16#90705F -> {skipped,"OpenSSL version too old"};
+ _ ->
+ if_supported(des3_cbf, fun des3_cfb_do/0)
+ end.
+
+%%
+%%
des3_cfb(doc) ->
"Encrypt and decrypt according to CFB 3DES, and check the result.";
des3_cfb(suite) ->
@@ -1119,7 +1153,8 @@ des3_cfb(suite) ->
des3_cfb(Config) when is_list(Config) ->
case openssl_version() of
V when V < 16#90705F -> {skipped,"OpenSSL version too old"};
- _ -> des3_cfb_do()
+ _ ->
+ if_supported(des3_cfb, fun des3_cfb_do/0)
end.
des3_cfb_do() ->
@@ -2084,6 +2119,9 @@ rc4_test(doc) ->
rc4_test(suite) ->
[];
rc4_test(Config) when is_list(Config) ->
+ if_supported(rc4, fun rc4_test_do/0).
+
+rc4_test_do() ->
CT1 = <<"Yo baby yo">>,
R1 = <<118,122,68,110,157,166,141,212,139,39>>,
K = "apaapa",
@@ -2099,6 +2137,9 @@ rc4_stream_test(doc) ->
rc4_stream_test(suite) ->
[];
rc4_stream_test(Config) when is_list(Config) ->
+ if_supported(rc4, fun rc4_stream_test_do/0).
+
+rc4_stream_test_do() ->
CT1 = <<"Yo ">>,
CT2 = <<"baby yo">>,
K = "apaapa",
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 96466869d1..f3e0623ac9 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.7
+CRYPTO_VSN = 3.7.4
diff --git a/lib/debugger/doc/src/Makefile b/lib/debugger/doc/src/Makefile
index 6c9617ca69..0f724b6f17 100644
--- a/lib/debugger/doc/src/Makefile
+++ b/lib/debugger/doc/src/Makefile
@@ -114,7 +114,7 @@ release_docs_spec: docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- (/bin/cp -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ ($(CP) -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
diff --git a/lib/debugger/doc/src/i.xml b/lib/debugger/doc/src/i.xml
index db89f23494..628b91e9e4 100644
--- a/lib/debugger/doc/src/i.xml
+++ b/lib/debugger/doc/src/i.xml
@@ -45,7 +45,7 @@
attached manually or automatically.</p>
<p>By preference, these functions can be included in module
- <seealso marker="stdlib:shell_default"><c>stdlib:shell_default</c></seealso>.
+ <seealso marker="stdlib:shell_default"><c>shell_default</c></seealso>.
By default, they are included in that module.</p>
</description>
@@ -372,7 +372,7 @@
</fsummary>
<desc>
<p>Returns the current version number of the interpreter.
- Same as the version number of the <c>Debugger</c> application.</p>
+ Same as the version number of the Debugger application.</p>
</desc>
</func>
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index 2e0d834269..93bc46ddbe 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -33,6 +33,22 @@
<p>This document describes the changes made to the Debugger
application.</p>
+<section><title>Debugger 4.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Update build scripts to not make assumtions about where
+ env, cp and perl are located.</p>
+ <p>
+ Own Id: OTP-13800</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Debugger 4.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl
index 3561454685..3e959e8e30 100644
--- a/lib/debugger/src/dbg_iserver.erl
+++ b/lib/debugger/src/dbg_iserver.erl
@@ -214,7 +214,6 @@ handle_call({new_process, Pid, Meta, Function}, _From, State) ->
%% Code loading
handle_call({load, Mod, Src, Bin}, _From, State) ->
-
%% Create an ETS table for storing information about the module
Db = State#state.db,
ModDb = ets:new(Mod, [ordered_set, public]),
@@ -285,23 +284,28 @@ handle_call({contents, Mod, Pid}, _From, State) ->
{reply, {ok, Bin}, State};
handle_call({raw_contents, Mod, Pid}, _From, State) ->
Db = State#state.db,
- [{{Mod, refs}, ModDbs}] = ets:lookup(Db, {Mod, refs}),
- ModDb = if
- Pid =:= any -> hd(ModDbs);
- true ->
- lists:foldl(fun(T, not_found) ->
- [{T, Pids}] = ets:lookup(Db, T),
- case lists:member(Pid, Pids) of
- true -> T;
- false -> not_found
- end;
- (_T, T) -> T
- end,
- not_found,
- ModDbs)
- end,
- [{mod_raw, Bin}] = ets:lookup(ModDb, mod_raw),
- {reply, {ok, Bin}, State};
+ case ets:lookup(Db, {Mod, refs}) of
+ [{{Mod, refs}, ModDbs}] ->
+ ModDb =
+ if
+ Pid =:= any -> hd(ModDbs);
+ true ->
+ lists:foldl(fun(T, not_found) ->
+ [{T, Pids}] = ets:lookup(Db, T),
+ case lists:member(Pid, Pids) of
+ true -> T;
+ false -> not_found
+ end;
+ (_T, T) -> T
+ end,
+ not_found,
+ ModDbs)
+ end,
+ [{mod_raw, Bin}] = ets:lookup(ModDb, mod_raw),
+ {reply, {ok, Bin}, State};
+ [] -> % code not interpreted
+ {reply, not_found, State}
+ end;
handle_call({is_interpreted, Mod, Name, Arity}, _From, State) ->
Db = State#state.db,
Reply = case ets:lookup(Db, {Mod, refs}) of
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index 6af19af33b..29c8e8cefb 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -818,11 +818,14 @@ gui_show_module(Win, Mod, Line, _Cm, Pid, How) ->
gui_load_module(Win, Mod, _Pid) ->
dbg_wx_trace_win:display(Win,{text, "Loading module..."}),
- %% Contents = int:contents(Mod, Pid),
- {ok, Contents} = dbg_iserver:call({raw_contents, Mod, any}),
- Win2 = dbg_wx_trace_win:show_code(Win, Mod, Contents),
- dbg_wx_trace_win:display(Win,{text, ""}),
- Win2.
+ case dbg_iserver:call({raw_contents, Mod, any}) of
+ {ok, Contents} ->
+ Win2 = dbg_wx_trace_win:show_code(Win, Mod, Contents),
+ dbg_wx_trace_win:display(Win,{text, ""}),
+ Win2;
+ not_found ->
+ dbg_wx_trace_win:show_no_code(Win)
+ end.
gui_update_bindings(Win,Meta) ->
Bs = int:meta(Meta, bindings, nostack),
diff --git a/lib/debugger/src/dbg_wx_view.erl b/lib/debugger/src/dbg_wx_view.erl
index 91fc0d08cb..86d009238f 100644
--- a/lib/debugger/src/dbg_wx_view.erl
+++ b/lib/debugger/src/dbg_wx_view.erl
@@ -263,7 +263,11 @@ shortcut(_) -> false.
gui_load_module(Win, Mod) ->
dbg_wx_trace_win:display(Win,{text, "Loading module..."}),
- {ok, Contents} = dbg_iserver:call({raw_contents, Mod, any}),
- Win2 = dbg_wx_trace_win:show_code(Win, Mod, Contents),
- dbg_wx_trace_win:display(Win,{text, ""}),
- Win2.
+ case dbg_iserver:call({raw_contents, Mod, any}) of
+ {ok, Contents} ->
+ Win2 = dbg_wx_trace_win:show_code(Win, Mod, Contents),
+ dbg_wx_trace_win:display(Win,{text, ""}),
+ Win2;
+ not_found ->
+ dbg_wx_trace_win:show_no_code(Win)
+ end.
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index 25ffc5054c..d302423077 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index dd496013cd..f5440865ef 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 4.2
+DEBUGGER_VSN = 4.2.1
diff --git a/lib/dialyzer/RELEASE_NOTES b/lib/dialyzer/RELEASE_NOTES
index 4e311bb543..2457faa07a 100644
--- a/lib/dialyzer/RELEASE_NOTES
+++ b/lib/dialyzer/RELEASE_NOTES
@@ -135,7 +135,7 @@ Version 1.9.1 (in Erlang/OTP R13B)
Version 1.9.0 (in Erlang/OTP R13A)
----------------------------------
- The analysis accepts opaque type declarations and detects violations of
- opaqueness of terms of such types. Starting with R13, many Erlang/OTP
+ opacity of terms of such types. Starting with R13, many Erlang/OTP
standard libraries (array, dict, digraph, ets, gb_sets, gb_trees, queue,
and sets) contain opaque type declarations of their main data types.
Dialyzer will spit out warnings in code that explicitly depends on the
diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt
index be1fd2f8bc..a571cd2e2b 100644
--- a/lib/dialyzer/doc/manual.txt
+++ b/lib/dialyzer/doc/manual.txt
@@ -255,7 +255,7 @@ Warning options:
-Wno_match
Suppress warnings for patterns that are unused or cannot match.
-Wno_opaque
- Suppress warnings for violations of opaqueness of data types.
+ Suppress warnings for violations of opacity of data types.
-Wunmatched_returns ***
Include warnings for function calls which ignore a structured return
value or do not match against one of many possible return value(s).
diff --git a/lib/dialyzer/doc/src/book.xml b/lib/dialyzer/doc/src/book.xml
index aecc0e5bfa..46df8b81b8 100644
--- a/lib/dialyzer/doc/src/book.xml
+++ b/lib/dialyzer/doc/src/book.xml
@@ -25,7 +25,7 @@
<title>Dialyzer</title>
<prepared></prepared>
<docno></docno>
- <date></date>
+ <date>2016-09-19</date>
<rev></rev>
<file>book.xml</file>
</header>
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 619db125b1..4b7eb4ad68 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2006</year><year>2015</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -25,341 +25,477 @@
<title>dialyzer</title>
<prepared></prepared>
<docno></docno>
- <date></date>
+ <date>2016-09-20</date>
<rev></rev>
+ <file>dialyzer.xml</file>
</header>
<module>dialyzer</module>
- <modulesummary>The Dialyzer, a DIscrepancy AnalYZer for ERlang programs</modulesummary>
+ <modulesummary>Dialyzer, a DIscrepancy AnaLYZer for ERlang programs.
+ </modulesummary>
<description>
- <p>The Dialyzer is a static analysis tool that identifies software
- discrepancies such as definite type errors, code which has become
- dead or unreachable due to some programming error, unnecessary
- tests, etc. in single Erlang modules or entire (sets of)
- applications. Dialyzer starts its analysis from either
- debug-compiled BEAM bytecode or from Erlang source code. The file
- and line number of a discrepancy is reported along with an
- indication of what the discrepancy is about. Dialyzer bases its
- analysis on the concept of success typings which allows for sound
- warnings (no false positives).</p>
- <p>Read more about Dialyzer and about how to use it from the GUI
- in <seealso marker="dialyzer_chapter">Dialyzer User's
- Guide</seealso>.</p>
+ <p>Dialyzer is a static analysis tool that identifies software
+ discrepancies, such as definite type errors, code that has become dead
+ or unreachable because of programming error, and unnecessary tests,
+ in single Erlang modules or entire (sets of) applications.</p>
+
+ <p>Dialyzer starts its analysis from either
+ debug-compiled BEAM bytecode or from Erlang source code. The file
+ and line number of a discrepancy is reported along with an
+ indication of what the discrepancy is about. Dialyzer bases its
+ analysis on the concept of success typings, which allows for sound
+ warnings (no false positives).</p>
</description>
<section>
- <title>Using the Dialyzer from the command line</title>
- <p>Dialyzer also has a command line version for automated use. Below is a
- brief description of the list of its options. The same information can
- be obtained by writing</p>
- <code type="none">
- dialyzer --help</code>
- <p>in a shell. Please refer to the GUI description for more details on
- the operation of Dialyzer.</p>
- <p>The exit status of the command line version is:</p>
+ <marker id="command_line"></marker>
+ <title>Using Dialyzer from the Command Line</title>
+ <p>Dialyzer has a command-line version for automated use. This
+ section provides a brief description of the options. The same information
+ can be obtained by writing the following in a shell:</p>
+
<code type="none">
- 0 - No problems were encountered during the analysis and no
- warnings were emitted.
- 1 - Problems were encountered during the analysis.
- 2 - No problems were encountered, but warnings were emitted.</code>
- <p>Usage:</p>
+dialyzer --help</code>
+
+ <p>For more details about the operation of Dialyzer, see section
+ <seealso marker="dialyzer_chapter#dialyzer_gui">
+ Using Dialyzer from the GUI</seealso> in the User's Guide.</p>
+
+ <p><em>Exit status of the command-line version:</em></p>
+
+ <taglist>
+ <tag><c>0</c></tag>
+ <item>
+ <p>No problems were found during the analysis and no warnings were
+ emitted.</p>
+ </item>
+ <tag><c>1</c></tag>
+ <item>
+ <p>Problems were found during the analysis.</p>
+ </item>
+ <tag><c>2</c></tag>
+ <item>
+ <p>No problems were found during the analysis, but warnings were
+ emitted.</p>
+ </item>
+ </taglist>
+
+ <p><em>Usage:</em></p>
+
<code type="none">
- dialyzer [--help] [--version] [--shell] [--quiet] [--verbose]
- [-pa dir]* [--plt plt] [--plts plt*] [-Ddefine]*
- [-I include_dir]* [--output_plt file] [-Wwarn]* [--raw]
- [--src] [--gui] [files_or_dirs] [-r dirs]
- [--apps applications] [-o outfile]
- [--build_plt] [--add_to_plt] [--remove_from_plt]
- [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings]
- [--dump_callgraph file] [--no_native] [--fullpath]
- [--statistics] [--no_native_cache]</code>
- <p>Options:</p>
+dialyzer [--add_to_plt] [--apps applications] [--build_plt]
+ [--check_plt] [-Ddefine]* [-Dname] [--dump_callgraph file]
+ [files_or_dirs] [--fullpath] [--get_warnings] [--gui] [--help]
+ [-I include_dir]* [--no_check_plt] [--no_native]
+ [--no_native_cache] [-o outfile] [--output_plt file] [-pa dir]*
+ [--plt plt] [--plt_info] [--plts plt*] [--quiet] [-r dirs]
+ [--raw] [--remove_from_plt] [--shell] [--src] [--statistics]
+ [--verbose] [--version] [-Wwarn]*</code>
+
+ <note>
+ <p>* denotes that multiple occurrences of the option are possible.</p>
+ </note>
+
+ <p><em>Options:</em></p>
+
<taglist>
- <tag><c><![CDATA[files_or_dirs]]></c> (for backwards compatibility also
- as: <c><![CDATA[-c files_or_dirs]]></c>)</tag>
- <item>Use Dialyzer from the command line to detect defects in the
- specified files or directories containing <c><![CDATA[.erl]]></c> or
- <c><![CDATA[.beam]]></c> files, depending on the type of the
- analysis.</item>
- <tag><c><![CDATA[-r dirs]]></c></tag>
- <item>Same as the previous but the specified directories are searched
- recursively for subdirectories containing <c><![CDATA[.erl]]></c> or
- <c><![CDATA[.beam]]></c> files in them, depending on the type of
- analysis.</item>
- <tag><c><![CDATA[--apps applications]]></c></tag>
- <item>Option typically used when building or modifying a plt as in:
+ <tag><c>--add_to_plt</c></tag>
+ <item>
+ <p>The PLT is extended to also include the files specified with
+ <c>-c</c> and <c>-r</c>. Use
+ <c>--plt</c> to specify which PLT to start from,
+ and <c>--output_plt</c> to specify where to put the PLT.
+ Notice that the analysis possibly can include files from the PLT if
+ they depend on the new files. This option only works for BEAM
+ files.</p>
+ </item>
+ <tag><c>--apps applications</c></tag>
+ <item>
+ <p>This option is typically used when building or modifying a PLT as
+ in:</p>
<code type="none">
- dialyzer --build_plt --apps erts kernel stdlib mnesia ...</code>
- to conveniently refer to library applications corresponding to the
- Erlang/OTP installation. However, the option is general and can also
- be used during analysis in order to refer to Erlang/OTP applications.
- In addition, file or directory names can also be included, as in:
+dialyzer --build_plt --apps erts kernel stdlib mnesia ...</code>
+ <p>to refer conveniently to library applications corresponding to the
+ Erlang/OTP installation. However, this option is general and can also
+ be used during analysis to refer to Erlang/OTP applications.
+ File or directory names can also be included, as in:</p>
<code type="none">
- dialyzer --apps inets ssl ./ebin ../other_lib/ebin/my_module.beam</code></item>
- <tag><c><![CDATA[-o outfile]]></c> (or
- <c><![CDATA[--output outfile]]></c>)</tag>
- <item>When using Dialyzer from the command line, send the analysis
- results to the specified outfile rather than to stdout.</item>
- <tag><c><![CDATA[--raw]]></c></tag>
- <item>When using Dialyzer from the command line, output the raw analysis
- results (Erlang terms) instead of the formatted result. The raw format
- is easier to post-process (for instance, to filter warnings or to
- output HTML pages).</item>
- <tag><c><![CDATA[--src]]></c></tag>
- <item>Override the default, which is to analyze BEAM files, and
- analyze starting from Erlang source code instead.</item>
- <tag><c><![CDATA[-Dname]]></c> (or <c><![CDATA[-Dname=value]]></c>)</tag>
- <item>When analyzing from source, pass the define to Dialyzer. (**)</item>
- <tag><c><![CDATA[-I include_dir]]></c></tag>
- <item>When analyzing from source, pass the <c><![CDATA[include_dir]]></c>
- to Dialyzer. (**)</item>
- <tag><c><![CDATA[-pa dir]]></c></tag>
- <item>Include <c><![CDATA[dir]]></c> in the path for Erlang (useful when
- analyzing files that have <c><![CDATA['-include_lib()']]></c>
- directives).</item>
- <tag><c><![CDATA[--output_plt file]]></c></tag>
- <item>Store the plt at the specified file after building it.</item>
- <tag><c><![CDATA[--plt plt]]></c></tag>
- <item>Use the specified plt as the initial plt (if the plt was built
- during setup the files will be checked for consistency).</item>
- <tag><c><![CDATA[--plts plt*]]></c></tag>
- <item>Merge the specified plts to create the initial plt -- requires
- that the plts are disjoint (i.e., do not have any module
- appearing in more than one plt).
- The plts are created in the usual way:
+dialyzer --apps inets ssl ./ebin ../other_lib/ebin/my_module.beam</code>
+ </item>
+ <tag><c>--build_plt</c></tag>
+ <item>
+ <p>The analysis starts from an empty PLT and creates a new one from
+ the files specified with <c>-c</c> and
+ <c>-r</c>. This option only works for BEAM files.
+ To override the default PLT location, use
+ <c>--plt</c> or <c>--output_plt</c>.</p>
+ </item>
+ <tag><c>--check_plt</c></tag>
+ <item>
+ <p>Check the PLT for consistency and rebuild it if it is not
+ up-to-date.</p>
+ </item>
+ <tag><c>-Dname</c> (or <c>-Dname=value</c>)</tag>
+ <item>
+ <p>When analyzing from source, pass the define to Dialyzer.
+ (**)</p>
+ </item>
+ <tag><c>--dump_callgraph file</c></tag>
+ <item>
+ <p>Dump the call graph into the specified file whose format is
+ determined by the filename extension. Supported extensions are:
+ <c>raw</c>, <c>dot</c>, and <c>ps</c>. If something else is used as
+ filename extension, default format <c>.raw</c> is used.</p>
+ </item>
+ <tag><c>files_or_dirs</c> (for backward compatibility also
+ as <c>-c files_or_dirs</c>)</tag>
+ <item>
+ <p>Use Dialyzer from the command line to detect defects in the
+ specified files or directories containing <c>.erl</c> or
+ <c>.beam</c> files, depending on the type of the
+ analysis.</p>
+ </item>
+ <tag><c>--fullpath</c></tag>
+ <item>
+ <p>Display the full path names of files for which warnings are
+ emitted.</p>
+ </item>
+ <tag><c>--get_warnings</c></tag>
+ <item>
+ <p>Make Dialyzer emit warnings even when manipulating the PLT.
+ Warnings are only emitted for files that are analyzed.</p>
+ </item>
+ <tag><c>--gui</c></tag>
+ <item>
+ <p>Use the GUI.</p></item>
+ <tag><c>--help</c> (or <c>-h</c>)</tag>
+ <item>
+ <p>Print this message and exit.</p>
+ </item>
+ <tag><c>-I include_dir</c></tag>
+ <item>
+ <p>When analyzing from source, pass the <c>include_dir</c>
+ to Dialyzer. (**)</p>
+ </item>
+ <tag><c>--no_check_plt</c></tag>
+ <item>
+ <p>Skip the PLT check when running Dialyzer. This is useful when
+ working with installed PLTs that never change.</p>
+ </item>
+ <tag><c>--no_native</c> (or <c>-nn</c>)</tag>
+ <item>
+ <p>Bypass the native code compilation of some key files that
+ Dialyzer heuristically performs when dialyzing many files.
+ This avoids the compilation time, but can result in (much) longer
+ analysis time.</p>
+ </item>
+ <tag><c>--no_native_cache</c></tag>
+ <item>
+ <p>By default, Dialyzer caches the results of native compilation
+ in directory <c>$XDG_CACHE_HOME/erlang/dialyzer_hipe_cache</c>.
+ <c>XDG_CACHE_HOME</c> defaults to <c>$HOME/.cache</c>.
+ Use this option to disable caching.</p>
+ </item>
+ <tag><c>-o outfile</c> (or
+ <c>--output outfile</c>)</tag>
+ <item>
+ <p>When using Dialyzer from the command line, send the analysis
+ results to the specified outfile rather than to <c>stdout</c>.</p>
+ </item>
+ <tag><c>--output_plt file</c></tag>
+ <item>
+ <p>Store the PLT at the specified file after building it.</p>
+ </item>
+ <tag><c>-pa dir</c></tag>
+ <item>
+ <p>Include <c>dir</c> in the path for Erlang. This is useful
+ when analyzing files that have <c>-include_lib()</c>
+ directives.</p>
+ </item>
+ <tag><c>--plt plt</c></tag>
+ <item>
+ <p>Use the specified PLT as the initial PLT. If the PLT was built
+ during setup, the files are checked for consistency.</p>
+ </item>
+ <tag><c>--plt_info</c></tag>
+ <item>
+ <p>Make Dialyzer print information about the PLT and then quit.
+ The PLT can be specified with <c>--plt(s)</c>.</p>
+ </item>
+ <tag><c>--plts plt*</c></tag>
+ <item>
+ <p>Merge the specified PLTs to create the initial PLT. This requires
+ that the PLTs are disjoint (that is, do not have any module
+ appearing in more than one PLT).
+ The PLTs are created in the usual way:</p>
<code type="none">
- dialyzer --build_plt --output_plt plt_1 files_to_include
- ...
- dialyzer --build_plt --output_plt plt_n files_to_include</code>
- and then can be used in either of the following ways:
+dialyzer --build_plt --output_plt plt_1 files_to_include
+...
+dialyzer --build_plt --output_plt plt_n files_to_include</code>
+ <p>They can then be used in either of the following ways:</p>
<code type="none">
- dialyzer files_to_analyze --plts plt_1 ... plt_n</code>
- or:
+dialyzer files_to_analyze --plts plt_1 ... plt_n</code>
+ <p>or</p>
<code type="none">
- dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code>
- (Note the -- delimiter in the second case)</item>
- <tag><c><![CDATA[-Wwarn]]></c></tag>
- <item>A family of options which selectively turn on/off warnings
- (for help on the names of warnings use
- <c><![CDATA[dialyzer -Whelp]]></c>).
- Note that the options can also be given in the file with a
- <c>-dialyzer()</c> attribute. See <seealso
- marker="#suppression">Requesting or Suppressing Warnings in
- Source Files</seealso> below for details.</item>
- <tag><c><![CDATA[--shell]]></c></tag>
- <item>Do not disable the Erlang shell while running the GUI.</item>
- <tag><c><![CDATA[--version]]></c> (or <c><![CDATA[-v]]></c>)</tag>
- <item>Print the Dialyzer version and some more information and
- exit.</item>
- <tag><c><![CDATA[--help]]></c> (or <c><![CDATA[-h]]></c>)</tag>
- <item>Print this message and exit.</item>
- <tag><c><![CDATA[--quiet]]></c> (or <c><![CDATA[-q]]></c>)</tag>
- <item>Make Dialyzer a bit more quiet.</item>
- <tag><c><![CDATA[--verbose]]></c></tag>
- <item>Make Dialyzer a bit more verbose.</item>
- <tag><c><![CDATA[--statistics]]></c></tag>
- <item>Prints information about the progress of execution (analysis phases,
- time spent in each and size of the relative input).</item>
- <tag><c><![CDATA[--build_plt]]></c></tag>
- <item>The analysis starts from an empty plt and creates a new one from
- the files specified with <c><![CDATA[-c]]></c> and
- <c><![CDATA[-r]]></c>. Only works for beam files. Use
- <c><![CDATA[--plt]]></c> or <c><![CDATA[--output_plt]]></c> to
- override the default plt location.</item>
- <tag><c><![CDATA[--add_to_plt]]></c></tag>
- <item>The plt is extended to also include the files specified with
- <c><![CDATA[-c]]></c> and <c><![CDATA[-r]]></c>. Use
- <c><![CDATA[--plt]]></c> to specify which plt to start from,
- and <c><![CDATA[--output_plt]]></c> to specify where to put the plt.
- Note that the analysis might include files from the plt if they depend
- on the new files. This option only works with beam files.</item>
- <tag><c><![CDATA[--remove_from_plt]]></c></tag>
- <item>The information from the files specified with
- <c><![CDATA[-c]]></c> and <c><![CDATA[-r]]></c> is removed
- from the plt. Note that this may cause a re-analysis of the remaining
- dependent files.</item>
- <tag><c><![CDATA[--check_plt]]></c></tag>
- <item>Check the plt for consistency and rebuild it if it is not
- up-to-date.</item>
- <tag><c><![CDATA[--no_check_plt]]></c></tag>
- <item>Skip the plt check when running Dialyzer. Useful when working with
- installed plts that never change.</item>
- <tag><c><![CDATA[--plt_info]]></c></tag>
- <item>Make Dialyzer print information about the plt and then quit. The
- plt can be specified with <c><![CDATA[--plt(s)]]></c>.</item>
- <tag><c><![CDATA[--get_warnings]]></c></tag>
- <item>Make Dialyzer emit warnings even when manipulating the plt.
- Warnings are only emitted for files that are actually analyzed.</item>
- <tag><c><![CDATA[--dump_callgraph file]]></c></tag>
- <item>Dump the call graph into the specified file whose format is
- determined by the file name extension. Supported extensions are: raw,
- dot, and ps. If something else is used as file name extension, default
- format '.raw' will be used.</item>
- <tag><c><![CDATA[--no_native]]></c> (or <c><![CDATA[-nn]]></c>)</tag>
- <item>Bypass the native code compilation of some key files that Dialyzer
- heuristically performs when dialyzing many files; this avoids the
- compilation time but it may result in (much) longer analysis
- time.</item>
- <tag><c><![CDATA[--no_native_cache]]></c></tag>
- <item>By default, Dialyzer caches the results of native compilation in the
- <c>$XDG_CACHE_HOME/erlang/dialyzer_hipe_cache</c> directory.
- <c>XDG_CACHE_HOME</c> defaults to <c>$HOME/.cache</c>.
- Use this option to disable caching.</item>
- <tag><c><![CDATA[--fullpath]]></c></tag>
- <item>Display the full path names of files for which warnings are emitted.</item>
- <tag><c><![CDATA[--gui]]></c></tag>
- <item>Use the GUI.</item>
+dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code>
+ <p>Notice the <c>--</c> delimiter in the second case.</p>
+ </item>
+ <tag><c>--quiet</c> (or <c>-q</c>)</tag>
+ <item>
+ <p>Make Dialyzer a bit more quiet.</p>
+ </item>
+ <tag><c>-r dirs</c></tag>
+ <item>
+ <p>Same as <c>files_or_dirs</c>, but the specified
+ directories are searched
+ recursively for subdirectories containing <c>.erl</c> or
+ <c>.beam</c> files in them, depending on the type of
+ analysis.</p>
+ </item>
+ <tag><c>--raw</c></tag>
+ <item>
+ <p>When using Dialyzer from the command line, output the raw
+ analysis results (Erlang terms) instead of the formatted result.
+ The raw format
+ is easier to post-process (for example, to filter warnings or to
+ output HTML pages).</p>
+ </item>
+ <tag><c>--remove_from_plt</c></tag>
+ <item>
+ <p>The information from the files specified with
+ <c>-c</c> and <c>-r</c> is removed from
+ the PLT. Notice that this can cause a reanalysis of the remaining
+ dependent files.</p>
+ </item>
+ <tag><c>--shell</c></tag>
+ <item>
+ <p>Do not disable the Erlang shell while running the GUI.</p>
+ </item>
+ <tag><c>--src</c></tag>
+ <item>
+ <p>Override the default, which is to analyze BEAM files, and
+ analyze starting from Erlang source code instead.</p>
+ </item>
+ <tag><c>--statistics</c></tag>
+ <item>
+ <p>Print information about the progress of execution (analysis phases,
+ time spent in each, and size of the relative input).</p>
+ </item>
+ <tag><c>--verbose</c></tag>
+ <item>
+ <p>Make Dialyzer a bit more verbose.</p>
+ </item>
+ <tag><c>--version</c> (or <c>-v</c>)</tag>
+ <item>
+ <p>Print the Dialyzer version and some more information and
+ exit.</p>
+ </item>
+ <tag><c>-Wwarn</c></tag>
+ <item>
+ <p>A family of options that selectively turn on/off warnings.
+ (For help on the names of warnings, use
+ <c>dialyzer -Whelp</c>.)
+ Notice that the options can also be specified in the file with a
+ <c>-dialyzer()</c> attribute. For details, see section <seealso
+ marker="#suppression">Requesting or Suppressing Warnings in
+ Source Files</seealso>.</p>
+ </item>
</taglist>
+
<note>
- <p>* denotes that multiple occurrences of these options are possible.</p>
- <p>** options <c><![CDATA[-D]]></c> and <c><![CDATA[-I]]></c> work both from command-line and in the Dialyzer GUI;
- the syntax of defines and includes is the same as that used by <c><![CDATA[erlc]]></c>.</p>
+ <p>** options <c>-D</c> and <c>-I</c> work both
+ from the command line and in the Dialyzer GUI; the syntax of
+ defines and includes is the same as that used by
+ <seealso marker="erts:erlc">erlc(1)</seealso>.</p>
</note>
- <p>Warning options:</p>
+
+ <p><em>Warning options:</em></p>
+
<taglist>
- <tag><c><![CDATA[-Wno_return]]></c></tag>
- <item>Suppress warnings for functions that will never return a
- value.</item>
- <tag><c><![CDATA[-Wno_unused]]></c></tag>
- <item>Suppress warnings for unused functions.</item>
- <tag><c><![CDATA[-Wno_improper_lists]]></c></tag>
- <item>Suppress warnings for construction of improper lists.</item>
- <tag><c><![CDATA[-Wno_fun_app]]></c></tag>
- <item>Suppress warnings for fun applications that will fail.</item>
- <tag><c><![CDATA[-Wno_match]]></c></tag>
- <item>Suppress warnings for patterns that are unused or cannot
- match.</item>
- <tag><c><![CDATA[-Wno_opaque]]></c></tag>
- <item>Suppress warnings for violations of opaqueness of data types.</item>
- <tag><c><![CDATA[-Wno_fail_call]]></c></tag>
- <item>Suppress warnings for failing calls.</item>
- <tag><c><![CDATA[-Wno_contracts]]></c></tag>
- <item>Suppress warnings about invalid contracts.</item>
- <tag><c><![CDATA[-Wno_behaviours]]></c></tag>
- <item>Suppress warnings about behaviour callbacks which drift from the
- published recommended interfaces.</item>
- <tag><c><![CDATA[-Wno_missing_calls]]></c></tag>
- <item>Suppress warnings about calls to missing functions.</item>
- <tag><c><![CDATA[-Wno_undefined_callbacks]]></c></tag>
- <item>Suppress warnings about behaviours that have no
- <c>-callback</c> attributes for their callbacks.</item>
- <tag><c><![CDATA[-Wunmatched_returns]]></c>***</tag>
- <item>Include warnings for function calls which ignore a structured return
- value or do not match against one of many possible return
- value(s).</item>
- <tag><c><![CDATA[-Werror_handling]]></c>***</tag>
- <item>Include warnings for functions that only return by means of an
- exception.</item>
- <tag><c><![CDATA[-Wrace_conditions]]></c>***</tag>
- <item>Include warnings for possible race conditions. Note that the
- analysis that finds data races performs intra-procedural data flow analysis
- and can sometimes explode in time. Enable it at your own risk.
- </item>
- <tag><c><![CDATA[-Wunderspecs]]></c>***</tag>
- <item>Warn about underspecified functions
- (the -spec is strictly more allowing than the success typing).</item>
- <tag><c><![CDATA[-Wunknown]]></c>***</tag>
- <item>Let warnings about unknown functions and types affect the
- exit status of the command line version. The default is to ignore
- warnings about unknown functions and types when setting the exit
- status. When using the Dialyzer from Erlang, warnings about unknown
- functions and types are returned; the default is not to return
- these warnings.</item>
+ <tag><c>-Werror_handling</c> (***)</tag>
+ <item>
+ <p>Include warnings for functions that only return by an exception.</p>
+ </item>
+ <tag><c>-Wno_behaviours</c></tag>
+ <item>
+ <p>Suppress warnings about behavior callbacks that drift from the
+ published recommended interfaces.</p>
+ </item>
+ <tag><c>-Wno_contracts</c></tag>
+ <item>
+ <p>Suppress warnings about invalid contracts.</p>
+ </item>
+ <tag><c>-Wno_fail_call</c></tag>
+ <item>
+ <p>Suppress warnings for failing calls.</p>
+ </item>
+ <tag><c>-Wno_fun_app</c></tag>
+ <item>
+ <p>Suppress warnings for fun applications that will fail.</p>
+ </item>
+ <tag><c>-Wno_improper_lists</c></tag>
+ <item>
+ <p>Suppress warnings for construction of improper lists.</p>
+ </item>
+ <tag><c>-Wno_match</c></tag>
+ <item>
+ <p>Suppress warnings for patterns that are unused or cannot match.</p>
+ </item>
+ <tag><c>-Wno_missing_calls</c></tag>
+ <item>
+ <p>Suppress warnings about calls to missing functions.</p>
+ </item>
+ <tag><c>-Wno_opaque</c></tag>
+ <item>
+ <p>Suppress warnings for violations of opacity of data types.</p>
+ </item>
+ <tag><c>-Wno_return</c></tag>
+ <item>
+ <p>Suppress warnings for functions that will never return a value.</p>
+ </item>
+ <tag><c>-Wno_undefined_callbacks</c></tag>
+ <item>
+ <p>Suppress warnings about behaviors that have no
+ <c>-callback</c> attributes for their callbacks.</p>
+ </item>
+ <tag><c>-Wno_unused</c></tag>
+ <item>
+ <p>Suppress warnings for unused functions.</p>
+ </item>
+ <tag><c>-Wrace_conditions</c> (***)</tag>
+ <item>
+ <p>Include warnings for possible race conditions. Notice that the
+ analysis that finds data races performs intra-procedural data flow
+ analysis and can sometimes explode in time. Enable it at your own
+ risk.</p>
+ </item>
+ <tag><c>-Wunderspecs</c> (***)</tag>
+ <item>
+ <p>Warn about underspecified functions (the specification is strictly
+ more allowing than the success typing).</p>
+ </item>
+ <tag><c>-Wunknown</c> (***)</tag>
+ <item>
+ <p>Let warnings about unknown functions and types affect the
+ exit status of the command-line version. The default is to ignore
+ warnings about unknown functions and types when setting the exit
+ status. When using Dialyzer from Erlang, warnings about unknown
+ functions and types are returned; the default is not to return
+ these warnings.</p>
+ </item>
+ <tag><c>-Wunmatched_returns</c> (***)</tag>
+ <item>
+ <p>Include warnings for function calls that ignore a structured return
+ value or do not match against one of many possible return
+ value(s).</p>
+ </item>
</taglist>
- <p>The following options are also available but their use is not
- recommended: (they are mostly for Dialyzer developers and internal
- debugging)</p>
+
+ <p>The following options are also available, but their use is not
+ recommended (they are mostly for Dialyzer developers and internal
+ debugging):</p>
+
<taglist>
- <tag><c><![CDATA[-Woverspecs]]></c>***</tag>
- <item>Warn about overspecified functions
- (the -spec is strictly less allowing than the success typing).</item>
- <tag><c><![CDATA[-Wspecdiffs]]></c>***</tag>
- <item>Warn when the -spec is different than the success typing.</item>
+ <tag><c>-Woverspecs</c> (***)</tag>
+ <item>
+ <p>Warn about overspecified functions (the specification is strictly
+ less allowing than the success typing).</p>
+ </item>
+ <tag><c>-Wspecdiffs</c> (***)</tag>
+ <item>
+ <p>Warn when the specification is different than the success typing.</p>
+ </item>
</taglist>
+
<note>
- <p>*** Identifies options that turn on warnings rather than
- turning them off.</p>
+ <p>*** denotes options that turn on warnings rather than
+ turning them off.</p>
</note>
</section>
<section>
- <title>Using the Dialyzer from Erlang</title>
- <p>You can also use Dialyzer directly from Erlang. Both the GUI and the
- command line versions are available. The options are similar to the ones
- given from the command line, so please refer to the sections above for
- a description of these.</p>
+ <title>Using Dialyzer from Erlang</title>
+ <p>Dialyzer can be used directly from Erlang. Both the GUI and the
+ command-line versions are also available. The options are similar to the
+ ones given from the command line, see section
+ <seealso marker="#command_line">
+ Using Dialyzer from the Command Line</seealso>.</p>
</section>
<section>
<marker id="suppression"></marker>
<title>Requesting or Suppressing Warnings in Source Files</title>
- <p>
- The <c>-dialyzer()</c> attribute can be used for turning off
+ <p>Attribute <c>-dialyzer()</c> can be used for turning off
warnings in a module by specifying functions or warning options.
For example, to turn off all warnings for the function
- <c>f/0</c>, include the following line:
- </p>
-<code type="none">
--dialyzer({nowarn_function, f/0}).
-</code>
+ <c>f/0</c>, include the following line:</p>
+
+ <code type="none">
+-dialyzer({nowarn_function, f/0}).</code>
+
<p>To turn off warnings for improper lists, add the following line
- to the source file:
- </p>
-<code type="none">
--dialyzer(no_improper_lists).
-</code>
- <p>The <c>-dialyzer()</c> attribute is allowed after function
- declarations. Lists of warning options or functions are allowed:
- </p>
-<code type="none">
--dialyzer([{nowarn_function, [f/0]}, no_improper_lists]).
-</code>
- <p>
- Warning options can be restricted to functions:
- </p>
-<code type="none">
--dialyzer({no_improper_lists, g/0}).
-</code>
-<code type="none">
--dialyzer({[no_return, no_match], [g/0, h/0]}).
-</code>
- <p>
- For help on the warning options use <c>dialyzer -Whelp</c>. The
- options are also enumerated <seealso
- marker="#gui/1">below</seealso> (<c>WarnOpts</c>).
- </p>
+ to the source file:</p>
+
+ <code type="none">
+-dialyzer(no_improper_lists).</code>
+
+ <p>Attribute <c>-dialyzer()</c> is allowed after function
+ declarations. Lists of warning options or functions are allowed:</p>
+
+ <code type="none">
+-dialyzer([{nowarn_function, [f/0]}, no_improper_lists]).</code>
+
+ <p>Warning options can be restricted to functions:</p>
+
+ <code type="none">
+-dialyzer({no_improper_lists, g/0}).</code>
+
+ <code type="none">
+-dialyzer({[no_return, no_match], [g/0, h/0]}).</code>
+
+ <p>For help on the warning options, use <c>dialyzer -Whelp</c>. The
+ options are also enumerated, see function <seealso marker="#gui/1">
+ <c>gui/1</c></seealso> below (<c>WarnOpts</c>).</p>
+
<note>
- <p>
- The <c>-dialyzer()</c> attribute is not checked by the Erlang
- Compiler, but by the Dialyzer itself.
- </p>
+ <p>Attribute <c>-dialyzer()</c> is not checked by the Erlang
+ compiler, but by Dialyzer itself.</p>
</note>
+
<note>
- <p>
- The warning option <c>-Wrace_conditions</c> has no effect when
- set in source files.
- </p>
+ <p>Warning option <c>-Wrace_conditions</c> has no effect when
+ set in source files.</p>
</note>
- <p>
- The <c>-dialyzer()</c> attribute can also be used for turning on
- warnings. For instance, if a module has been fixed regarding
- unmatched returns, adding the line
- </p>
-<code type="none">
--dialyzer(unmatched_returns).
-</code>
- <p>
- can help in assuring that no new unmatched return warnings are
- introduced.
- </p>
+
+ <p>Attribute <c>-dialyzer()</c> can also be used for turning on
+ warnings. For example, if a module has been fixed regarding
+ unmatched returns, adding the following line can help in assuring
+ that no new unmatched return warnings are introduced:</p>
+
+ <code type="none">
+-dialyzer(unmatched_returns).</code>
</section>
<funcs>
<func>
+ <name>format_warning(Msg) -> string()</name>
+ <fsummary>Get the string version of a warning message.</fsummary>
+ <type>
+ <v>Msg = {Tag, Id, msg()}</v>
+ <d>See <c>run/1</c>.</d>
+ </type>
+ <desc>
+ <p>Get a string from warnings as returned by
+ <seealso marker="#run/1"><c>run/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
<name>gui() -> ok | {error, Msg}</name>
<name>gui(OptList) -> ok | {error, Msg}</name>
- <fsummary>Dialyzer GUI version</fsummary>
+ <fsummary>Dialyzer GUI version.</fsummary>
<type>
- <v>OptList -- see below</v>
+ <v>OptList</v>
+ <d>See below.</d>
</type>
<desc>
<p>Dialyzer GUI version.</p>
@@ -368,9 +504,12 @@ OptList :: [Option]
Option :: {files, [Filename :: string()]}
| {files_rec, [DirName :: string()]}
| {defines, [{Macro :: atom(), Value :: term()}]}
- | {from, src_code | byte_code} %% Defaults to byte_code
- | {init_plt, FileName :: string()} %% If changed from default
- | {plts, [FileName :: string()]} %% If changed from default
+ | {from, src_code | byte_code}
+ %% Defaults to byte_code
+ | {init_plt, FileName :: string()}
+ %% If changed from default
+ | {plts, [FileName :: string()]}
+ %% If changed from default
| {include_dirs, [DirName :: string()]}
| {output_file, FileName :: string()}
| {output_plt, FileName :: string()}
@@ -383,76 +522,71 @@ Option :: {files, [Filename :: string()]}
| {warnings, [WarnOpts]}
| {get_warnings, bool()}
-WarnOpts :: no_return
- | no_unused
- | no_improper_lists
+WarnOpts :: error_handling
+ | no_behaviours
+ | no_contracts
+ | no_fail_call
| no_fun_app
+ | no_improper_lists
| no_match
+ | no_missing_calls
| no_opaque
- | no_fail_call
- | no_contracts
- | no_behaviours
+ | no_return
| no_undefined_callbacks
- | unmatched_returns
- | error_handling
+ | no_unused
| race_conditions
- | overspecs
| underspecs
- | specdiffs
- | unknown</code>
+ | unknown
+ | unmatched_returns
+ | overspecs
+ | specdiffs</code>
</desc>
</func>
+
<func>
- <name>run(OptList) -> Warnings</name>
- <fsummary>Dialyzer command line version</fsummary>
- <type>
- <v>OptList -- see gui/0,1</v>
- <v>Warnings -- see below </v>
- </type>
+ <name>plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()}</name>
+ <fsummary>Return information about the specified PLT.</fsummary>
<desc>
- <p>Dialyzer command line version.</p>
- <code type="none">
-Warnings :: [{Tag, Id, Msg}]
-Tag :: 'warn_behaviour'
- | 'warn_bin_construction'
- | 'warn_callgraph'
- | 'warn_contract_not_equal'
- | 'warn_contract_range'
- | 'warn_contract_subtype'
- | 'warn_contract_supertype'
- | 'warn_contract_syntax'
- | 'warn_contract_types'
- | 'warn_failing_call'
- | 'warn_fun_app'
- | 'warn_matching'
- | 'warn_non_proper_list'
- | 'warn_not_called'
- | 'warn_opaque'
- | 'warn_race_condition'
- | 'warn_return_no_exit'
- | 'warn_return_only_exit'
- | 'warn_umatched_return'
- | 'warn_undefined_callbacks'
- | 'warn_unknown'
-Id = {File :: string(), Line :: integer()}
-Msg = msg() -- Undefined</code>
+ <p>Returns information about the specified PLT.</p>
</desc>
</func>
+
<func>
- <name>format_warning(Msg) -> string()</name>
- <fsummary>Get the string version of a warning message.</fsummary>
+ <name>run(OptList) -> Warnings</name>
+ <fsummary>Dialyzer command-line version.</fsummary>
<type>
- <v>Msg = {Tag, Id, msg()} -- See run/1</v>
+ <v>OptList</v>
+ <d>See <c>gui/0,1</c>.</d>
+ <v>Warnings</v>
+ <d>See below.</d>
</type>
<desc>
- <p>Get a string from warnings as returned by dialyzer:run/1.</p>
- </desc>
- </func>
- <func>
- <name>plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()}</name>
- <fsummary>Returns information about the specified plt.</fsummary>
- <desc>
- <p>Returns information about the specified plt.</p>
+ <p>Dialyzer command-line version.</p>
+ <code type="none">
+Warnings :: [{Tag, Id, Msg}]
+Tag :: 'warn_behaviour'
+ | 'warn_bin_construction'
+ | 'warn_callgraph'
+ | 'warn_contract_not_equal'
+ | 'warn_contract_range'
+ | 'warn_contract_subtype'
+ | 'warn_contract_supertype'
+ | 'warn_contract_syntax'
+ | 'warn_contract_types'
+ | 'warn_failing_call'
+ | 'warn_fun_app'
+ | 'warn_matching'
+ | 'warn_non_proper_list'
+ | 'warn_not_called'
+ | 'warn_opaque'
+ | 'warn_race_condition'
+ | 'warn_return_no_exit'
+ | 'warn_return_only_exit'
+ | 'warn_umatched_return'
+ | 'warn_undefined_callbacks'
+ | 'warn_unknown'
+Id = {File :: string(), Line :: integer()}
+Msg = msg() -- Undefined</code>
</desc>
</func>
</funcs>
diff --git a/lib/dialyzer/doc/src/dialyzer_chapter.xml b/lib/dialyzer/doc/src/dialyzer_chapter.xml
index c445f2633f..b5acf3732e 100644
--- a/lib/dialyzer/doc/src/dialyzer_chapter.xml
+++ b/lib/dialyzer/doc/src/dialyzer_chapter.xml
@@ -25,196 +25,211 @@
<title>Dialyzer</title>
<prepared></prepared>
<docno></docno>
- <date></date>
+ <date>2016-09-19</date>
<rev></rev>
<file>dialyzer_chapter.xml</file>
</header>
<section>
<title>Introduction</title>
- <p><em>Dialyzer</em> is a static analysis tool that identifies software discrepancies
- such as type errors, unreachable code, unnecessary tests, etc in single Erlang modules
- or entire (sets of) applications.</p>
- </section>
-
- <section>
- <title>Using the Dialyzer from the GUI</title>
-
<section>
- <title>Choosing the applications or modules</title>
- <p>In the "File" window you will find a listing of the current directory.
- Click your way to the directories/modules you want to add or type the
- correct path in the entry.</p>
- <p>Mark the directories/modules you want to analyze for discrepancies and
- click "Add". You can either add the <c><![CDATA[.beam]]></c> and <c><![CDATA[.erl]]></c>-files directly, or
- you can add directories that contain these kinds of files. Note that
- you are only allowed to add the type of files that can be analyzed in
- the current mode of operation (see below), and that you cannot mix
- <c><![CDATA[.beam]]></c> and <c><![CDATA[.erl]]></c>-files.</p>
+ <title>Scope</title>
+ <p>Dialyzer is a static analysis tool that identifies software
+ discrepancies, such as definite type errors, code that has become dead
+ or unreachable because of programming error, and unnecessary tests,
+ in single Erlang modules or entire (sets of) applications.</p>
+
+ <p>Dialyzer can be called from the command line, from Erlang,
+ and from a GUI.</p>
</section>
<section>
- <title>The analysis modes</title>
- <p>Dialyzer has two modes of analysis, "Byte Code" or "Source Code".
- These are controlled by the buttons in the top-middle part of the
- main window, under "Analysis Options".</p>
- </section>
-
- <section>
- <title>Controlling the discrepancies reported by the Dialyzer</title>
- <p>Under the "Warnings" pull-down menu, there are buttons that control
- which discrepancies are reported to the user in the "Warnings" window.
- By clicking on these buttons, one can enable/disable a whole class of
- warnings. Information about the classes of warnings can be found on
- the "Warnings" item under the "Help" menu (at the rightmost top corner).</p>
- <p>If modules are compiled with inlining, spurious warnings may be emitted.
- In the "Options" menu you can choose to ignore inline-compiled modules
- when analyzing byte code. When starting from source code this is not a
- problem since the inlining is explicitly turned off by Dialyzer. The
- option causes Dialyzer to suppress all warnings from inline-compiled
- modules, since there is currently no way for Dialyzer to find what
- parts of the code have been produced by inlining. </p>
+ <title>Prerequisites</title>
+ <p>It is assumed that the reader is familiar with the Erlang programming
+ language.</p>
</section>
+ </section>
- <section>
- <title>Running the analysis</title>
- <p>Once you have chosen the modules or directories you want to analyze,
- click the "Run" button to start the analysis. If for some reason you
- want to stop the analysis while it is running, push the "Stop" button.</p>
- <p>The information from the analysis will be displayed in the Log and the
- Warnings windows.</p>
- </section>
+ <section>
+ <marker id="plt"/>
+ <title>The Persistent Lookup Table</title>
+ <p>Dialyzer stores the result of an analysis in a Persistent
+ Lookup Table (PLT). The PLT can then be used as a starting
+ point for later analyses. It is recommended to build a PLT with the
+ Erlang/OTP applications that you are using, but also to include your
+ own applications that you are using frequently.</p>
+
+ <p>The PLT is built using option <c>--build_plt</c> to Dialyzer.
+ The following command builds the recommended minimal PLT for
+ Erlang/OTP:</p>
- <section>
- <title>Include directories and macro definitions</title>
- <p>When analyzing from source you might have to supply Dialyzer with a
- list of include directories and macro definitions (as you can do with
- the <c><![CDATA[erlc]]></c> flags <c><![CDATA[-I]]></c> and <c><![CDATA[-D]]></c>). This can be done either by starting Dialyzer
- with these flags from the command line as in:</p>
- <code type="none">
+ <code type="none">
+dialyzer --build_plt --apps erts kernel stdlib mnesia</code>
- dialyzer -I my_includes -DDEBUG -Dvsn=42 -I one_more_dir
- </code>
- <p>or by adding these explicitly using the "Manage Macro Definitions" or
- "Manage Include Directories" sub-menus in the "Options" menu.</p>
- </section>
+ <p>Dialyzer looks if there is an environment variable called
+ <c>DIALYZER_PLT</c> and places the PLT at this location. If no such
+ variable is set, Dialyzer places the PLT at
+ <c>$HOME/.dialyzer_plt</c>. The placement can also be specified using
+ the options <c>--plt</c> or <c>--output_plt</c>.</p>
- <section>
- <title>Saving the information on the Log and Warnings windows</title>
- <p>In the "File" menu there are options to save the contents of the Log
- and the Warnings window. Just choose the options and enter the file to
- save the contents in.</p>
- <p>There are also buttons to clear the contents of each window.</p>
- </section>
+ <p>Information can be added to an existing PLT using option
+ <c>--add_to_plt</c>. If you also want to include the Erlang compiler in
+ the PLT and place it in a new PLT, then use the following command:</p>
- <section>
- <title>Inspecting the inferred types of the analyzed functions</title>
- <p>Dialyzer stores the information of the analyzed functions in a
- Persistent Lookup Table (PLT). After an analysis you can inspect this
- information. In the PLT menu you can choose to either search the PLT
- or inspect the contents of the whole PLT. The information is presented
- in edoc format.</p>
- </section>
- </section>
+ <code type="none">
+dialyzer --add_to_plt --apps compiler --output_plt my.plt</code>
- <section>
- <title>Using the Dialyzer from the command line</title>
- <p>See <seealso marker="dialyzer">dialyzer(3)</seealso>.</p>
- </section>
+ <p>Then you can add your favorite application my_app to the new
+ PLT:</p>
- <section>
- <title>Using the Dialyzer from Erlang</title>
- <p>See <seealso marker="dialyzer">dialyzer(3)</seealso>.</p>
- </section>
+ <code type="none">
+dialyzer --add_to_plt --plt my.plt -r my_app/ebin</code>
- <section>
- <title>More on the Persistent Lookup Table (PLT)</title>
+ <p>But you realize that it is unnecessary to have the Erlang compiler in this
+ one:</p>
- <p> The persistent lookup table, or PLT, is used to store the
- result of an analysis. The PLT can then be used as a starting
- point for later analyses. It is recommended to build a PLT with
- the otp applications that you are using, but also to include your
- own applications that you are using frequently.</p>
+ <code type="none">
+dialyzer --remove_from_plt --plt my.plt --apps compiler</code>
- <p>The PLT is built using the --build_plt option to dialyzer. The
- following command builds the recommended minimal PLT for OTP.</p>
+ <p>Later, when you have fixed a bug in your application my_app,
+ you want to update the PLT so that it becomes fresh the next time
+ you run Dialyzer. In this case, run the following command:</p>
<code type="none">
+dialyzer --check_plt --plt my.plt</code>
- dialyzer --build_plt -r $ERL_TOP/lib/stdlib/ebin\
- $ERL_TOP/lib/kernel/ebin \
- $ERL_TOP/lib/mnesia/ebin
- </code>
+ <p>Dialyzer then reanalyzes the changed files
+ and the files that depend on these files. Notice that this
+ consistency check is performed automatically the next time you
+ run Dialyzer with this PLT. Option <c>--check_plt</c> is only
+ for doing so without doing any other analysis.</p>
- <p>Dialyzer will look if there is an environment variable called
- $DIALYZER_PLT and place the PLT at this location. If no such
- variable is set, Dialyzer will place the PLT at
- $HOME/.dialyzer_plt. The placement can also be specified using the
- --plt, or --output_plt options.</p>
-
- <p>You can also add information to an existing plt using the
- --add_to_plt option. Suppose you want to also include the compiler
- in the PLT and place it in a new PLT, then give the command</p>
+ <p>To get information about a PLT, use the following option:</p>
<code type="none">
+dialyzer --plt_info</code>
- dialyzer --add_to_plt -r $ERL_TOP/lib/compiler/ebin --output_plt my.plt
- </code>
+ <p>To specify which PLT, use option <c>--plt</c>.</p>
- <p>Then you would like to add your favorite application my_app to
- the new plt.</p>
+ <p>To get the output printed to a file, use option <c>--output_file</c>.</p>
- <code type="none">
+ <p>Notice that when manipulating the PLT, no warnings are
+ emitted. To turn on warnings during (re)analysis of the PLT, use
+ option <c>--get_warnings</c>.</p>
+ </section>
- dialyzer --add_to_plt --plt my.plt -r my_app/ebin
- </code>
+ <section>
+ <title>Using Dialyzer from the Command Line</title>
+ <p>Dialyzer has a command-line version for automated use.
+ See <seealso marker="dialyzer"><c>dialyzer(3)</c></seealso>.</p>
+ </section>
- <p>But you realize that it is unnecessary to have compiler in this one.</p>
+ <section>
+ <title>Using Dialyzer from Erlang</title>
+ <p>Dialyzer can also be used directly from Erlang.
+ See <seealso marker="dialyzer"><c>dialyzer(3)</c></seealso>.</p>
+ </section>
- <code type="none">
+ <section>
+ <marker id="dialyzer_gui"/>
+ <title>Using Dialyzer from the GUI</title>
+ <section>
+ <title>Choosing the Applications or Modules</title>
+ <p>The <em>File</em> window displays a listing of the current directory.
+ Click your way to the directories/modules you want to add or type the
+ correct path in the entry.</p>
- dialyzer --remove_from_plt --plt my.plt -r $ERL_TOP/lib/compiler/ebin
- </code>
+ <p>Mark the directories/modules you want to analyze for discrepancies and
+ click <em>Add</em>. You can either add the <c>.beam</c> and
+ <c>.erl</c> files directly, or add directories that contain
+ these kind of files. Notice that
+ you are only allowed to add the type of files that can be analyzed in
+ the current mode of operation (see below), and that you cannot mix
+ <c>.beam</c> and <c>.erl</c> files.</p>
+ </section>
- <p> Later, when you have fixed a bug in your application my_app,
- you want to update the plt so that it will be fresh the next time
- you run Dialyzer, run the command</p>
+ <section>
+ <title>Analysis Modes</title>
+ <p>Dialyzer has two analysis modes: "Byte Code" and "Source Code".
+ They are controlled by the buttons in the top-middle part of the
+ main window, under <em>Analysis Options</em>.</p>
+ </section>
- <code type="none">
+ <section>
+ <title>Controlling the Discrepancies Reported by Dialyzer</title>
+ <p>Under the <em>Warnings</em> pull-down menu, there are buttons that
+ control which discrepancies are reported to the user in the
+ <em>Warnings</em> window. By clicking these buttons, you can
+ enable/disable a whole class of warnings. Information about the classes
+ of warnings is found on the "Warnings" item under the <em>Help</em>
+ menu (in the rightmost top corner).</p>
+
+ <p>If modules are compiled with inlining, spurious warnings can be
+ emitted. In the <em>Options</em> menu you can choose to ignore
+ inline-compiled modules when analyzing byte code.
+ When starting from source code, this is not a problem because
+ inlining is explicitly turned off by Dialyzer. The option causes
+ Dialyzer to suppress all warnings from inline-compiled
+ modules, as there is currently no way for Dialyzer to find what
+ parts of the code have been produced by inlining.</p>
+ </section>
- dialyzer --check_plt --plt my.plt
- </code>
+ <section>
+ <title>Running the Analysis</title>
+ <p>Once you have chosen the modules or directories you want to analyze,
+ click the <em>Run</em> button to start the analysis. If you for some
+ reason want to stop the analysis while it is running, click the
+ <em>Stop</em> button.</p>
- <p> Dialyzer will then reanalyze the files that have been changed,
- and the files that depend on these files. Note that this
- consistency check will be performed automatically the next time
- you run Dialyzer with this plt. The --check_plt option is merely
- for doing so without doing any other analysis.</p>
+ <p>The information from the analysis is displayed in the <em>Log</em>
+ window and the <em>Warnings</em> window.</p>
+ </section>
- <p> To get some information about a plt use the option</p>
- <code type="none">
+ <section>
+ <title>Include Directories and Macro Definitions</title>
+ <p>When analyzing from source, you might have to supply Dialyzer
+ with a list of include directories and macro definitions (as you can do
+ with the <seealso marker="erts:erlc"><c>erlc</c></seealso> flags
+ <c>-I</c> and <c>-D</c>). This can be done
+ either by starting Dialyzer with these flags from the command
+ line as in:</p>
+
+ <code type="none">
+dialyzer -I my_includes -DDEBUG -Dvsn=42 -I one_more_dir</code>
- dialyzer --plt_info
- </code>
+ <p>or by adding these explicitly using submenu
+ <em>Manage Macro Definitions</em> or
+ <em>Manage Include Directories</em> in the <em>Options</em> menu.</p>
+ </section>
- <p>You can also specify which plt with the --plt option, and get the
- output printed to a file with --output_file</p>
+ <section>
+ <title>Saving the Information on the Log and Warnings Windows</title>
+ <p>The <em>File</em> menu includes options to save the contents of the
+ <em>Log</em> window and the <em>Warnings</em> window. Simply choose the
+ options and enter the file to save the contents in.</p>
- <p>Note that when manipulating the plt, no warnings are
- emitted. To turn on warnings during (re)analysis of the plt, use
- the option --get_warnings.</p>
+ <p>There are also buttons to clear the contents of each window.</p>
+ </section>
+ <section>
+ <title>Inspecting the Inferred Types of the Analyzed Functions</title>
+ <p>Dialyzer stores the information of the analyzed functions in a
+ Persistent Lookup Table (PLT), see section
+ <seealso marker="#plt">The Persistent Lookup Table</seealso>.</p>
+
+ <p>After an analysis, you can inspect this information.
+ In the <em>PLT</em> menu you can choose to either search the PLT
+ or inspect the contents of the whole PLT. The information is presented
+ in <seealso marker="edoc:edoc"><c>EDoc</c></seealso> format.</p>
+ </section>
</section>
<section>
- <title>Feedback and bug reports</title>
- <p>At this point, we very much welcome user feedback (even wish-lists!).
- If you notice something weird, especially if the Dialyzer reports any
- discrepancy that is a false positive, please send an error report
- describing the symptoms and how to reproduce them to:</p>
- <code type="none"><![CDATA[
- ]]></code>
+ <title>Feedback and Bug Reports</title>
+ <p>We very much welcome user feedback - even wishlists!
+ If you notice anything weird, especially if Dialyzer reports
+ any discrepancy that is a false positive, please send an error report
+ describing the symptoms and how to reproduce them.</p>
</section>
</chapter>
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index a5a52fee61..0dbee1ce34 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -32,6 +32,132 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 3.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Report unknown types properly. A bug was introduced
+ in Erlang/OTP 19.3, where warnings about unknown types
+ were simply discarded. </p>
+ <p>
+ Own Id: OTP-14368</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug concerning parameterized opaque types. </p>
+ <p>
+ Own Id: OTP-14130</p>
+ </item>
+ <item>
+ <p> Improve a few warnings. One of them could cause a
+ crash. </p>
+ <p>
+ Own Id: OTP-14177</p>
+ </item>
+ <item>
+ <p>The dialyzer and observer applications will now use a
+ portable way to find the home directory. That means that
+ there is no longer any need to manually set the HOME
+ environment variable on Windows.</p>
+ <p>
+ Own Id: OTP-14249 Aux Id: ERL-161 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The peak memory consumption is reduced. </p><p> The
+ evaluation of huge SCCs in <c>dialyzer_typesig</c> is
+ optimized. </p><p> Analyzing modules with binary
+ construction with huge strings is now much faster. </p>
+ <p>
+ Own Id: OTP-14126 Aux Id: ERL-308 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix bugs regarding opaque types. </p>
+ <p>
+ Own Id: OTP-13693</p>
+ </item>
+ <item>
+ <p> Fix error handling of bad <c>-dialyzer()</c>
+ attributes. </p>
+ <p>
+ Own Id: OTP-13979 Aux Id: ERL-283 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> A few warning messages have been improved. </p>
+ <p>
+ Own Id: OTP-11403</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.0.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The translation of forms to types is improved for
+ opaque types in a few cases. </p>
+ <p>
+ Own Id: OTP-13682</p>
+ </item>
+ <item>
+ <p> Add warning suppression to compiler-generated case
+ statements. Warnings about clauses that cannot match and
+ are also compiler generated are suppressed unless none of
+ the clauses return. </p>
+ <p>
+ Own Id: OTP-13723 Aux Id: ERL-159, PR-1121 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix a map related bug.</p>
+ <p>
+ Own Id: OTP-13709 Aux Id: ERL-177, PR-1115 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 3.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -485,7 +611,7 @@
or modifying opaque types within the scope of a module.
</p> <p> Hitherto the shape of terms (tuple, list, etc.)
has been used to determine the opaque terms, but now the
- contracts are used for decorating types with opaqueness.
+ contracts are used for decorating types with opacity.
</p>
<p>
Own Id: OTP-10397</p>
@@ -1468,7 +1594,7 @@
<list>
<item>
<p>The analysis accepts opaque type declarations and
- detects violations of opaqueness of terms of such types.
+ detects violations of opacity of terms of such types.
Starting with R13, many Erlang/OTP standard libraries
(array, dict, digraph, ets, gb_sets, gb_trees, queue, and
sets) contain opaque type declarations of their main data
diff --git a/lib/dialyzer/doc/src/part.xml b/lib/dialyzer/doc/src/part.xml
index 575f77549a..9bfcf21a66 100644
--- a/lib/dialyzer/doc/src/part.xml
+++ b/lib/dialyzer/doc/src/part.xml
@@ -25,12 +25,11 @@
<title>Dialyzer User's Guide</title>
<prepared></prepared>
<docno></docno>
- <date></date>
+ <date>2016-09-19</date>
<rev></rev>
<file>part.xml</file>
</header>
<description>
- <p><em>Dialyzer</em> is a static analysis tool that identifies software discrepancies such as type errors, unreachable code, unnecessary tests, etc in single Erlang modules or entire (sets of) applications.</p>
</description>
<xi:include href="dialyzer_chapter.xml"/>
</part>
diff --git a/lib/dialyzer/doc/src/ref_man.xml b/lib/dialyzer/doc/src/ref_man.xml
index 01478cfb40..ddac047f2e 100644
--- a/lib/dialyzer/doc/src/ref_man.xml
+++ b/lib/dialyzer/doc/src/ref_man.xml
@@ -25,11 +25,10 @@
<title>Dialyzer Reference Manual</title>
<prepared></prepared>
<docno></docno>
- <date></date>
+ <date>2016-09-19</date>
<rev></rev>
</header>
<description>
- <p><em>Dialyzer</em> is a static analysis tool that identifies software discrepancies such as type errors, unreachable code, unnecessary tests, etc in single Erlang modules or entire (sets of) applications.</p>
</description>
<xi:include href="dialyzer.xml"/>
</application>
diff --git a/lib/dialyzer/src/dialyzer.app.src b/lib/dialyzer/src/dialyzer.app.src
index 5b28f7ae86..f517c51ec1 100644
--- a/lib/dialyzer/src/dialyzer.app.src
+++ b/lib/dialyzer/src/dialyzer.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,5 +48,5 @@
{applications, [compiler, hipe, kernel, stdlib, wx]},
{env, []},
{runtime_dependencies, ["wx-1.2","syntax_tools-2.0","stdlib-3.0",
- "kernel-5.0","hipe-3.15.1","erts-8.0",
+ "kernel-5.0","hipe-3.15.4","erts-8.0",
"compiler-7.0"]}]}.
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index bcac8afe64..d25ffd02a2 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -282,7 +282,7 @@ cl_check_log(none) ->
cl_check_log(Output) ->
io:format(" Check output file `~s' for details\n", [Output]).
--spec format_warning(raw_warning()) -> string().
+-spec format_warning(raw_warning() | dial_warning()) -> string().
format_warning(W) ->
format_warning(W, basename).
@@ -407,6 +407,10 @@ message_to_string({contract_range, [Contract, M, F, ArgStrings, Line, CRet]}) ->
message_to_string({invalid_contract, [M, F, A, Sig]}) ->
io_lib:format("Invalid type specification for function ~w:~w/~w."
" The success typing is ~s\n", [M, F, A, Sig]);
+message_to_string({contract_with_opaque, [M, F, A, OpaqueType, SigType]}) ->
+ io_lib:format("The specification for ~w:~w/~w"
+ " has an opaque subtype ~s which is violated by the"
+ " success typing ~s\n", [M, F, A, OpaqueType, SigType]);
message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) ->
io_lib:format("The specification for ~w:~w/~w states that the function"
" might also return ~s but the inferred return is ~s\n",
@@ -432,25 +436,25 @@ message_to_string({opaque_guard, [Arg1, Infix, Arg2, ArgNs]}) ->
io_lib:format("Guard test ~s ~s ~s contains ~s\n",
[Arg1, Infix, Arg2, form_positions(ArgNs)]);
message_to_string({opaque_guard, [Guard, Args]}) ->
- io_lib:format("Guard test ~w~s breaks the opaqueness of its argument\n",
+ io_lib:format("Guard test ~w~s breaks the opacity of its argument\n",
[Guard, Args]);
message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) ->
Term = if OpaqueType =:= OpaqueTerm -> "the term";
true -> OpaqueTerm
end,
io_lib:format("The attempt to match a term of type ~s against the ~s"
- " breaks the opaqueness of ~s\n", [OpaqueType, Pat, Term]);
+ " breaks the opacity of ~s\n", [OpaqueType, Pat, Term]);
message_to_string({opaque_neq, [Type, _Op, OpaqueType]}) ->
io_lib:format("Attempt to test for inequality between a term of type ~s"
" and a term of opaque type ~s\n", [Type, OpaqueType]);
message_to_string({opaque_type_test, [Fun, Args, Arg, ArgType]}) ->
- io_lib:format("The type test ~s~s breaks the opaqueness of the term ~s~s\n",
+ io_lib:format("The type test ~s~s breaks the opacity of the term ~s~s\n",
[Fun, Args, Arg, ArgType]);
message_to_string({opaque_size, [SizeType, Size]}) ->
- io_lib:format("The size ~s breaks the opaqueness of ~s\n",
+ io_lib:format("The size ~s breaks the opacity of ~s\n",
[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",
+ io_lib:format("The call ~s:~s~s breaks the opacity of the term ~s :: ~s\n",
[M, F, Args, Culprit, OpaqueType]);
%%----- Warnings for concurrency errors --------------------
message_to_string({race_condition, [M, F, Args, Reason]}) ->
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index ea6a71217c..1139044ec9 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 50fc1d8471..7f8e68908e 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -101,9 +101,9 @@ loop(#server_state{parent = Parent} = State,
{AnalPid, cserver, CServer, Plt} ->
send_codeserver_plt(Parent, CServer, Plt),
loop(State, Analysis, ExtCalls);
- {AnalPid, done, Plt, DocPlt} ->
+ {AnalPid, done, MiniPlt, DocPlt} ->
send_ext_calls(Parent, ExtCalls),
- send_analysis_done(Parent, Plt, DocPlt);
+ send_analysis_done(Parent, MiniPlt, DocPlt);
{AnalPid, ext_calls, NewExtCalls} ->
loop(State, Analysis, NewExtCalls);
{AnalPid, ext_types, ExtTypes} ->
@@ -121,6 +121,7 @@ loop(#server_state{parent = Parent} = State,
%% The Analysis
%%--------------------------------------------------------------------
+%% Calls to erlang:garbage_collect() help to reduce the heap size.
analysis_start(Parent, Analysis, LegalWarnings) ->
CServer = dialyzer_codeserver:new(),
Plt = Analysis#analysis.plt,
@@ -157,12 +158,9 @@ analysis_start(Parent, Analysis, LegalWarnings) ->
TmpCServer1 = dialyzer_codeserver:set_temp_records(MergedRecords, TmpCServer0),
TmpCServer2 =
dialyzer_codeserver:finalize_exported_types(MergedExpTypes, TmpCServer1),
+ erlang:garbage_collect(),
?timing(State#analysis_state.timing_server, "remote",
- begin
- TmpCServer3 =
- dialyzer_utils:process_record_remote_types(TmpCServer2),
- dialyzer_contracts:process_contract_remote_types(TmpCServer3)
- end)
+ contracts_and_records(TmpCServer2, Parent))
catch
throw:{error, _ErrorMsg} = Error -> exit(Error)
end,
@@ -171,48 +169,75 @@ analysis_start(Parent, Analysis, LegalWarnings) ->
NewPlt1 = dialyzer_plt:insert_exported_types(NewPlt0, ExpTypes),
State0 = State#analysis_state{plt = NewPlt1},
dump_callgraph(Callgraph, State0, Analysis),
- State1 = State0#analysis_state{codeserver = NewCServer},
%% Remove all old versions of the files being analyzed
AllNodes = dialyzer_callgraph:all_nodes(Callgraph),
- Plt1 = dialyzer_plt:delete_list(NewPlt1, AllNodes),
+ Plt1_a = dialyzer_plt:delete_list(NewPlt1, AllNodes),
+ Plt1 = dialyzer_plt:insert_callbacks(Plt1_a, NewCServer),
+ State1 = State0#analysis_state{codeserver = NewCServer, plt = Plt1},
Exports = dialyzer_codeserver:get_exports(NewCServer),
+ NonExports = sets:subtract(sets:from_list(AllNodes), Exports),
+ NonExportsList = sets:to_list(NonExports),
NewCallgraph =
case Analysis#analysis.race_detection of
true -> dialyzer_callgraph:put_race_detection(true, Callgraph);
false -> Callgraph
end,
- State2 = analyze_callgraph(NewCallgraph, State1#analysis_state{plt = Plt1}),
+ State2 = analyze_callgraph(NewCallgraph, State1),
+ #analysis_state{plt = MiniPlt2, doc_plt = DocPlt} = State2,
dialyzer_callgraph:dispose_race_server(NewCallgraph),
- rcv_and_send_ext_types(Parent),
- NonExports = sets:subtract(sets:from_list(AllNodes), Exports),
- NonExportsList = sets:to_list(NonExports),
- Plt2 = dialyzer_plt:delete_list(State2#analysis_state.plt, NonExportsList),
- send_codeserver_plt(Parent, CServer, State2#analysis_state.plt),
- send_analysis_done(Parent, Plt2, State2#analysis_state.doc_plt).
+ %% Since the PLT is never used, a dummy is sent:
+ DummyPlt = dialyzer_plt:new(),
+ send_codeserver_plt(Parent, CServer, DummyPlt),
+ MiniPlt3 = dialyzer_plt:delete_list(MiniPlt2, NonExportsList),
+ send_analysis_done(Parent, MiniPlt3, DocPlt).
+
+contracts_and_records(CodeServer, Parent) ->
+ Fun = contrs_and_recs(CodeServer, Parent),
+ {Pid, Ref} = erlang:spawn_monitor(Fun),
+ dialyzer_codeserver:give_away(CodeServer, Pid),
+ Pid ! {self(), go},
+ receive {'DOWN', Ref, process, Pid, Return} ->
+ Return
+ end.
+
+-spec contrs_and_recs(dialyzer_codeserver:codeserver(), pid()) ->
+ fun(() -> no_return()).
+
+contrs_and_recs(TmpCServer2, Parent) ->
+ fun() ->
+ Caller = receive {Pid, go} -> Pid end,
+ {TmpCServer3, RecordDict} =
+ dialyzer_utils:process_record_remote_types(TmpCServer2),
+ TmpServer4 =
+ dialyzer_contracts:process_contract_remote_types(TmpCServer3,
+ RecordDict),
+ dialyzer_codeserver:give_away(TmpServer4, Parent),
+ rcv_and_send_ext_types(Caller, Parent),
+ exit(TmpServer4)
+ end.
analyze_callgraph(Callgraph, #analysis_state{codeserver = Codeserver,
doc_plt = DocPlt,
+ plt = Plt,
timing_server = TimingServer,
parent = Parent,
solvers = Solvers} = State) ->
- Plt = dialyzer_plt:insert_callbacks(State#analysis_state.plt, Codeserver),
- {NewPlt, NewDocPlt} =
- case State#analysis_state.analysis_type of
- plt_build ->
- NewPlt0 =
- dialyzer_succ_typings:analyze_callgraph(Callgraph, Plt, Codeserver,
- TimingServer, Solvers, Parent),
- {NewPlt0, DocPlt};
- succ_typings ->
- {Warnings, NewPlt0, NewDocPlt0} =
- dialyzer_succ_typings:get_warnings(Callgraph, Plt, DocPlt, Codeserver,
- TimingServer, Solvers, Parent),
- Warnings1 = filter_warnings(Warnings, Codeserver),
- send_warnings(State#analysis_state.parent, Warnings1),
- {NewPlt0, NewDocPlt0}
- end,
- dialyzer_callgraph:delete(Callgraph),
- State#analysis_state{plt = NewPlt, doc_plt = NewDocPlt}.
+ case State#analysis_state.analysis_type of
+ plt_build ->
+ NewMiniPlt =
+ dialyzer_succ_typings:analyze_callgraph(Callgraph, Plt, Codeserver,
+ TimingServer, Solvers, Parent),
+ dialyzer_callgraph:delete(Callgraph),
+ State#analysis_state{plt = NewMiniPlt, doc_plt = DocPlt};
+ succ_typings ->
+ {Warnings, NewMiniPlt, NewDocPlt} =
+ dialyzer_succ_typings:get_warnings(Callgraph, Plt, DocPlt, Codeserver,
+ TimingServer, Solvers, Parent),
+ dialyzer_callgraph:delete(Callgraph),
+ Warnings1 = filter_warnings(Warnings, Codeserver),
+ send_warnings(State#analysis_state.parent, Warnings1),
+ State#analysis_state{plt = NewMiniPlt, doc_plt = NewDocPlt}
+ end.
%%--------------------------------------------------------------------
%% Build the callgraph and fill the codeserver.
@@ -406,24 +431,28 @@ compile_common(File, AbstrCode, CompOpts, Callgraph, CServer,
{ok, RecInfo} ->
CServer1 =
dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
- MetaFunInfo =
- dialyzer_utils:get_fun_meta_info(Mod, AbstrCode, LegalWarnings),
- CServer2 =
- dialyzer_codeserver:insert_fun_meta_info(MetaFunInfo, CServer1),
- case UseContracts of
- true ->
- case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
- {error, _} = Error -> Error;
- {ok, SpecInfo, CallbackInfo} ->
- CServer3 =
- dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
- CallbackInfo,
- CServer2),
- store_core(Mod, Core, Callgraph, CServer3)
- end;
- false ->
- store_core(Mod, Core, Callgraph, CServer2)
- end
+ case
+ dialyzer_utils:get_fun_meta_info(Mod, AbstrCode, LegalWarnings)
+ of
+ {error, _} = Error -> Error;
+ MetaFunInfo ->
+ CServer2 =
+ dialyzer_codeserver:insert_fun_meta_info(MetaFunInfo, CServer1),
+ case UseContracts of
+ true ->
+ case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
+ {error, _} = Error -> Error;
+ {ok, SpecInfo, CallbackInfo} ->
+ CServer3 =
+ dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
+ CallbackInfo,
+ CServer2),
+ store_core(Mod, Core, Callgraph, CServer3)
+ end;
+ false ->
+ store_core(Mod, Core, Callgraph, CServer2)
+ end
+ end
end
end.
@@ -525,13 +554,13 @@ default_includes(Dir) ->
%% Handle Messages
%%-------------------------------------------------------------------
-rcv_and_send_ext_types(Parent) ->
+rcv_and_send_ext_types(SendTo, Parent) ->
Self = self(),
Self ! {Self, done},
case rcv_ext_types(Self, []) of
[] -> ok;
ExtTypes ->
- Parent ! {Self, ext_types, ExtTypes},
+ Parent ! {SendTo, ext_types, ExtTypes},
ok
end.
@@ -565,8 +594,9 @@ is_ok_fun({_Filename, _Line, {_M, _F, _A} = MFA}, Codeserver) ->
is_ok_tag(Tag, {_F, _L, MorMFA}, Codeserver) ->
not dialyzer_utils:is_suppressed_tag(MorMFA, Tag, Codeserver).
-send_analysis_done(Parent, Plt, DocPlt) ->
- Parent ! {self(), done, Plt, DocPlt},
+send_analysis_done(Parent, MiniPlt, DocPlt) ->
+ ok = dialyzer_plt:give_away(MiniPlt, Parent),
+ Parent ! {self(), done, MiniPlt, DocPlt},
ok.
send_ext_calls(_Parent, none) ->
@@ -579,7 +609,7 @@ send_ext_types(Parent, ExtTypes) ->
Parent ! {self(), ext_types, ExtTypes},
ok.
-send_codeserver_plt(Parent, CServer, Plt ) ->
+send_codeserver_plt(Parent, CServer, Plt) ->
Parent ! {self(), cserver, CServer, Plt},
ok.
@@ -598,14 +628,14 @@ format_bad_calls([{{_, _, _}, {_, module_info, A}}|Left], CodeServer, Acc)
format_bad_calls([{FromMFA, {M, F, A} = To}|Left], CodeServer, Acc) ->
{_Var, FunCode} = dialyzer_codeserver:lookup_mfa_code(FromMFA, CodeServer),
Msg = {call_to_missing, [M, F, A]},
- {File, Line} = find_call_file_and_line(FunCode, To),
+ {File, Line} = find_call_file_and_line(FromMFA, FunCode, To, CodeServer),
WarningInfo = {File, Line, FromMFA},
NewAcc = [{?WARN_CALLGRAPH, WarningInfo, Msg}|Acc],
format_bad_calls(Left, CodeServer, NewAcc);
format_bad_calls([], _CodeServer, Acc) ->
Acc.
-find_call_file_and_line(Tree, MFA) ->
+find_call_file_and_line({Module, _, _}, Tree, MFA, CodeServer) ->
Fun =
fun(SubTree, Acc) ->
case cerl:is_c_call(SubTree) of
@@ -618,7 +648,7 @@ find_call_file_and_line(Tree, MFA) ->
case {cerl:concrete(M), cerl:concrete(F), A} of
MFA ->
Ann = cerl:get_ann(SubTree),
- [{get_file(Ann), get_line(Ann)}|Acc];
+ [{get_file(CodeServer, Module, Ann), get_line(Ann)}|Acc];
{erlang, make_fun, 3} ->
[CA1, CA2, CA3] = cerl:call_args(SubTree),
case
@@ -634,7 +664,8 @@ find_call_file_and_line(Tree, MFA) ->
of
MFA ->
Ann = cerl:get_ann(SubTree),
- [{get_file(Ann), get_line(Ann)}|Acc];
+ [{get_file(CodeServer, Module, Ann),
+ get_line(Ann)}|Acc];
_ ->
Acc
end;
@@ -654,8 +685,10 @@ get_line([Line|_]) when is_integer(Line) -> Line;
get_line([_|Tail]) -> get_line(Tail);
get_line([]) -> -1.
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
+get_file(Codeserver, Module, [{file, FakeFile}|_]) ->
+ dialyzer_codeserver:translate_fake_file(Codeserver, Module, FakeFile);
+get_file(Codeserver, Module, [_|Tail]) ->
+ get_file(Codeserver, Module, Tail).
-spec dump_callgraph(dialyzer_callgraph:callgraph(), #analysis_state{}, #analysis{}) ->
'ok'.
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl
index 5623929a43..a8af5debb9 100644
--- a/lib/dialyzer/src/dialyzer_behaviours.erl
+++ b/lib/dialyzer/src/dialyzer_behaviours.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,9 +62,9 @@ check_callbacks(Module, Attrs, Records, Plt, Codeserver) ->
_ ->
MFA = {Module,module_info,0},
{_Var,Code} = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
- File = get_file(cerl:get_ann(Code)),
+ File = get_file(Codeserver, Module, cerl:get_ann(Code)),
State = #state{plt = Plt, filename = File, behlines = BehLines,
- codeserver = Codeserver, records = Records},
+ codeserver = Codeserver, records = Records},
Warnings = get_warnings(Module, Behaviours, State),
[add_tag_warning_info(Module, W, State) || W <- Warnings]
end.
@@ -213,12 +213,15 @@ add_tag_warning_info(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) ->
dialyzer_codeserver:lookup_mfa_code({Module, Fun, Arity},
State#state.codeserver),
Anns = cerl:get_ann(FunCode),
- WarningInfo = {get_file(Anns), get_line(Anns), {Module, Fun, Arity}},
+ File = get_file(State#state.codeserver, Module, Anns),
+ WarningInfo = {File, get_line(Anns), {Module, Fun, Arity}},
{?WARN_BEHAVIOUR, WarningInfo, Warn}.
get_line([Line|_]) when is_integer(Line) -> Line;
get_line([_|Tail]) -> get_line(Tail);
get_line([]) -> -1.
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
+get_file(Codeserver, Module, [{file, FakeFile}|_]) ->
+ dialyzer_codeserver:translate_fake_file(Codeserver, Module, FakeFile);
+get_file(Codeserver, Module, [_|Tail]) ->
+ get_file(Codeserver, Module, Tail).
diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl
index 50abb22009..b079cd3090 100644
--- a/lib/dialyzer/src/dialyzer_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_callgraph.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -119,7 +119,11 @@
-opaque callgraph() :: #callgraph{}.
--type active_digraph() :: {'d', digraph:graph()} | {'e', ets:tid(), ets:tid()}.
+-type active_digraph() :: {'d', digraph:graph()}
+ | {'e',
+ Out :: ets:tid(),
+ In :: ets:tid(),
+ Map :: ets:tid()}.
%%----------------------------------------------------------------------
@@ -248,24 +252,30 @@ find_non_local_calls([], Set) ->
-spec get_depends_on(scc() | module(), callgraph()) -> [scc()].
-get_depends_on(SCC, #callgraph{active_digraph = {'e', Out, _In}}) ->
- case ets_lookup_dict(SCC, Out) of
- {ok, Value} -> Value;
- error -> []
- end;
+get_depends_on(SCC, #callgraph{active_digraph = {'e', Out, _In, Maps}}) ->
+ lookup_scc(SCC, Out, Maps);
get_depends_on(SCC, #callgraph{active_digraph = {'d', DG}}) ->
digraph:out_neighbours(DG, SCC).
-spec get_required_by(scc() | module(), callgraph()) -> [scc()].
-get_required_by(SCC, #callgraph{active_digraph = {'e', _Out, In}}) ->
- case ets_lookup_dict(SCC, In) of
- {ok, Value} -> Value;
- error -> []
- end;
+get_required_by(SCC, #callgraph{active_digraph = {'e', _Out, In, Maps}}) ->
+ lookup_scc(SCC, In, Maps);
get_required_by(SCC, #callgraph{active_digraph = {'d', DG}}) ->
digraph:in_neighbours(DG, SCC).
+lookup_scc(SCC, Table, Maps) ->
+ case ets_lookup_dict({'scc', SCC}, Maps) of
+ {ok, SCCInt} ->
+ case ets_lookup_dict(SCCInt, Table) of
+ {ok, Ints} ->
+ [ets:lookup_element(Maps, Int, 2) || Int <- Ints];
+ error ->
+ []
+ end;
+ error -> []
+ end.
+
%%----------------------------------------------------------------------
%% Handling of modules & SCCs
%%----------------------------------------------------------------------
@@ -582,9 +592,10 @@ digraph_delete(DG) ->
active_digraph_delete({'d', DG}) ->
digraph:delete(DG);
-active_digraph_delete({'e', Out, In}) ->
+active_digraph_delete({'e', Out, In, Maps}) ->
ets:delete(Out),
- ets:delete(In).
+ ets:delete(In),
+ ets:delete(Maps).
digraph_edges(DG) ->
digraph:edges(DG).
@@ -758,37 +769,28 @@ to_ps(#callgraph{} = CG, File, Args) ->
ok.
condensation(G) ->
- SCs = digraph_utils:strong_components(G),
- V2I = ets:new(condensation_v2i, []),
- I2C = ets:new(condensation_i2c, []),
- I2I = ets:new(condensation_i2i, [bag]),
- CFun =
- fun(SC, N) ->
- lists:foreach(fun(V) -> true = ets:insert(V2I, {V,N}) end, SC),
- true = ets:insert(I2C, {N, SC}),
- N + 1
- end,
- lists:foldl(CFun, 1, SCs),
- Fun1 =
- fun({V1, V2}) ->
- I1 = ets:lookup_element(V2I, V1, 2),
- I2 = ets:lookup_element(V2I, V2, 2),
- I1 =:= I2 orelse ets:insert(I2I, {I1, I2})
- end,
- lists:foreach(Fun1, digraph:edges(G)),
- Fun3 =
- fun({I1, I2}, {Out, In}) ->
- SC1 = ets:lookup_element(I2C, I1, 2),
- SC2 = ets:lookup_element(I2C, I2, 2),
- {dict:append(SC1, SC2, Out), dict:append(SC2, SC1, In)}
- end,
- {OutDict, InDict} = ets:foldl(Fun3, {dict:new(), dict:new()}, I2I),
- [OutETS, InETS] =
+ SCCs = digraph_utils:strong_components(G),
+ %% Assign unique numbers to SCCs:
+ Ints = lists:seq(1, length(SCCs)),
+ IntToSCC = lists:zip(Ints, SCCs),
+ IntScc = sofs:relation(IntToSCC, [{int, scc}]),
+ %% Subsitute strong components for vertices in edges using the
+ %% unique numbers:
+ C2V = sofs:relation([{SC, V} || SC <- SCCs, V <- SC], [{scc, v}]),
+ I2V = sofs:relative_product(IntScc, C2V), % [{v, int}]
+ Es = sofs:relation(digraph:edges(G), [{v, v}]),
+ R1 = sofs:relative_product(I2V, Es),
+ R2 = sofs:relative_product(I2V, sofs:converse(R1)),
+ %% Create in- and out-neighbours:
+ In = sofs:relation_to_family(sofs:strict_relation(R2)),
+ R3 = sofs:converse(R2),
+ Out = sofs:relation_to_family(sofs:strict_relation(R3)),
+ [OutETS, InETS, MapsETS] =
[ets:new(Name,[{read_concurrency, true}]) ||
- Name <- [callgraph_deps_out, callgraph_deps_in]],
- ets:insert(OutETS, dict:to_list(OutDict)),
- ets:insert(InETS, dict:to_list(InDict)),
- ets:delete(V2I),
- ets:delete(I2C),
- ets:delete(I2I),
- {{'e', OutETS, InETS}, SCs}.
+ Name <- [callgraph_deps_out, callgraph_deps_in, callgraph_scc_map]],
+ ets:insert(OutETS, sofs:to_external(Out)),
+ ets:insert(InETS, sofs:to_external(In)),
+ %% Create mappings from SCCs to unique integers, and the inverse:
+ ets:insert(MapsETS, lists:zip([{'scc', SCC} || SCC<- SCCs], Ints)),
+ ets:insert(MapsETS, IntToSCC),
+ {{'e', OutETS, InETS, MapsETS}, SCCs}.
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index fc56693ea3..e8c1613a33 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -637,8 +637,8 @@ cl_loop(State, LogCache) ->
{BackendPid, warnings, Warnings} ->
NewState = store_warnings(State, Warnings),
cl_loop(NewState, LogCache);
- {BackendPid, done, NewPlt, _NewDocPlt} ->
- return_value(State, NewPlt);
+ {BackendPid, done, NewMiniPlt, _NewDocPlt} ->
+ return_value(State, NewMiniPlt);
{BackendPid, ext_calls, ExtCalls} ->
cl_loop(State#cl_state{external_calls = ExtCalls}, LogCache);
{BackendPid, ext_types, ExtTypes} ->
@@ -654,6 +654,7 @@ cl_loop(State, LogCache) ->
cl_error(State, Msg);
_Other ->
%% io:format("Received ~p\n", [_Other]),
+ %% Note: {BackendPid, cserver, CodeServer, Plt} is ignored.
cl_loop(State, LogCache)
end.
@@ -699,10 +700,13 @@ return_value(State = #cl_state{erlang_mode = ErlangMode,
output_plt = OutputPlt,
plt_info = PltInfo,
stored_warnings = StoredWarnings},
- Plt) ->
+ MiniPlt) ->
case OutputPlt =:= none of
- true -> ok;
- false -> dialyzer_plt:to_file(OutputPlt, Plt, ModDeps, PltInfo)
+ true ->
+ dialyzer_plt:delete(MiniPlt);
+ false ->
+ Plt = dialyzer_plt:restore_full_plt(MiniPlt),
+ dialyzer_plt:to_file(OutputPlt, Plt, ModDeps, PltInfo)
end,
UnknownWarnings = unknown_warnings(State),
RetValue =
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index 934351aeeb..f668b81cd3 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -510,7 +510,7 @@ warning_options_msg() ->
-Wno_match
Suppress warnings for patterns that are unused or cannot match.
-Wno_opaque
- Suppress warnings for violations of opaqueness of data types.
+ Suppress warnings for violations of opacity of data types.
-Wno_fail_call
Suppress warnings for failing calls.
-Wno_contracts
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index 03cd9671af..543934193d 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,9 @@
-module(dialyzer_codeserver).
-export([delete/1,
- finalize_contracts/3,
+ store_temp_contracts/4,
+ give_away/2,
+ finalize_contracts/1,
finalize_exported_types/2,
finalize_records/2,
get_contracts/1,
@@ -38,7 +40,9 @@
get_exports/1,
get_records/1,
get_next_core_label/1,
- get_temp_contracts/1,
+ get_temp_contracts/2,
+ contracts_modules/1,
+ store_contracts/4,
get_temp_exported_types/1,
get_temp_records/1,
insert/3,
@@ -48,6 +52,7 @@
is_exported/2,
lookup_mod_code/2,
lookup_mfa_code/2,
+ lookup_mfa_var_label/2,
lookup_mod_records/2,
lookup_mod_contracts/2,
lookup_mfa_contract/2,
@@ -56,21 +61,22 @@
set_next_core_label/2,
set_temp_records/2,
store_temp_records/3,
- store_temp_contracts/4]).
+ translate_fake_file/3]).
--export_type([codeserver/0, fun_meta_info/0]).
+-export_type([codeserver/0, fun_meta_info/0, contracts/0]).
-include("dialyzer.hrl").
%%--------------------------------------------------------------------
-type dict_ets() :: ets:tid().
+-type map_ets() :: ets:tid().
-type set_ets() :: ets:tid().
-type types() :: erl_types:type_table().
--type mod_records() :: dict:dict(module(), types()).
+-type mod_records() :: erl_types:mod_records().
--type contracts() :: dict:dict(mfa(),dialyzer_contracts:file_contract()).
+-type contracts() :: #{mfa() => dialyzer_contracts:file_contract()}.
-type mod_contracts() :: dict:dict(module(), contracts()).
%% A property-list of data compiled from -compile and -dialyzer attributes.
@@ -81,16 +87,16 @@
-record(codeserver, {next_core_label = 0 :: label(),
code :: dict_ets(),
- exported_types :: set_ets() | 'undefined', % set(mfa())
- records :: dict_ets() | 'undefined',
- contracts :: dict_ets() | 'undefined',
- callbacks :: dict_ets() | 'undefined',
+ exported_types :: set_ets(), % set(mfa())
+ records :: map_ets(),
+ contracts :: map_ets(),
+ callbacks :: map_ets(),
fun_meta_info :: dict_ets(), % {mfa(), meta_info()}
exports :: 'clean' | set_ets(), % set(mfa())
temp_exported_types :: 'clean' | set_ets(), % set(mfa())
- temp_records :: 'clean' | dict_ets(),
- temp_contracts :: 'clean' | dict_ets(),
- temp_callbacks :: 'clean' | dict_ets()
+ temp_records :: 'clean' | map_ets(),
+ temp_contracts :: 'clean' | map_ets(),
+ temp_callbacks :: 'clean' | map_ets()
}).
-opaque codeserver() :: #codeserver{}.
@@ -104,7 +110,7 @@ ets_dict_find(Key, Table) ->
_:_ -> error
end.
-ets_dict_store(Key, Element, Table) ->
+ets_map_store(Key, Element, Table) ->
true = ets:insert(Table, {Key, Element}),
Table.
@@ -128,9 +134,6 @@ ets_set_to_set(Table) ->
Fold = fun({E}, Set) -> sets:add_element(E, Set) end,
ets:foldl(Fold, sets:new(), Table).
-ets_read_concurrent_table(Name) ->
- ets:new(Name, [{read_concurrency, true}]).
-
%%--------------------------------------------------------------------
-spec new() -> codeserver().
@@ -138,6 +141,13 @@ ets_read_concurrent_table(Name) ->
new() ->
CodeOptions = [compressed, public, {read_concurrency, true}],
Code = ets:new(dialyzer_codeserver_code, CodeOptions),
+ ReadOptions = [compressed, {read_concurrency, true}],
+ [Contracts, Callbacks, Records, ExportedTypes] =
+ [ets:new(Name, ReadOptions) ||
+ Name <- [dialyzer_codeserver_contracts,
+ dialyzer_codeserver_callbacks,
+ dialyzer_codeserver_records,
+ dialyzer_codeserver_exported_types]],
TempOptions = [public, {write_concurrency, true}],
[Exports, FunMetaInfo, TempExportedTypes, TempRecords, TempContracts,
TempCallbacks] =
@@ -150,6 +160,10 @@ new() ->
#codeserver{code = Code,
exports = Exports,
fun_meta_info = FunMetaInfo,
+ exported_types = ExportedTypes,
+ records = Records,
+ contracts = Contracts,
+ callbacks = Callbacks,
temp_exported_types = TempExportedTypes,
temp_records = TempRecords,
temp_contracts = TempContracts,
@@ -170,13 +184,15 @@ insert(Mod, ModCode, CS) ->
Exports = cerl:module_exports(ModCode),
Attrs = cerl:module_attrs(ModCode),
Defs = cerl:module_defs(ModCode),
+ {Files, SmallDefs} = compress_file_anno(Defs),
As = cerl:get_ann(ModCode),
Funs =
[{{Mod, cerl:fname_id(Var), cerl:fname_arity(Var)},
- Val} || Val = {Var, _Fun} <- Defs],
- Keys = [Key || {Key, _Value} <- Funs],
+ Val, {Var, cerl_trees:get_label(Fun)}} || Val = {Var, Fun} <- SmallDefs],
+ Keys = [Key || {Key, _Value, _Label} <- Funs],
ModEntry = {Mod, {Name, Exports, Attrs, Keys, As}},
- true = ets:insert(CS#codeserver.code, [ModEntry|Funs]),
+ ModFileEntry = {{mod, Mod}, Files},
+ true = ets:insert(CS#codeserver.code, [ModEntry, ModFileEntry|Funs]),
CS.
-spec get_temp_exported_types(codeserver()) -> sets:set(mfa()).
@@ -220,12 +236,12 @@ get_exports(#codeserver{exports = Exports}) ->
-spec finalize_exported_types(sets:set(mfa()), codeserver()) -> codeserver().
-finalize_exported_types(Set, CS) ->
- ExportedTypes = ets_read_concurrent_table(dialyzer_codeserver_exported_types),
+finalize_exported_types(Set,
+ #codeserver{exported_types = ExportedTypes,
+ temp_exported_types = TempETypes} = CS) ->
true = ets_set_insert_set(Set, ExportedTypes),
- TempExpTypes = CS#codeserver.temp_exported_types,
- true = ets:delete(TempExpTypes),
- CS#codeserver{exported_types = ExportedTypes, temp_exported_types = clean}.
+ true = ets:delete(TempETypes),
+ CS#codeserver{temp_exported_types = clean}.
-spec lookup_mod_code(atom(), codeserver()) -> cerl:c_module().
@@ -237,6 +253,11 @@ lookup_mod_code(Mod, CS) when is_atom(Mod) ->
lookup_mfa_code({_M, _F, _A} = MFA, CS) ->
table__lookup(CS#codeserver.code, MFA).
+-spec lookup_mfa_var_label(mfa(), codeserver()) -> {cerl:c_var(), label()}.
+
+lookup_mfa_var_label({_M, _F, _A} = MFA, CS) ->
+ ets:lookup_element(CS#codeserver.code, MFA, 3).
+
-spec get_next_core_label(codeserver()) -> label().
get_next_core_label(#codeserver{next_core_label = NCL}) ->
@@ -251,8 +272,8 @@ set_next_core_label(NCL, CS) ->
lookup_mod_records(Mod, #codeserver{records = RecDict}) when is_atom(Mod) ->
case ets_dict_find(Mod, RecDict) of
- error -> dict:new();
- {ok, Dict} -> Dict
+ error -> maps:new();
+ {ok, Map} -> Map
end.
-spec get_records(codeserver()) -> mod_records().
@@ -262,11 +283,11 @@ get_records(#codeserver{records = RecDict}) ->
-spec store_temp_records(module(), types(), codeserver()) -> codeserver().
-store_temp_records(Mod, Dict, #codeserver{temp_records = TempRecDict} = CS)
+store_temp_records(Mod, Map, #codeserver{temp_records = TempRecDict} = CS)
when is_atom(Mod) ->
- case dict:size(Dict) =:= 0 of
+ case maps:size(Map) =:= 0 of
true -> CS;
- false -> CS#codeserver{temp_records = ets_dict_store(Mod, Dict, TempRecDict)}
+ false -> CS#codeserver{temp_records = ets_map_store(Mod, Map, TempRecDict)}
end.
-spec get_temp_records(codeserver()) -> mod_records().
@@ -284,20 +305,20 @@ set_temp_records(Dict, CS) ->
-spec finalize_records(mod_records(), codeserver()) -> codeserver().
-finalize_records(Dict, CS) ->
- true = ets:delete(CS#codeserver.temp_records),
- Records = ets_read_concurrent_table(dialyzer_codeserver_records),
+finalize_records(Dict, #codeserver{temp_records = TmpRecords,
+ records = Records} = CS) ->
+ true = ets:delete(TmpRecords),
true = ets_dict_store_dict(Dict, Records),
- CS#codeserver{records = Records, temp_records = clean}.
+ CS#codeserver{temp_records = clean}.
-spec lookup_mod_contracts(atom(), codeserver()) -> contracts().
lookup_mod_contracts(Mod, #codeserver{contracts = ContDict})
when is_atom(Mod) ->
case ets_dict_find(Mod, ContDict) of
- error -> dict:new();
+ error -> maps:new();
{ok, Keys} ->
- dict:from_list([get_file_contract(Key, ContDict)|| Key <- Keys])
+ maps:from_list([get_file_contract(Key, ContDict)|| Key <- Keys])
end.
get_file_contract(Key, ContDict) ->
@@ -330,48 +351,69 @@ get_callbacks(#codeserver{callbacks = CallbDict}) ->
-spec store_temp_contracts(module(), contracts(), contracts(), codeserver()) ->
codeserver().
-store_temp_contracts(Mod, SpecDict, CallbackDict,
+store_temp_contracts(Mod, SpecMap, CallbackMap,
#codeserver{temp_contracts = Cn,
temp_callbacks = Cb} = CS)
when is_atom(Mod) ->
- CS1 =
- case dict:size(SpecDict) =:= 0 of
- true -> CS;
- false ->
- CS#codeserver{temp_contracts = ets_dict_store(Mod, SpecDict, Cn)}
- end,
- case dict:size(CallbackDict) =:= 0 of
- true -> CS1;
- false ->
- CS1#codeserver{temp_callbacks = ets_dict_store(Mod, CallbackDict, Cb)}
- end.
-
--spec get_temp_contracts(codeserver()) -> {mod_contracts(), mod_contracts()}.
+ CS1 = CS#codeserver{temp_contracts = ets_map_store(Mod, SpecMap, Cn)},
+ CS1#codeserver{temp_callbacks = ets_map_store(Mod, CallbackMap, Cb)}.
-get_temp_contracts(#codeserver{temp_contracts = TempContDict,
- temp_callbacks = TempCallDict}) ->
- {ets_dict_to_dict(TempContDict), ets_dict_to_dict(TempCallDict)}.
+-spec contracts_modules(codeserver()) -> [module()].
--spec finalize_contracts(mod_contracts(), mod_contracts(), codeserver()) ->
- codeserver().
+contracts_modules(#codeserver{temp_contracts = TempContTable}) ->
+ ets:select(TempContTable, [{{'$1', '$2'}, [], ['$1']}]).
-finalize_contracts(SpecDict, CallbackDict, CS) ->
- Contracts = ets_read_concurrent_table(dialyzer_codeserver_contracts),
- Callbacks = ets_read_concurrent_table(dialyzer_codeserver_callbacks),
- Contracts = dict:fold(fun decompose_spec_dict/3, Contracts, SpecDict),
- Callbacks = dict:fold(fun decompose_cb_dict/3, Callbacks, CallbackDict),
- CS#codeserver{contracts = Contracts, callbacks = Callbacks,
- temp_contracts = clean, temp_callbacks = clean}.
+-spec store_contracts(module(), contracts(), contracts(), codeserver()) ->
+ codeserver().
-decompose_spec_dict(Mod, Dict, Table) ->
- Keys = dict:fetch_keys(Dict),
- true = ets:insert(Table, dict:to_list(Dict)),
- true = ets:insert(Table, {Mod, Keys}),
- Table.
+store_contracts(Mod, SpecMap, CallbackMap, CS) ->
+ #codeserver{contracts = SpecDict, callbacks = CallbackDict} = CS,
+ Keys = maps:keys(SpecMap),
+ true = ets:insert(SpecDict, maps:to_list(SpecMap)),
+ true = ets:insert(SpecDict, {Mod, Keys}),
+ true = ets:insert(CallbackDict, maps:to_list(CallbackMap)),
+ CS.
-decompose_cb_dict(_Mod, Dict, Table) ->
- true = ets:insert(Table, dict:to_list(Dict)),
- Table.
+-spec get_temp_contracts(module(), codeserver()) ->
+ {contracts(), contracts()}.
+
+get_temp_contracts(Mod, #codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict}) ->
+ [{Mod, Contracts}] = ets:lookup(TempContDict, Mod),
+ true = ets:delete(TempContDict, Mod),
+ [{Mod, Callbacks}] = ets:lookup(TempCallDict, Mod),
+ true = ets:delete(TempCallDict, Mod),
+ {Contracts, Callbacks}.
+
+-spec give_away(codeserver(), pid()) -> 'ok'.
+
+give_away(#codeserver{temp_records = TempRecords,
+ temp_contracts = TempContracts,
+ temp_callbacks = TempCallbacks,
+ records = Records,
+ contracts = Contracts,
+ callbacks = Callbacks}, Pid) ->
+ _ = [true = ets:give_away(Table, Pid, any) ||
+ Table <- [TempRecords, TempContracts, TempCallbacks,
+ Records, Contracts, Callbacks],
+ Table =/= clean],
+ ok.
+
+-spec finalize_contracts(codeserver()) -> codeserver().
+
+finalize_contracts(#codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict} = CS) ->
+ true = ets:delete(TempContDict),
+ true = ets:delete(TempCallDict),
+ CS#codeserver{temp_contracts = clean, temp_callbacks = clean}.
+
+-spec translate_fake_file(codeserver(), module(), file:filename()) ->
+ file:filename().
+
+translate_fake_file(#codeserver{code = Code}, Module, FakeFile) ->
+ Files = ets:lookup_element(Code, {mod, Module}, 2),
+ {FakeFile, File} = lists:keyfind(FakeFile, 1, Files),
+ File.
table__lookup(TablePid, M) when is_atom(M) ->
{Name, Exports, Attrs, Keys, As} = ets:lookup_element(TablePid, M, 2),
@@ -379,3 +421,25 @@ table__lookup(TablePid, M) when is_atom(M) ->
cerl:ann_c_module(As, Name, Exports, Attrs, Defs);
table__lookup(TablePid, MFA) ->
ets:lookup_element(TablePid, MFA, 2).
+
+compress_file_anno(Term) ->
+ {Files, SmallTerm} = compress_file_anno(Term, []),
+ {[{FakeFile, File} || {File, {file, FakeFile}} <- Files], SmallTerm}.
+
+compress_file_anno({file, F}, Fs) when is_list(F) ->
+ case lists:keyfind(F, 1, Fs) of
+ false ->
+ I = integer_to_list(length(Fs)),
+ FileI = {file, I},
+ NFs = [{F, FileI}|Fs],
+ {NFs, FileI};
+ {F, FileI} -> {Fs, FileI}
+ end;
+compress_file_anno(T, Fs) when is_tuple(T) ->
+ {NFs, NL} = compress_file_anno(tuple_to_list(T), Fs),
+ {NFs, list_to_tuple(NL)};
+compress_file_anno([E|L], Fs) ->
+ {Fs1, NE} = compress_file_anno(E, Fs),
+ {NFs, NL} = compress_file_anno(L, Fs1),
+ {NFs, [NE|NL]};
+compress_file_anno(T, Fs) -> {Fs, T}.
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index 976a2b8955..b101f710e7 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
get_contract_return/2,
%% get_contract_signature/1,
is_overloaded/1,
- process_contract_remote_types/1,
+ process_contract_remote_types/2,
store_tmp_contract/5]).
-export_type([file_contract/0, plt_contracts/0]).
@@ -146,14 +146,13 @@ sequence([], _Delimiter) -> "";
sequence([H], _Delimiter) -> H;
sequence([H|T], Delimiter) -> H ++ Delimiter ++ sequence(T, Delimiter).
--spec process_contract_remote_types(dialyzer_codeserver:codeserver()) ->
- dialyzer_codeserver:codeserver().
+-spec process_contract_remote_types(dialyzer_codeserver:codeserver(),
+ erl_types:mod_records()) ->
+ dialyzer_codeserver:codeserver().
-process_contract_remote_types(CodeServer) ->
- {TmpContractDict, TmpCallbackDict} =
- dialyzer_codeserver:get_temp_contracts(CodeServer),
+process_contract_remote_types(CodeServer, RecordDict) ->
+ Mods = dialyzer_codeserver:contracts_modules(CodeServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer),
- RecordDict = dialyzer_codeserver:get_records(CodeServer),
ContractFun =
fun({{_M, _F, _A}=MFA, {File, TmpContract, Xtra}}, C0) ->
#tmp_contract{contract_funs = CFuns, forms = Forms} = TmpContract,
@@ -165,20 +164,21 @@ process_contract_remote_types(CodeServer) ->
{{MFA, {File, Contract, Xtra}}, C2}
end,
ModuleFun =
- fun({ModuleName, ContractDict}, C3) ->
- {NewContractList, C4} =
- lists:mapfoldl(ContractFun, C3, dict:to_list(ContractDict)),
- {{ModuleName, dict:from_list(NewContractList)}, C4}
+ fun(ModuleName) ->
+ Cache = erl_types:cache__new(),
+ {ContractMap, CallbackMap} =
+ dialyzer_codeserver:get_temp_contracts(ModuleName, CodeServer),
+ {NewContractList, Cache1} =
+ lists:mapfoldl(ContractFun, Cache, maps:to_list(ContractMap)),
+ {NewCallbackList, _NewCache} =
+ lists:mapfoldl(ContractFun, Cache1, maps:to_list(CallbackMap)),
+ dialyzer_codeserver:store_contracts(ModuleName,
+ maps:from_list(NewContractList),
+ maps:from_list(NewCallbackList),
+ CodeServer)
end,
- Cache = erl_types:cache__new(),
- {NewContractList, C5} =
- lists:mapfoldl(ModuleFun, Cache, dict:to_list(TmpContractDict)),
- {NewCallbackList, _C6} =
- lists:mapfoldl(ModuleFun, C5, dict:to_list(TmpCallbackDict)),
- NewContractDict = dict:from_list(NewContractList),
- NewCallbackDict = dict:from_list(NewCallbackList),
- dialyzer_codeserver:finalize_contracts(NewContractDict, NewCallbackDict,
- CodeServer).
+ lists:foreach(ModuleFun, Mods),
+ dialyzer_codeserver:finalize_contracts(CodeServer).
-type opaques_fun() :: fun((module()) -> [erl_types:erl_type()]).
@@ -232,7 +232,7 @@ check_contract(#contract{contracts = Contracts}, SuccType, Opaques) ->
error ->
{error, {overlapping_contract, []}};
ok ->
- InfList = [erl_types:t_inf(Contract, SuccType, Opaques)
+ InfList = [{Contract, erl_types:t_inf(Contract, SuccType, Opaques)}
|| Contract <- Contracts2],
case check_contract_inf_list(InfList, SuccType, Opaques) of
{error, _} = Invalid -> Invalid;
@@ -256,10 +256,21 @@ check_domains([Dom|Doms]) ->
%% Allow a contract if one of the overloaded contracts is possible.
%% We used to be more strict, e.g., all overloaded contracts had to be
%% possible.
-check_contract_inf_list([FunType|Left], SuccType, Opaques) ->
+check_contract_inf_list(List, SuccType, Opaques) ->
+ case check_contract_inf_list(List, SuccType, Opaques, []) of
+ ok -> ok;
+ {error, []} -> {error, invalid_contract};
+ {error, [{SigRange, ContrRange}|_]} ->
+ case erl_types:t_find_opaque_mismatch(SigRange, ContrRange, Opaques) of
+ error -> {error, invalid_contract};
+ {ok, _T1, T2} -> {error, {opaque_mismatch, T2}}
+ end
+ end.
+
+check_contract_inf_list([{Contract, FunType}|Left], SuccType, Opaques, OM) ->
FunArgs = erl_types:t_fun_args(FunType),
case lists:any(fun erl_types:t_is_none_or_unit/1, FunArgs) of
- true -> check_contract_inf_list(Left, SuccType, Opaques);
+ true -> check_contract_inf_list(Left, SuccType, Opaques, OM);
false ->
STRange = erl_types:t_fun_range(SuccType),
case erl_types:t_is_none_or_unit(STRange) of
@@ -267,13 +278,16 @@ check_contract_inf_list([FunType|Left], SuccType, Opaques) ->
false ->
Range = erl_types:t_fun_range(FunType),
case erl_types:t_is_none(erl_types:t_inf(STRange, Range)) of
- true -> check_contract_inf_list(Left, SuccType, Opaques);
+ true ->
+ CR = erl_types:t_fun_range(Contract),
+ NewOM = [{STRange, CR}|OM],
+ check_contract_inf_list(Left, SuccType, Opaques, NewOM);
false -> ok
end
end
end;
-check_contract_inf_list([], _SuccType, _Opaques) ->
- {error, invalid_contract}.
+check_contract_inf_list([], _SuccType, _Opaques, OM) ->
+ {error, OM}.
check_extraneous([], _SuccType) -> ok;
check_extraneous([C|Cs], SuccType) ->
@@ -383,7 +397,7 @@ solve_constraints(Contract, Call, Constraints) ->
%% ?debug("Inf: ~s\n", [erl_types:t_to_string(Inf)]),
%% erl_types:t_assign_variables_to_subtype(Contract, Inf).
--type contracts() :: dict:dict(mfa(),dialyzer_contracts:file_contract()).
+-type contracts() :: dialyzer_codeserver:contracts().
%% Checks the contracts for functions that are not implemented
-spec contracts_without_fun(contracts(), [_], dialyzer_callgraph:callgraph()) ->
@@ -393,12 +407,12 @@ contracts_without_fun(Contracts, AllFuns0, Callgraph) ->
AllFuns1 = [{dialyzer_callgraph:lookup_name(Label, Callgraph), Arity}
|| {Label, Arity} <- AllFuns0],
AllFuns2 = [{M, F, A} || {{ok, {M, F, _}}, A} <- AllFuns1],
- AllContractMFAs = dict:fetch_keys(Contracts),
+ AllContractMFAs = maps:keys(Contracts),
ErrorContractMFAs = AllContractMFAs -- AllFuns2,
[warn_spec_missing_fun(MFA, Contracts) || MFA <- ErrorContractMFAs].
warn_spec_missing_fun({M, F, A} = MFA, Contracts) ->
- {{File, Line}, _Contract, _Xtra} = dict:fetch(MFA, Contracts),
+ {{File, Line}, _Contract, _Xtra} = maps:get(MFA, Contracts),
WarningInfo = {File, Line, MFA},
{?WARN_CONTRACT_SYNTAX, WarningInfo, {spec_missing_fun, [M, F, A]}}.
@@ -431,11 +445,11 @@ insert_constraints([], Map) -> Map.
-spec store_tmp_contract(mfa(), file_line(), spec_data(), contracts(), types()) ->
contracts().
-store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecDict, RecordsDict) ->
+store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecMap, RecordsDict) ->
%% io:format("contract from form: ~p\n", [TypeSpec]),
TmpContract = contract_from_form(TypeSpec, MFA, RecordsDict, FileLine),
%% io:format("contract: ~p\n", [TmpContract]),
- dict:store(MFA, {FileLine, TmpContract, Xtra}, SpecDict).
+ maps:put(MFA, {FileLine, TmpContract, Xtra}, SpecMap).
contract_from_form(Forms, MFA, RecDict, FileLine) ->
{CFuns, Forms1} = contract_from_form(Forms, MFA, RecDict, FileLine, [], []),
@@ -663,7 +677,7 @@ get_invalid_contract_warnings(Modules, CodeServer, Plt, FindOpaques) ->
get_invalid_contract_warnings_modules([Mod|Mods], CodeServer, Plt, FindOpaques, Acc) ->
Contracts1 = dialyzer_codeserver:lookup_mod_contracts(Mod, CodeServer),
- Contracts2 = dict:to_list(Contracts1),
+ Contracts2 = maps:to_list(Contracts1),
Records = dialyzer_codeserver:lookup_mod_records(Mod, CodeServer),
NewAcc = get_invalid_contract_warnings_funs(Contracts2, Plt, Records, FindOpaques, Acc),
get_invalid_contract_warnings_modules(Mods, CodeServer, Plt, FindOpaques, NewAcc);
@@ -687,6 +701,9 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left],
case check_contract(Contract, Sig, Opaques) of
{error, invalid_contract} ->
[invalid_contract_warning(MFA, WarningInfo, Sig, RecDict)|Acc];
+ {error, {opaque_mismatch, T2}} ->
+ W = contract_opaque_warning(MFA, WarningInfo, T2, Sig, RecDict),
+ [W|Acc];
{error, {overlapping_contract, []}} ->
[overlapping_contract_warning(MFA, WarningInfo)|Acc];
{error, {extra_range, ExtraRanges, STRange}} ->
@@ -740,6 +757,12 @@ invalid_contract_warning({M, F, A}, WarningInfo, SuccType, RecDict) ->
SuccTypeStr = dialyzer_utils:format_sig(SuccType, RecDict),
{?WARN_CONTRACT_TYPES, WarningInfo, {invalid_contract, [M, F, A, SuccTypeStr]}}.
+contract_opaque_warning({M, F, A}, WarningInfo, OpType, SuccType, RecDict) ->
+ OpaqueStr = erl_types:t_to_string(OpType),
+ SuccTypeStr = dialyzer_utils:format_sig(SuccType, RecDict),
+ {?WARN_CONTRACT_TYPES, WarningInfo,
+ {contract_with_opaque, [M, F, A, OpaqueStr, SuccTypeStr]}}.
+
overlapping_contract_warning({M, F, A}, WarningInfo) ->
{?WARN_CONTRACT_TYPES, WarningInfo, {overlapping_contract, [M, F, A]}}.
@@ -768,19 +791,9 @@ picky_contract_check(CSig0, Sig0, MFA, WarningInfo, Contract, RecDict, Acc) ->
end.
extra_contract_warning(MFA, WarningInfo, Contract, CSig, Sig, RecDict) ->
- %% We do not want to depend upon erl_types:t_to_string() possibly
- %% hiding the contents of opaque types.
- SigUnopaque = erl_types:t_unopaque(Sig),
- CSigUnopaque = erl_types:t_unopaque(CSig),
- SigString0 =
- lists:flatten(dialyzer_utils:format_sig(SigUnopaque, RecDict)),
- ContractString0 =
- lists:flatten(dialyzer_utils:format_sig(CSigUnopaque, RecDict)),
- %% The only difference is in record fields containing 'undefined' or not.
- IsUndefRecordFieldsRelated = SigString0 =:= ContractString0,
{IsRemoteTypesRelated, SubtypeRelation} =
is_remote_types_related(Contract, CSig, Sig, MFA, RecDict),
- case IsUndefRecordFieldsRelated orelse IsRemoteTypesRelated of
+ case IsRemoteTypesRelated of
true ->
no_warning;
false ->
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 9399789464..83ce875280 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -529,7 +529,7 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
case is_race_analysis_enabled(State) of
true ->
Ann = cerl:get_ann(Tree),
- File = get_file(Ann),
+ File = get_file(Ann, State),
Line = abs(get_line(Ann)),
dialyzer_races:store_race_call(Fun, ArgTypes, Args,
{File, Line}, State);
@@ -978,12 +978,21 @@ handle_case(Tree, Map, State) ->
false -> State1
end,
Map2 = join_maps_begin(Map1),
- {MapList, State3, Type} =
+ {MapList, State3, Type, Warns} =
handle_clauses(Clauses, Arg, ArgType, ArgType, State2,
- [], Map2, [], []),
+ [], Map2, [], [], []),
+ %% Non-Erlang BEAM languages, such as Elixir, expand language constructs
+ %% into case statements. In that case, we do not want to warn on
+ %% individual clauses not matching unless none of them can.
+ SupressForced = is_compiler_generated(cerl:get_ann(Tree))
+ andalso not (t_is_none(Type)),
+ State4 = lists:foldl(fun({T,R,M,F}, S) ->
+ state__add_warning(
+ S,T,R,M,F andalso (not SupressForced))
+ end, State3, Warns),
Map3 = join_maps_end(MapList, Map2),
debug_pp_map(Map3),
- {State3, Map3, Type}
+ {State4, Map3, Type}
end.
%%----------------------------------------
@@ -1082,22 +1091,24 @@ handle_receive(Tree, Map, State) ->
RaceListSize + 1, State);
false -> State
end,
- {MapList, State2, ReceiveType} =
+ {MapList, State2, ReceiveType, Warns} =
handle_clauses(Clauses, ?no_arg, t_any(), t_any(), State1, [], Map,
- [], []),
+ [], [], []),
+ State3 = lists:foldl(fun({T,R,M,F}, S) -> state__add_warning(S,T,R,M,F) end,
+ State2, Warns),
Map1 = join_maps(MapList, Map),
- {State3, Map2, TimeoutType} = traverse(Timeout, Map1, State2),
- Opaques = State3#state.opaques,
+ {State4, Map2, TimeoutType} = traverse(Timeout, Map1, State3),
+ Opaques = State4#state.opaques,
case (t_is_atom(TimeoutType, Opaques) andalso
(t_atom_vals(TimeoutType, Opaques) =:= ['infinity'])) of
true ->
- {State3, Map2, ReceiveType};
+ {State4, Map2, ReceiveType};
false ->
Action = cerl:receive_action(Tree),
- {State4, Map3, ActionType} = traverse(Action, Map, State3),
+ {State5, Map3, ActionType} = traverse(Action, Map, State4),
Map4 = join_maps([Map3, Map1], Map),
Type = t_sup(ReceiveType, ActionType),
- {State4, Map4, Type}
+ {State5, Map4, Type}
end.
%%----------------------------------------
@@ -1200,7 +1211,7 @@ handle_tuple(Tree, Map, State) ->
TagVal = cerl:atom_val(Tag),
case state__lookup_record(TagVal, length(Left), State1) of
error -> {State1, Map1, TupleType};
- {ok, RecType} ->
+ {ok, RecType, FieldNames} ->
InfTupleType = t_inf(RecType, TupleType),
case t_is_none(InfTupleType) of
true ->
@@ -1221,10 +1232,13 @@ handle_tuple(Tree, Map, State) ->
Tree, Msg),
{State2, Map1, t_none()};
{error, opaque, ErrorPat, ErrorType, OpaqueType} ->
+ OpaqueStr = format_type(OpaqueType, State1),
+ Name = field_name(Elements, ErrorPat, FieldNames),
Msg = {opaque_match,
- [format_patterns(ErrorPat),
- format_type(ErrorType, State1),
- format_type(OpaqueType, State1)]},
+ ["record field" ++ Name ++
+ " declared to be of type " ++
+ format_type(ErrorType, State1),
+ OpaqueStr, OpaqueStr]},
State2 = state__add_warning(State1, ?WARN_OPAQUE,
Tree, Msg),
{State2, Map1, t_none()};
@@ -1241,11 +1255,20 @@ handle_tuple(Tree, Map, State) ->
end
end.
+field_name(Elements, ErrorPat, FieldNames) ->
+ try
+ [Pat] = ErrorPat,
+ Take = lists:takewhile(fun(X) -> X =/= Pat end, Elements),
+ " " ++ format_atom(lists:nth(length(Take), FieldNames))
+ catch
+ _:_ -> ""
+ end.
+
%%----------------------------------------
%% Clauses
%%
handle_clauses([C|Left], Arg, ArgType, OrigArgType, State, CaseTypes, MapIn,
- Acc, ClauseAcc) ->
+ Acc, ClauseAcc, WarnAcc0) ->
IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
State1 =
case IsRaceAnalysisEnabled of
@@ -1258,8 +1281,8 @@ handle_clauses([C|Left], Arg, ArgType, OrigArgType, State, CaseTypes, MapIn,
State);
false -> State
end,
- {State2, ClauseMap, BodyType, NewArgType} =
- do_clause(C, Arg, ArgType, OrigArgType, MapIn, State1),
+ {State2, ClauseMap, BodyType, NewArgType, WarnAcc} =
+ do_clause(C, Arg, ArgType, OrigArgType, MapIn, State1, WarnAcc0),
{NewClauseAcc, State3} =
case IsRaceAnalysisEnabled of
true ->
@@ -1277,9 +1300,9 @@ handle_clauses([C|Left], Arg, ArgType, OrigArgType, State, CaseTypes, MapIn,
false -> {[BodyType|CaseTypes], [ClauseMap|Acc]}
end,
handle_clauses(Left, Arg, NewArgType, OrigArgType, State3,
- NewCaseTypes, MapIn, NewAcc, NewClauseAcc);
+ NewCaseTypes, MapIn, NewAcc, NewClauseAcc, WarnAcc);
handle_clauses([], _Arg, _ArgType, _OrigArgType, State, CaseTypes, _MapIn, Acc,
- ClauseAcc) ->
+ ClauseAcc, WarnAcc) ->
State1 =
case is_race_analysis_enabled(State) of
true ->
@@ -1289,9 +1312,9 @@ handle_clauses([], _Arg, _ArgType, _OrigArgType, State, CaseTypes, _MapIn, Acc,
RaceListSize + 1, State);
false -> State
end,
- {lists:reverse(Acc), State1, t_sup(CaseTypes)}.
+ {lists:reverse(Acc), State1, t_sup(CaseTypes), WarnAcc}.
-do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
+do_clause(C, Arg, ArgType0, OrigArgType, Map, State, Warns) ->
Pats = cerl:clause_pats(C),
Guard = cerl:clause_guard(C),
Body = cerl:clause_body(C),
@@ -1323,13 +1346,11 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
[cerl_prettypr:format(C), format_type(ArgType0, State1)]),
case state__warning_mode(State1) of
false ->
- {State1, Map, t_none(), ArgType0};
+ {State1, Map, t_none(), ArgType0, Warns};
true ->
{Msg, Force} =
case t_is_none(ArgType0) of
true ->
- PatString = format_patterns(Pats),
- PatTypes = [PatString, format_type(OrigArgType, State1)],
%% See if this is covered by an earlier clause or if it
%% simply cannot match
OrigArgTypes =
@@ -1337,14 +1358,24 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
true -> Any = t_any(), [Any || _ <- Pats];
false -> t_to_tlist(OrigArgType)
end,
+ PatString = format_patterns(Pats),
+ ArgTypeString = format_type(OrigArgType, State1),
+ BindResOrig =
+ bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1),
Tag =
- case bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1) of
+ case BindResOrig of
{error, bind, _, _, _} -> pattern_match;
{error, record, _, _, _} -> record_match;
{error, opaque, _, _, _} -> opaque_match;
{_, _} -> pattern_match_cov
end,
- {{Tag, PatTypes}, false};
+ PatTypes = case BindResOrig of
+ {error, opaque, _, _, OpaqueType} ->
+ [PatString, ArgTypeString,
+ format_type(OpaqueType, State1)];
+ _ -> [PatString, ArgTypeString]
+ end,
+ {{Tag, PatTypes}, false};
false ->
%% Try to find out if this is a default clause in a list
%% comprehension and supress this. A real Hack(tm)
@@ -1403,8 +1434,7 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
{record_match, _} -> ?WARN_MATCHING;
{pattern_match_cov, _} -> ?WARN_MATCHING
end,
- {state__add_warning(State1, WarnType, C, Msg, Force),
- Map, t_none(), ArgType0}
+ {State1, Map, t_none(), ArgType0, [{WarnType, C, Msg, Force}|Warns]}
end;
{Map2, PatTypes} ->
Map3 =
@@ -1437,9 +1467,9 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
false ->
{guard_fail_pat, [PatString, format_type(ArgType0, State1)]}
end,
- State2 =
+ Warn =
case Reason of
- none -> state__add_warning(State1, ?WARN_MATCHING, C, DefaultMsg);
+ none -> {?WARN_MATCHING, C, DefaultMsg, false};
{FailGuard, Msg} ->
case is_compiler_generated(cerl:get_ann(FailGuard)) of
false ->
@@ -1448,15 +1478,15 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
{neg_guard_fail, _} -> ?WARN_MATCHING;
{opaque_guard, _} -> ?WARN_OPAQUE
end,
- state__add_warning(State1, WarnType, FailGuard, Msg);
+ {WarnType, FailGuard, Msg, false};
true ->
- state__add_warning(State1, ?WARN_MATCHING, C, Msg)
+ {?WARN_MATCHING, C, Msg, false}
end
end,
- {State2, Map, t_none(), NewArgType};
+ {State1, Map, t_none(), NewArgType, [Warn|Warns]};
Map4 ->
{RetState, RetMap, BodyType} = traverse(Body, Map4, State1),
- {RetState, RetMap, BodyType, NewArgType}
+ {RetState, RetMap, BodyType, NewArgType, Warns}
end
end.
@@ -1622,7 +1652,7 @@ bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) ->
TagAtom = cerl:atom_val(Tag),
case state__lookup_record(TagAtom, length(Left), State) of
error -> {false, t_tuple(length(Es))};
- {ok, Record} ->
+ {ok, Record, _FieldNames} ->
[_Head|AnyTail] = [t_any() || _ <- Es],
UntypedRecord = t_tuple([t_atom(TagAtom)|AnyTail]),
{not t_is_equal(Record, UntypedRecord), Record}
@@ -2150,7 +2180,7 @@ handle_guard_is_record(Guard, Map, Env, Eval, State) ->
TupleType =
case state__lookup_record(Tag, ArityMin1, State) of
error -> Tuple;
- {ok, Prototype} -> Prototype
+ {ok, Prototype, _FieldNames} -> Prototype
end,
Type = t_inf(TupleType, RecType, State#state.opaques),
case t_is_none(Type) of
@@ -2600,7 +2630,7 @@ bind_guard_case_clauses(Arg, Clauses, Map0, Env, Eval, State) ->
Map = join_maps_begin(Map0),
{GenMap, GenArgType} = bind_guard(Arg, Map, Env, dont_know, State),
bind_guard_case_clauses(GenArgType, GenMap, Arg, Clauses1, Map, Env, Eval,
- t_none(), [], State).
+ t_none(), [], [], State).
filter_fail_clauses([Clause|Left]) ->
case (cerl:clause_pats(Clause) =:= []) of
@@ -2619,7 +2649,7 @@ filter_fail_clauses([]) ->
[].
bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
- Map, Env, Eval, AccType, AccMaps, State) ->
+ Map, Env, Eval, AccType, AccMaps, Throws, State) ->
Pats = cerl:clause_pats(Clause),
{NewMap0, ArgType} =
case Pats of
@@ -2663,9 +2693,9 @@ bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
case (NewMap1 =:= none) orelse t_is_none(GenArgType) of
true ->
bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env,
- Eval, AccType, AccMaps, State);
+ Eval, AccType, AccMaps, Throws, State);
false ->
- {NewAccType, NewAccMaps} =
+ {NewAccType, NewAccMaps, NewThrows} =
try
{NewMap2, GuardType} = bind_guard(Guard, NewMap1, Env, pos, State),
case t_is_none(t_inf(t_atom(true), GuardType)) of
@@ -2689,17 +2719,26 @@ bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
dont_know ->
ok
end,
- {t_sup(AccType, CType), [NewMap3|AccMaps]}
+ {t_sup(AccType, CType), [NewMap3|AccMaps], Throws}
catch
- throw:{fail, _What} -> {AccType, AccMaps}
+ throw:{fail, Reason} ->
+ Throws1 = case Reason of
+ none -> Throws;
+ _ -> Throws ++ [Reason]
+ end,
+ {AccType, AccMaps, Throws1}
end,
bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env,
- Eval, NewAccType, NewAccMaps, State)
+ Eval, NewAccType, NewAccMaps, NewThrows, State)
end;
bind_guard_case_clauses(_GenArgType, _GenMap, _ArgExpr, [], Map, _Env, _Eval,
- AccType, AccMaps, _State) ->
+ AccType, AccMaps, Throws, _State) ->
case t_is_none(AccType) of
- true -> throw({fail, none});
+ true ->
+ case Throws of
+ [Throw|_] -> throw({fail, Throw});
+ [] -> throw({fail, none})
+ end;
false -> {join_maps_end(AccMaps, Map), AccType}
end.
@@ -3059,7 +3098,7 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State,
Ann = cerl:get_ann(Tree),
case Force of
true ->
- WarningInfo = {get_file(Ann),
+ WarningInfo = {get_file(Ann, State),
abs(get_line(Ann)),
State#state.curr_fun},
Warn = {Tag, WarningInfo, Msg},
@@ -3069,7 +3108,9 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State,
case is_compiler_generated(Ann) of
true -> State;
false ->
- WarningInfo = {get_file(Ann), get_line(Ann), State#state.curr_fun},
+ WarningInfo = {get_file(Ann, State),
+ get_line(Ann),
+ State#state.curr_fun},
Warn = {Tag, WarningInfo, Msg},
case Tag of
?WARN_CONTRACT_RANGE -> ok;
@@ -3197,7 +3238,8 @@ state__lookup_record(Tag, Arity, #state{records = Records}) ->
RecType =
t_tuple([t_atom(Tag)|
[FieldType || {_FieldName, _Abstr, FieldType} <- Fields]]),
- {ok, RecType};
+ FieldNames = [FieldName || {FieldName, _Abstr, _FieldType} <- Fields],
+ {ok, RecType, FieldNames};
error ->
error
end.
@@ -3467,6 +3509,12 @@ state__put_races(Races, State) ->
state__records_only(#state{records = Records}) ->
#state{records = Records}.
+-spec state__translate_file(file:filename(), state()) -> file:filename().
+
+state__translate_file(FakeFile, State) ->
+ #state{codeserver = CodeServer, module = Module} = State,
+ dialyzer_codeserver:translate_fake_file(CodeServer, Module, FakeFile).
+
%%% ===========================================================================
%%%
%%% Races
@@ -3538,9 +3586,11 @@ get_line([Line|_]) when is_integer(Line) -> Line;
get_line([_|Tail]) -> get_line(Tail);
get_line([]) -> -1.
-get_file([]) -> [];
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
+get_file([], _State) -> [];
+get_file([{file, FakeFile}|_], State) ->
+ state__translate_file(FakeFile, State);
+get_file([_|Tail], State) ->
+ get_file(Tail, State).
is_compiler_generated(Ann) ->
lists:member(compiler_generated, Ann) orelse (get_line(Ann) < 1).
@@ -3650,6 +3700,9 @@ map_pats(Pats) ->
fold_literals(TreeList) ->
[cerl:fold_literal(Tree) || Tree <- TreeList].
+format_atom(A) ->
+ format_cerl(cerl:c_atom(A)).
+
type(Tree) ->
Folded = cerl:fold_literal(Tree),
case cerl:type(Folded) of
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index 30d2bdeca4..1701aff2f2 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -310,7 +310,7 @@ createWarningsMenu() ->
addCheckedItem(WarningsMenu, ?menuID_WARN_FAIL_FUN_CALLS,
"Failing function calls"),
addCheckedItem(WarningsMenu, ?menuID_WARN_BAD_FUN, "Bad fun applications"),
- addCheckedItem(WarningsMenu, ?menuID_WARN_OPAQUE, "Opaqueness violations"),
+ addCheckedItem(WarningsMenu, ?menuID_WARN_OPAQUE, "Opacity violations"),
addCheckedItem(WarningsMenu, ?menuID_WARN_LIST_CONSTR,
"Improper list constructions"),
addCheckedItem(WarningsMenu, ?menuID_WARN_UNUSED_FUN, "Unused functions"),
@@ -505,8 +505,9 @@ gui_loop(#gui_state{backend_pid = BackendPid, doc_plt = DocPlt,
end,
ExplanationPid = spawn_link(Fun),
gui_loop(State#gui_state{expl_pid = ExplanationPid});
- {BackendPid, done, _NewPlt, NewDocPlt} ->
+ {BackendPid, done, NewMiniPlt, NewDocPlt} ->
message(State, "Analysis done"),
+ dialyzer_plt:delete(NewMiniPlt),
config_gui_stop(State),
gui_loop(State#gui_state{doc_plt = NewDocPlt});
{'EXIT', BackendPid, {error, Reason}} ->
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index add660eae9..e71a0fca9d 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index cf2f0e919e..d054d5a5a0 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -2,7 +2,7 @@
%%----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,7 +58,9 @@
get_specs/4,
to_file/4,
get_mini_plt/1,
- restore_full_plt/2
+ restore_full_plt/1,
+ delete/1,
+ give_away/2
]).
%% Debug utilities
@@ -82,14 +84,16 @@
%%----------------------------------------------------------------------
-record(plt, {info = table_new() :: dict:dict(),
- types = table_new() :: dict:dict(),
+ types = table_new() :: erl_types:mod_records(),
contracts = table_new() :: dict:dict(),
callbacks = table_new() :: dict:dict(),
exported_types = sets:new() :: sets:set()}).
-record(mini_plt, {info :: ets:tid(),
+ types :: ets:tid(),
contracts :: ets:tid(),
- callbacks :: ets:tid()
+ callbacks :: ets:tid(),
+ exported_types :: ets:tid()
}).
-opaque plt() :: #plt{} | #mini_plt{}.
@@ -130,6 +134,10 @@ delete_module(#plt{info = Info, types = Types,
-spec delete_list(plt(), [mfa() | integer()]) -> plt().
+delete_list(#mini_plt{info = Info,
+ contracts = Contracts}=Plt, List) ->
+ Plt#mini_plt{info = ets_table_delete_list(Info, List),
+ contracts = ets_table_delete_list(Contracts, List)};
delete_list(#plt{info = Info, types = Types,
contracts = Contracts,
callbacks = Callbacks,
@@ -183,7 +191,7 @@ lookup(Plt, Label) when is_integer(Label) ->
lookup_1(#mini_plt{info = Info}, MFAorLabel) ->
ets_table_lookup(Info, MFAorLabel).
--spec insert_types(plt(), dict:dict()) -> plt().
+-spec insert_types(plt(), erl_types:mod_records()) -> plt().
insert_types(PLT, Rec) ->
PLT#plt{types = Rec}.
@@ -193,7 +201,7 @@ insert_types(PLT, Rec) ->
insert_exported_types(PLT, Set) ->
PLT#plt{exported_types = Set}.
--spec get_types(plt()) -> dict:dict().
+-spec get_types(plt()) -> erl_types:mod_records().
get_types(#plt{types = Types}) ->
Types.
@@ -226,12 +234,8 @@ contains_mfa(#plt{info = Info, contracts = Contracts}, MFA) ->
get_default_plt() ->
case os:getenv("DIALYZER_PLT") of
false ->
- case os:getenv("HOME") of
- false ->
- plt_error("The HOME environment variable needs to be set " ++
- "so that Dialyzer knows where to find the default PLT");
- HomeDir -> filename:join(HomeDir, ".dialyzer_plt")
- end;
+ {ok,[[HomeDir]]} = init:get_argument(home),
+ filename:join(HomeDir, ".dialyzer_plt");
UserSpecPlt -> UserSpecPlt
end.
@@ -253,8 +257,10 @@ from_file(FileName, ReturnInfo) ->
Msg = io_lib:format("Old PLT file ~s\n", [FileName]),
plt_error(Msg);
ok ->
+ Types = [{Mod, maps:from_list(dict:to_list(Types))} ||
+ {Mod, Types} <- dict:to_list(Rec#file_plt.types)],
Plt = #plt{info = Rec#file_plt.info,
- types = Rec#file_plt.types,
+ types = dict:from_list(Types),
contracts = Rec#file_plt.contracts,
callbacks = Rec#file_plt.callbacks,
exported_types = Rec#file_plt.exported_types},
@@ -371,12 +377,14 @@ to_file(FileName,
end,
OldModDeps, ModDeps),
ImplMd5 = compute_implementation_md5(),
+ FileTypes = dict:from_list([{Mod, dict:from_list(maps:to_list(MTypes))} ||
+ {Mod, MTypes} <- dict:to_list(Types)]),
Record = #file_plt{version = ?VSN,
file_md5_list = MD5,
info = Info,
contracts = Contracts,
callbacks = Callbacks,
- types = Types,
+ types = FileTypes,
exported_types = ExpTypes,
mod_deps = NewModDeps,
implementation_md5 = ImplMd5},
@@ -510,32 +518,100 @@ init_md5_list_1(Md5List, [], Acc) ->
-spec get_mini_plt(plt()) -> plt().
-get_mini_plt(#plt{info = Info, contracts = Contracts, callbacks = Callbacks}) ->
- [ETSInfo, ETSContracts, ETSCallbacks] =
- [ets:new(Name, [public]) || Name <- [plt_info, plt_contracts, plt_callbacks]],
+get_mini_plt(#plt{info = Info,
+ types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
+ exported_types = ExpTypes}) ->
+ [ETSInfo, ETSTypes, ETSContracts, ETSCallbacks, ETSExpTypes] =
+ [ets:new(Name, [public]) ||
+ Name <- [plt_info, plt_types, plt_contracts, plt_callbacks,
+ plt_exported_types]],
CallbackList = dict:to_list(Callbacks),
CallbacksByModule =
[{M, [Cb || {{M1,_,_},_} = Cb <- CallbackList, M1 =:= M]} ||
M <- lists:usort([M || {{M,_,_},_} <- CallbackList])],
- [true, true] =
+ [true, true, true] =
[ets:insert(ETS, dict:to_list(Data)) ||
- {ETS, Data} <- [{ETSInfo, Info}, {ETSContracts, Contracts}]],
+ {ETS, Data} <- [{ETSInfo, Info},
+ {ETSTypes, Types},
+ {ETSContracts, Contracts}]],
true = ets:insert(ETSCallbacks, CallbacksByModule),
- #mini_plt{info = ETSInfo, contracts = ETSContracts, callbacks = ETSCallbacks};
+ true = ets:insert(ETSExpTypes, [{ET} || ET <- sets:to_list(ExpTypes)]),
+ #mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes};
get_mini_plt(undefined) ->
undefined.
--spec restore_full_plt(plt(), plt()) -> plt().
-
-restore_full_plt(#mini_plt{info = ETSInfo, contracts = ETSContracts}, Plt) ->
- Info = dict:from_list(ets:tab2list(ETSInfo)),
- Contracts = dict:from_list(ets:tab2list(ETSContracts)),
- ets:delete(ETSContracts),
- ets:delete(ETSInfo),
- Plt#plt{info = Info, contracts = Contracts};
-restore_full_plt(undefined, undefined) ->
+-spec restore_full_plt(plt()) -> plt().
+
+restore_full_plt(#mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes} = MiniPlt) ->
+ Info = dict:from_list(tab2list(ETSInfo)),
+ Contracts = dict:from_list(tab2list(ETSContracts)),
+ Types = dict:from_list(tab2list(ETSTypes)),
+ Callbacks =
+ dict:from_list([Cb || {_M, Cbs} <- tab2list(ETSCallbacks), Cb <- Cbs]),
+ ExpTypes = sets:from_list([E || {E} <- tab2list(ETSExpTypes)]),
+ ok = delete(MiniPlt),
+ #plt{info = Info,
+ types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
+ exported_types = ExpTypes};
+restore_full_plt(undefined) ->
undefined.
+-spec delete(plt()) -> 'ok'.
+
+delete(#mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes}) ->
+ true = ets:delete(ETSContracts),
+ true = ets:delete(ETSTypes),
+ true = ets:delete(ETSInfo),
+ true = ets:delete(ETSCallbacks),
+ true = ets:delete(ETSExpTypes),
+ ok.
+
+-spec give_away(plt(), pid()) -> 'ok'.
+
+give_away(#mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes},
+ Pid) ->
+ true = ets:give_away(ETSContracts, Pid, any),
+ true = ets:give_away(ETSTypes, Pid, any),
+ true = ets:give_away(ETSInfo, Pid, any),
+ true = ets:give_away(ETSCallbacks, Pid, any),
+ true = ets:give_away(ETSExpTypes, Pid, any),
+ ok.
+
+%% Somewhat slower than ets:tab2list(), but uses less memory.
+tab2list(T) ->
+ tab2list(ets:first(T), T, []).
+
+tab2list('$end_of_table', T, A) ->
+ case ets:first(T) of % no safe_fixtable()...
+ '$end_of_table' -> A;
+ Key -> tab2list(Key, T, A)
+ end;
+tab2list(Key, T, A) ->
+ Vs = ets:lookup(T, Key),
+ Key1 = ets:next(T, Key),
+ ets:delete(T, Key),
+ tab2list(Key1, T, Vs ++ A).
+
%%---------------------------------------------------------------------------
%% Edoc
@@ -607,6 +683,12 @@ table_delete_module1(Plt, Mod) ->
table_delete_module2(Plt, Mod) ->
dict:filter(fun(M, _Val) -> M =/= Mod end, Plt).
+ets_table_delete_list(Tab, [H|T]) ->
+ ets:delete(Tab, H),
+ ets_table_delete_list(Tab, T);
+ets_table_delete_list(Tab, []) ->
+ Tab.
+
table_delete_list(Plt, [H|T]) ->
table_delete_list(dict:erase(H, Plt), T);
table_delete_list(Plt, []) ->
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index 987da3aecf..705a870786 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -96,7 +96,7 @@ analyze_callgraph(Callgraph, Plt, Codeserver, TimingServer, Solvers, Parent) ->
NewState =
init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
TimingServer, Solvers, Parent),
- dialyzer_plt:restore_full_plt(NewState#st.plt, Plt).
+ NewState#st.plt.
%%--------------------------------------------------------------------
@@ -111,6 +111,7 @@ init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
get_refined_success_typings(SCCs, #st{callgraph = Callgraph,
timing_server = TimingServer} = State) ->
+ erlang:garbage_collect(),
case find_succ_typings(SCCs, State) of
{fixpoint, State1} -> State1;
{not_fixpoint, NotFixpoint1, State1} ->
@@ -155,8 +156,8 @@ get_warnings(Callgraph, Plt, DocPlt, Codeserver,
?timing(TimingServer, "warning",
get_warnings_from_modules(Mods, InitState, MiniDocPlt)),
{postprocess_warnings(CWarns ++ ModWarns, Codeserver),
- dialyzer_plt:restore_full_plt(MiniPlt, Plt),
- dialyzer_plt:restore_full_plt(MiniDocPlt, DocPlt)}.
+ MiniPlt,
+ dialyzer_plt:restore_full_plt(MiniDocPlt)}.
get_warnings_from_modules(Mods, State, DocPlt) ->
#st{callgraph = Callgraph, codeserver = Codeserver,
@@ -174,10 +175,10 @@ collect_warnings(M, {Codeserver, Callgraph, Plt, DocPlt}) ->
%% Check if there are contracts for functions that do not exist
Warnings1 =
dialyzer_contracts:contracts_without_fun(Contracts, AllFuns, Callgraph),
+ Attrs = cerl:module_attrs(ModCode),
{Warnings2, FunTypes} =
dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Codeserver,
Records),
- Attrs = cerl:module_attrs(ModCode),
Warnings3 =
dialyzer_behaviours:check_callbacks(M, Attrs, Records, Plt, Codeserver),
DocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt),
@@ -262,7 +263,7 @@ refine_one_module(M, {CodeServer, Callgraph, Plt, _Solvers}) ->
NewFunTypes =
dialyzer_dataflow:get_fun_types(ModCode, Plt, Callgraph, CodeServer, Records),
Contracts1 = dialyzer_codeserver:lookup_mod_contracts(M, CodeServer),
- Contracts = orddict:from_list(dict:to_list(Contracts1)),
+ Contracts = orddict:from_list(maps:to_list(Contracts1)),
FindOpaques = find_opaques_fun(Records),
DecoratedFunTypes =
decorate_succ_typings(Contracts, Callgraph, NewFunTypes, FindOpaques),
@@ -348,21 +349,25 @@ find_succ_typings(SCCs, #st{codeserver = Codeserver, callgraph = Callgraph,
-spec find_succ_types_for_scc(scc(), typesig_init_data()) -> [mfa_or_funlbl()].
-find_succ_types_for_scc(SCC, {Codeserver, Callgraph, Plt, Solvers}) ->
- SCC_Info = [{MFA,
- dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
- dialyzer_codeserver:lookup_mod_records(M, Codeserver)}
- || {M, _, _} = MFA <- SCC],
+find_succ_types_for_scc(SCC0, {Codeserver, Callgraph, Plt, Solvers}) ->
+ SCC = [MFA || {_, _, _} = MFA <- SCC0],
Contracts1 = [{MFA, dialyzer_codeserver:lookup_mfa_contract(MFA, Codeserver)}
- || {_, _, _} = MFA <- SCC],
+ || MFA <- SCC],
Contracts2 = [{MFA, Contract} || {MFA, {ok, Contract}} <- Contracts1],
Contracts3 = orddict:from_list(Contracts2),
Label = dialyzer_codeserver:get_next_core_label(Codeserver),
- AllFuns = collect_fun_info([Fun || {_MFA, {_Var, Fun}, _Rec} <- SCC_Info]),
+ AllFuns = lists:append(
+ [begin
+ {_Var, Fun} =
+ dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
+ collect_fun_info([Fun])
+ end || MFA <- SCC]),
+ erlang:garbage_collect(),
PropTypes = get_fun_types_from_plt(AllFuns, Callgraph, Plt),
%% Assume that the PLT contains the current propagated types
- FunTypes = dialyzer_typesig:analyze_scc(SCC_Info, Label, Callgraph,
- Plt, PropTypes, Solvers),
+ FunTypes = dialyzer_typesig:analyze_scc(SCC, Label, Callgraph,
+ Codeserver, Plt, PropTypes,
+ Solvers),
AllFunSet = sets:from_list([X || {X, _} <- AllFuns]),
FilteredFunTypes =
dict:filter(fun(X, _) -> sets:is_element(X, AllFunSet) end, FunTypes),
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index 1787b66192..4d650592e2 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
-module(dialyzer_typesig).
--export([analyze_scc/6]).
+-export([analyze_scc/7]).
-export([get_safe_underapprox/2]).
%%-import(helper, %% 'helper' could be any module doing sanity checks...
@@ -101,10 +101,9 @@
-type types() :: erl_types:type_table().
--type typesig_scc() :: [{mfa(), {cerl:c_var(), cerl:c_fun()}, types()}].
-type typesig_funmap() :: #{type_var() => type_var()}.
--type prop_types() :: dict:dict(label(), types()).
+-type prop_types() :: dict:dict(label(), erl_types:erl_type()).
-record(state, {callgraph :: dialyzer_callgraph:callgraph()
| 'undefined',
@@ -121,7 +120,7 @@
plt :: dialyzer_plt:plt()
| 'undefined',
prop_types = dict:new() :: prop_types(),
- records = dict:new() :: types(),
+ records = maps:new() :: types(),
scc = [] :: ordsets:ordset(type_var()),
mfas :: [mfa()],
solvers = [] :: [solver()]
@@ -160,11 +159,10 @@
%%-----------------------------------------------------------------------------
%% Analysis of strongly connected components.
%%
-%% analyze_scc(SCC, NextLabel, CallGraph, PLT, PropTypes, Solvers) -> FunTypes
+%% analyze_scc(SCC, NextLabel, CallGraph, CodeServer,
+%% PLT, PropTypes, Solvers) -> FunTypes
%%
-%% SCC - [{MFA, Def, Records}]
-%% where Def = {Var, Fun} as in the Core Erlang module definitions.
-%% Records = dict(RecName, {Arity, [{FieldName, FieldType}]})
+%% SCC - [{MFA}]
%% NextLabel - An integer that is higher than any label in the code.
%% CallGraph - A callgraph as produced by dialyzer_callgraph.erl
%% Note: The callgraph must have been built with all the
@@ -176,28 +174,27 @@
%% Solvers - User specified solvers.
%%-----------------------------------------------------------------------------
--spec analyze_scc(typesig_scc(), label(),
+-spec analyze_scc([mfa()], label(),
dialyzer_callgraph:callgraph(),
+ dialyzer_codeserver:codeserver(),
dialyzer_plt:plt(), prop_types(), [solver()]) -> prop_types().
-analyze_scc(SCC, NextLabel, CallGraph, Plt, PropTypes, Solvers0) ->
+analyze_scc(SCC, NextLabel, CallGraph, CServer, Plt, PropTypes, Solvers0) ->
Solvers = solvers(Solvers0),
- assert_format_of_scc(SCC),
- State1 = new_state(SCC, NextLabel, CallGraph, Plt, PropTypes, Solvers),
- DefSet = add_def_list([Var || {_MFA, {Var, _Fun}, _Rec} <- SCC], sets:new()),
- State2 = traverse_scc(SCC, DefSet, State1),
+ State1 = new_state(SCC, NextLabel, CallGraph, CServer, Plt, PropTypes,
+ Solvers),
+ DefSet = add_def_list(maps:values(State1#state.name_map), sets:new()),
+ ModRecs = [{M, dialyzer_codeserver:lookup_mod_records(M, CServer)} ||
+ M <- lists:usort([M || {M, _, _} <- SCC])],
+ State2 = traverse_scc(SCC, CServer, DefSet, ModRecs, State1),
State3 = state__finalize(State2),
+ erlang:garbage_collect(),
Funs = state__scc(State3),
pp_constrs_scc(Funs, State3),
constraints_to_dot_scc(Funs, State3),
T = solve(Funs, State3),
dict:from_list(maps:to_list(T)).
-assert_format_of_scc([{_MFA, {_Var, _Fun}, _Records}|Left]) ->
- assert_format_of_scc(Left);
-assert_format_of_scc([]) ->
- ok.
-
solvers([]) -> [v2];
solvers(Solvers) -> Solvers.
@@ -207,12 +204,15 @@ solvers(Solvers) -> Solvers.
%%
%% ============================================================================
-traverse_scc([{_MFA, Def, Rec}|Left], DefSet, AccState) ->
+traverse_scc([{M,_,_}=MFA|Left], Codeserver, DefSet, ModRecs, AccState) ->
+ Def = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
+ {M, Rec} = lists:keyfind(M, 1, ModRecs),
TmpState1 = state__set_rec_dict(AccState, Rec),
DummyLetrec = cerl:c_letrec([Def], cerl:c_atom(foo)),
- {NewAccState, _} = traverse(DummyLetrec, DefSet, TmpState1),
- traverse_scc(Left, DefSet, NewAccState);
-traverse_scc([], _DefSet, AccState) ->
+ TmpState2 = state__new_constraint_context(TmpState1),
+ {NewAccState, _} = traverse(DummyLetrec, DefSet, TmpState2),
+ traverse_scc(Left, Codeserver, DefSet, ModRecs, NewAccState);
+traverse_scc([], _Codeserver, _DefSet, _ModRecs, AccState) ->
AccState.
traverse(Tree, DefinedVars, State) ->
@@ -2106,6 +2106,12 @@ v2_solve_disj([I|Is], [C|Cs], I, Map0, V2State0, UL, MapL, Eval, Uneval,
end;
v2_solve_disj([], [], _I, _Map, V2State, UL, MapL, Eval, Uneval, Failed) ->
{ok, V2State, lists:reverse(Eval), UL, MapL, lists:reverse(Uneval), Failed};
+v2_solve_disj([every_i], Cs, I, Map, V2State, UL, MapL, Eval, Uneval, Failed) ->
+ NewIs = case Cs of
+ [] -> [];
+ _ -> [I, every_i]
+ end,
+ v2_solve_disj(NewIs, Cs, I, Map, V2State, UL, MapL, Eval, Uneval, Failed);
v2_solve_disj(Is, [C|Cs], I, Map, V2State, UL, MapL, Eval, Uneval0, Failed) ->
Uneval = [{I,C#constraint_list.id} ||
not is_failed_list(C, V2State)] ++ Uneval0,
@@ -2177,7 +2183,7 @@ v2_solve_conj([I|Is], [Cs|Tail], I, Map0, Conj, IsFlat, V2State0,
M = lists:keydelete(I, 1, vars_per_child(U, Masks)),
{V2State2, NewF0} = save_updated_vars_list(AllCs, M, V2State1),
{NewF, F} = lists:splitwith(fun(J) -> J < I end, NewF0),
- Is1 = lists:umerge(Is, F),
+ Is1 = umerge_mask(Is, F),
NewFs = [NewF|NewFs0],
v2_solve_conj(Is1, Tail, I+1, Map, Conj, IsFlat, V2State2,
[U|UL], NewFs, VarsUp, LastMap, LastFlags)
@@ -2199,6 +2205,14 @@ v2_solve_conj([], _Cs, _I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
v2_solve_conj(NewFlags, Cs, 1, Map, Conj, IsFlat, V2State,
[], [], [U|VarsUp], Map, NewFlags)
end;
+v2_solve_conj([every_i], Cs, I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
+ LastMap, LastFlags) ->
+ NewIs = case Cs of
+ [] -> [];
+ _ -> [I, every_i]
+ end,
+ v2_solve_conj(NewIs, Cs, I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
+ LastMap, LastFlags);
v2_solve_conj(Is, [_|Tail], I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
LastMap, LastFlags) ->
v2_solve_conj(Is, Tail, I+1, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
@@ -2215,7 +2229,12 @@ report_detected_loop(_) ->
add_mask_to_flags(Flags, [Im|M], I, L) when I > Im ->
add_mask_to_flags(Flags, M, I, [Im|L]);
add_mask_to_flags(Flags, [_|M], _I, L) ->
- {lists:umerge(M, Flags), lists:reverse(L)}.
+ {umerge_mask(Flags, M), lists:reverse(L)}.
+
+umerge_mask([every_i]=Is, _F) ->
+ Is;
+umerge_mask(Is, F) ->
+ lists:umerge(Is, F).
get_mask(V, Masks) ->
case maps:find(V, Masks) of
@@ -2229,7 +2248,7 @@ get_flags(#v2_state{constr_data = ConData}=V2State0, C) ->
error ->
?debug("get_flags Id=~w Flags=all ~w\n", [Id, length(Cs)]),
V2State = V2State0#v2_state{constr_data = maps:put(Id, {[],[]}, ConData)},
- {V2State, lists:seq(1, length(Cs))};
+ {V2State, [every_i]};
{ok, failed} ->
{V2State0, failed_list};
{ok, {Part,U}} when U =/= [] ->
@@ -2702,11 +2721,14 @@ pp_map(_S, _Map) ->
%%
%% ============================================================================
-new_state(SCC0, NextLabel, CallGraph, Plt, PropTypes, Solvers) ->
- List = [{MFA, Var} || {MFA, {Var, _Fun}, _Rec} <- SCC0],
+new_state(MFAs, NextLabel, CallGraph, CServer, Plt, PropTypes, Solvers) ->
+ List_SCC =
+ [begin
+ {Var, Label} = dialyzer_codeserver:lookup_mfa_var_label(MFA, CServer),
+ {{MFA, Var}, t_var(Label)}
+ end || MFA <- MFAs],
+ {List, SCC} = lists:unzip(List_SCC),
NameMap = maps:from_list(List),
- MFAs = [MFA || {MFA, _Var} <- List],
- SCC = [mk_var(Fun) || {_MFA, {_Var, Fun}, _Rec} <- SCC0],
SelfRec =
case SCC of
[OneF] ->
@@ -2906,8 +2928,9 @@ state__get_rec_var(Fun, #state{fun_map = Map}) ->
maps:find(Fun, Map).
state__finalize(State) ->
- State1 = enumerate_constraints(State),
- order_fun_constraints(State1).
+ State1 = state__new_constraint_context(State),
+ State2 = enumerate_constraints(State1),
+ order_fun_constraints(State2).
%% ============================================================================
%%
@@ -2987,7 +3010,7 @@ find_constraint_deps([Type|Tail], Acc) ->
NewAcc = [[t_var_name(D) || D <- t_collect_vars(Type)]|Acc],
find_constraint_deps(Tail, NewAcc);
find_constraint_deps([], Acc) ->
- lists:flatten(Acc).
+ lists:append(Acc).
mk_constraint_1(Lhs, eq, Rhs, Deps) when Lhs < Rhs ->
#constraint{lhs = Lhs, op = eq, rhs = Rhs, deps = Deps};
@@ -3095,8 +3118,8 @@ expand_to_conjunctions(#constraint_list{type = disj, list = List}) ->
List1 = [C || C <- List, is_simple_constraint(C)],
%% Just an assert.
[] = [C || #constraint{} = C <- List1],
- Expanded = lists:flatten([expand_to_conjunctions(C)
- || #constraint_list{} = C <- List]),
+ Expanded = lists:append([expand_to_conjunctions(C)
+ || #constraint_list{} = C <- List]),
ReturnList = Expanded ++ List1,
if length(ReturnList) > ?DISJ_NORM_FORM_LIMIT -> throw(too_many_disj);
true -> ReturnList
@@ -3121,8 +3144,10 @@ calculate_deps(List) ->
calculate_deps([H|Tail], Acc) ->
Deps = get_deps(H),
calculate_deps(Tail, [Deps|Acc]);
+calculate_deps([], []) -> [];
+calculate_deps([], [L]) -> L;
calculate_deps([], Acc) ->
- ordsets:from_list(lists:flatten(Acc)).
+ lists:umerge(Acc).
mk_conj_constraint_list(List) ->
mk_constraint_list(conj, List).
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 76a5cf3d0b..7a395666cd 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -202,7 +202,7 @@ get_core_from_abstract_code(AbstrCode, Opts) ->
get_record_and_type_info(AbstractCode) ->
Module = get_module(AbstractCode),
- get_record_and_type_info(AbstractCode, Module, dict:new()).
+ get_record_and_type_info(AbstractCode, Module, maps:new()).
-spec get_record_and_type_info(abstract_code(), module(), type_table()) ->
{'ok', type_table()} | {'error', string()}.
@@ -215,7 +215,7 @@ get_record_and_type_info([{attribute, A, record, {Name, Fields0}}|Left],
{ok, Fields} = get_record_fields(Fields0, RecDict),
Arity = length(Fields),
FN = {File, erl_anno:line(A)},
- NewRecDict = dict:store({record, Name}, {FN, [{Arity,Fields}]}, RecDict),
+ NewRecDict = maps:put({record, Name}, {FN, [{Arity,Fields}]}, RecDict),
get_record_and_type_info(Left, Module, NewRecDict, File);
get_record_and_type_info([{attribute, A, type, {{record, Name}, Fields0, []}}
|Left], Module, RecDict, File) ->
@@ -223,7 +223,7 @@ get_record_and_type_info([{attribute, A, type, {{record, Name}, Fields0, []}}
{ok, Fields} = get_record_fields(Fields0, RecDict),
Arity = length(Fields),
FN = {File, erl_anno:line(A)},
- NewRecDict = dict:store({record, Name}, {FN, [{Arity, Fields}]}, RecDict),
+ NewRecDict = maps:put({record, Name}, {FN, [{Arity, Fields}]}, RecDict),
get_record_and_type_info(Left, Module, NewRecDict, File);
get_record_and_type_info([{attribute, A, Attr, {Name, TypeForm}}|Left],
Module, RecDict, File)
@@ -263,9 +263,9 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, FN,
false ->
try erl_types:t_var_names(ArgForms) of
ArgNames ->
- dict:store({TypeOrOpaque, Name, Arity},
- {{Module, FN, TypeForm, ArgNames},
- erl_types:t_any()}, RecDict)
+ maps:put({TypeOrOpaque, Name, Arity},
+ {{Module, FN, TypeForm, ArgNames},
+ erl_types:t_any()}, RecDict)
catch
_:_ ->
throw({error, flat_format("Type declaration for ~w does not "
@@ -296,19 +296,18 @@ get_record_fields([{record_field, _Line, Name, _Init}|Left], RecDict, Acc) ->
get_record_fields([], _RecDict, Acc) ->
lists:reverse(Acc).
--spec process_record_remote_types(codeserver()) -> codeserver().
+-spec process_record_remote_types(codeserver()) ->
+ {codeserver(), mod_records()}.
%% The field types are cached. Used during analysis when handling records.
process_record_remote_types(CServer) ->
TempRecords = dialyzer_codeserver:get_temp_records(CServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CServer),
- Cache = erl_types:cache__new(),
- {TempRecords1, Cache1} =
- process_opaque_types0(TempRecords, ExpTypes, Cache),
+ TempRecords1 = process_opaque_types0(TempRecords, ExpTypes),
%% A cache (not the field type cache) is used for speeding things up a bit.
VarTable = erl_types:var_table__new(),
ModuleFun =
- fun({Module, Record}, C0) ->
+ fun({Module, Record}) ->
RecordFun =
fun({Key, Value}, C2) ->
case Key of
@@ -334,24 +333,27 @@ process_record_remote_types(CServer) ->
_Other -> {{Key, Value}, C2}
end
end,
- {RecordList, C1} =
- lists:mapfoldl(RecordFun, C0, dict:to_list(Record)),
- {{Module, dict:from_list(RecordList)}, C1}
+ Cache = erl_types:cache__new(),
+ {RecordList, _NewCache} =
+ lists:mapfoldl(RecordFun, Cache, maps:to_list(Record)),
+ {Module, maps:from_list(RecordList)}
end,
- {NewRecordsList, C1} =
- lists:mapfoldl(ModuleFun, Cache1, dict:to_list(TempRecords1)),
+ NewRecordsList = lists:map(ModuleFun, dict:to_list(TempRecords1)),
NewRecords = dict:from_list(NewRecordsList),
- _C8 = check_record_fields(NewRecords, ExpTypes, C1),
- dialyzer_codeserver:finalize_records(NewRecords, CServer).
+ check_record_fields(NewRecords, ExpTypes),
+ {dialyzer_codeserver:finalize_records(NewRecords, CServer), NewRecords}.
%% erl_types:t_from_form() substitutes the declaration of opaque types
%% for the expanded type in some cases. To make sure the initial type,
%% any(), is not used, the expansion is done twice.
%% XXX: Recursive opaque types are not handled well.
-process_opaque_types0(TempRecords0, TempExpTypes, Cache) ->
- {TempRecords1, NewCache} =
+process_opaque_types0(TempRecords0, TempExpTypes) ->
+ Cache = erl_types:cache__new(),
+ {TempRecords1, Cache1} =
process_opaque_types(TempRecords0, TempExpTypes, Cache),
- process_opaque_types(TempRecords1, TempExpTypes, NewCache).
+ {TempRecords, _NewCache} =
+ process_opaque_types(TempRecords1, TempExpTypes, Cache1),
+ TempRecords.
process_opaque_types(TempRecords, TempExpTypes, Cache) ->
VarTable = erl_types:var_table__new(),
@@ -371,8 +373,8 @@ process_opaque_types(TempRecords, TempExpTypes, Cache) ->
end
end,
{RecordList, C1} =
- lists:mapfoldl(RecordFun, C0, dict:to_list(Record)),
- {{Module, dict:from_list(RecordList)}, C1}
+ lists:mapfoldl(RecordFun, C0, maps:to_list(Record)),
+ {{Module, maps:from_list(RecordList)}, C1}
%% dict:map(RecordFun, Record)
end,
{TempRecordList, NewCache} =
@@ -380,7 +382,8 @@ process_opaque_types(TempRecords, TempExpTypes, Cache) ->
{dict:from_list(TempRecordList), NewCache}.
%% dict:map(ModuleFun, TempRecords).
-check_record_fields(Records, TempExpTypes, Cache) ->
+check_record_fields(Records, TempExpTypes) ->
+ Cache = erl_types:cache__new(),
VarTable = erl_types:var_table__new(),
CheckFun =
fun({Module, Element}, C0) ->
@@ -410,9 +413,10 @@ check_record_fields(Records, TempExpTypes, Cache) ->
msg_with_position(Fun, FileLine)
end
end,
- lists:foldl(ElemFun, C0, dict:to_list(Element))
+ lists:foldl(ElemFun, C0, maps:to_list(Element))
end,
- lists:foldl(CheckFun, Cache, dict:to_list(Records)).
+ _NewCache = lists:foldl(CheckFun, Cache, dict:to_list(Records)),
+ ok.
msg_with_position(Fun, FileLine) ->
try Fun()
@@ -435,17 +439,17 @@ merge_records(NewRecords, OldRecords) ->
%%
%% ============================================================================
--type spec_dict() :: dict:dict().
--type callback_dict() :: dict:dict().
+-type spec_map() :: dialyzer_codeserver:contracts().
+-type callback_map() :: dialyzer_codeserver:contracts().
-spec get_spec_info(module(), abstract_code(), type_table()) ->
- {'ok', spec_dict(), callback_dict()} | {'error', string()}.
+ {'ok', spec_map(), callback_map()} | {'error', string()}.
-get_spec_info(ModName, AbstractCode, RecordsDict) ->
+get_spec_info(ModName, AbstractCode, RecordsMap) ->
OptionalCallbacks0 = get_optional_callbacks(AbstractCode, ModName),
OptionalCallbacks = gb_sets:from_list(OptionalCallbacks0),
- get_spec_info(AbstractCode, dict:new(), dict:new(),
- RecordsDict, ModName, OptionalCallbacks, "nofile").
+ get_spec_info(AbstractCode, maps:new(), maps:new(),
+ RecordsMap, ModName, OptionalCallbacks, "nofile").
get_optional_callbacks(Abs, ModName) ->
[{ModName, F, A} || {F, A} <- get_optional_callbacks(Abs)].
@@ -463,7 +467,7 @@ get_optional_callbacks(Abs) ->
%% are erl_types:erl_type()
get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
- SpecDict, CallbackDict, RecordsDict, ModName, OptCb, File)
+ SpecMap, CallbackMap, RecordsMap, ModName, OptCb, File)
when ((Contract =:= 'spec') or (Contract =:= 'callback')),
is_list(TypeSpec) ->
Ln = erl_anno:line(Anno),
@@ -472,24 +476,24 @@ get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
{F, A} -> {ModName, F, A}
end,
Xtra = [optional_callback || gb_sets:is_member(MFA, OptCb)],
- ActiveDict =
+ ActiveMap =
case Contract of
- spec -> SpecDict;
- callback -> CallbackDict
+ spec -> SpecMap;
+ callback -> CallbackMap
end,
- try dict:find(MFA, ActiveDict) of
+ try maps:find(MFA, ActiveMap) of
error ->
SpecData = {TypeSpec, Xtra},
- NewActiveDict =
+ NewActiveMap =
dialyzer_contracts:store_tmp_contract(MFA, {File, Ln}, SpecData,
- ActiveDict, RecordsDict),
- {NewSpecDict, NewCallbackDict} =
+ ActiveMap, RecordsMap),
+ {NewSpecMap, NewCallbackMap} =
case Contract of
- spec -> {NewActiveDict, CallbackDict};
- callback -> {SpecDict, NewActiveDict}
+ spec -> {NewActiveMap, CallbackMap};
+ callback -> {SpecMap, NewActiveMap}
end,
- get_spec_info(Left, NewSpecDict, NewCallbackDict,
- RecordsDict, ModName, OptCb, File);
+ get_spec_info(Left, NewSpecMap, NewCallbackMap,
+ RecordsMap, ModName, OptCb, File);
{ok, {{OtherFile, L}, _D}} ->
{Mod, Fun, Arity} = MFA,
Msg = flat_format(" Contract/callback for function ~w:~w/~w "
@@ -502,28 +506,33 @@ get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
[Ln, Error])}
end;
get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left],
- SpecDict, CallbackDict, RecordsDict, ModName, OptCb, _File) ->
- get_spec_info(Left, SpecDict, CallbackDict,
- RecordsDict, ModName, OptCb, IncludeFile);
-get_spec_info([_Other|Left], SpecDict, CallbackDict,
- RecordsDict, ModName, OptCb, File) ->
- get_spec_info(Left, SpecDict, CallbackDict,
- RecordsDict, ModName, OptCb, File);
-get_spec_info([], SpecDict, CallbackDict,
- _RecordsDict, _ModName, _OptCb, _File) ->
- {ok, SpecDict, CallbackDict}.
+ SpecMap, CallbackMap, RecordsMap, ModName, OptCb, _File) ->
+ get_spec_info(Left, SpecMap, CallbackMap,
+ RecordsMap, ModName, OptCb, IncludeFile);
+get_spec_info([_Other|Left], SpecMap, CallbackMap,
+ RecordsMap, ModName, OptCb, File) ->
+ get_spec_info(Left, SpecMap, CallbackMap,
+ RecordsMap, ModName, OptCb, File);
+get_spec_info([], SpecMap, CallbackMap,
+ _RecordsMap, _ModName, _OptCb, _File) ->
+ {ok, SpecMap, CallbackMap}.
-spec get_fun_meta_info(module(), abstract_code(), [dial_warn_tag()]) ->
- dialyzer_codeserver:fun_meta_info().
+ dialyzer_codeserver:fun_meta_info() | {'error', string()}.
get_fun_meta_info(M, Abs, LegalWarnings) ->
- NoWarn = get_nowarn_unused_function(M, Abs),
- FuncSupp = get_func_suppressions(M, Abs),
- Warnings0 = get_options(Abs, LegalWarnings),
- Warnings = ordsets:to_list(Warnings0),
- ModuleWarnings = [{M, W} || W <- Warnings],
- RawProps = lists:append([NoWarn, FuncSupp, ModuleWarnings]),
- process_options(dialyzer_utils:family(RawProps), Warnings0).
+ try
+ {get_nowarn_unused_function(M, Abs), get_func_suppressions(M, Abs)}
+ of
+ {NoWarn, FuncSupp} ->
+ Warnings0 = get_options(Abs, LegalWarnings),
+ Warnings = ordsets:to_list(Warnings0),
+ ModuleWarnings = [{M, W} || W <- Warnings],
+ RawProps = lists:append([NoWarn, FuncSupp, ModuleWarnings]),
+ process_options(dialyzer_utils:family(RawProps), Warnings0)
+ catch throw:{error, _} = Error ->
+ Error
+ end.
process_options([{M, _}=Mod|Left], Warnings) when is_atom(M) ->
[Mod|process_options(Left, Warnings)];
@@ -702,7 +711,7 @@ format_errors([]) ->
-spec format_sig(erl_types:erl_type()) -> string().
format_sig(Type) ->
- format_sig(Type, dict:new()).
+ format_sig(Type, maps:new()).
-spec format_sig(erl_types:erl_type(), type_table()) -> string().
@@ -954,9 +963,7 @@ label(Tree) ->
-spec parallelism() -> integer().
parallelism() ->
- CPUs = erlang:system_info(logical_processors_available),
- Schedulers = erlang:system_info(schedulers),
- min(CPUs, Schedulers).
+ erlang:system_info(schedulers_online).
-spec family([{K,V}]) -> [{K,[V]}].
diff --git a/lib/dialyzer/test/Makefile b/lib/dialyzer/test/Makefile
index f43e04dd59..0d8fba438c 100644
--- a/lib/dialyzer/test/Makefile
+++ b/lib/dialyzer/test/Makefile
@@ -12,6 +12,7 @@ AUXILIARY_FILES=\
dialyzer_common.erl\
file_utils.erl\
dialyzer_SUITE.erl\
+ abstract_SUITE.erl\
plt_SUITE.erl
# ----------------------------------------------------
diff --git a/lib/dialyzer/test/abstract_SUITE.erl b/lib/dialyzer/test/abstract_SUITE.erl
new file mode 100644
index 0000000000..0e84dfab24
--- /dev/null
+++ b/lib/dialyzer/test/abstract_SUITE.erl
@@ -0,0 +1,106 @@
+%% This suite contains cases that cannot be written
+%% in Erlang itself and must be done via the abstract
+%% format.
+
+-module(abstract_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include("dialyzer_test_constants.hrl").
+
+-export([suite/0, all/0, init_per_suite/0, init_per_suite/1, end_per_suite/1]).
+-export([generated_case/1]).
+
+suite() ->
+ [{timetrap, {minutes, 1}}].
+all() ->
+ [generated_case].
+
+init_per_suite() ->
+ [{timetrap, ?plt_timeout}].
+init_per_suite(Config) ->
+ OutDir = ?config(priv_dir, Config),
+ case dialyzer_common:check_plt(OutDir) of
+ fail -> {skip, "Plt creation/check failed."};
+ ok -> [{dialyzer_options, []}|Config]
+ end.
+
+end_per_suite(_Config) ->
+ %% This function is required since init_per_suite/1 exists.
+ ok.
+
+generated_case(Config) when is_list(Config) ->
+ %% Equivalent to:
+ %%
+ %% -module(foo).
+ %% -export(bar).
+ %% bar() ->
+ %% Arg = sample,
+ %% case Arg of
+ %% #{} -> map;
+ %% _ -> Arg:fn()
+ %% end.
+ %%
+ %% Except the case statement and its clauses are marked as autogenerated.
+ [] =
+ test([{attribute,1,module,foo},
+ {attribute,2,export,[{bar,0}]},
+ {function,3,bar,0,
+ [{clause,3,[],[],
+ [{match,4,{var,4,'Arg'},{atom,4,sample}},
+ {'case',[{location,5},{generated,true}],{var,5,'Arg'},
+ [{clause,[{location,6},{generated,true}],[{map,6,[]}],[],
+ [{atom,6,map}]},
+ {clause,[{location,7},{generated,true}],[{var,7,'_'}],[],
+ [{call,7,{remote,7,{var,7,'Arg'},{atom,7,fn}},[]}]}]}]}]}],
+ Config, [], []),
+ %% With the first clause not auto-generated
+ [{warn_matching,{_,6},_}] =
+ test([{attribute,1,module,foo},
+ {attribute,2,export,[{bar,0}]},
+ {function,3,bar,0,
+ [{clause,3,[],[],
+ [{match,4,{var,4,'Arg'},{atom,4,sample}},
+ {'case',[{location,5},{generated,true}],{var,5,'Arg'},
+ [{clause,6,[{map,6,[]}],[],
+ [{atom,6,map}]},
+ {clause,[{location,7},{generated,true}],[{var,7,'_'}],[],
+ [{call,7,{remote,7,{var,7,'Arg'},{atom,7,fn}},[]}]}]}]}]}],
+ Config, [], []),
+ %% With Arg set to [] so neither clause matches
+ [{warn_return_no_exit,{_,3},_},
+ {warn_matching,{_,6},_},
+ {warn_failing_call,{_,7},_}] =
+ test([{attribute,1,module,foo},
+ {attribute,2,export,[{bar,0}]},
+ {function,3,bar,0,
+ [{clause,3,[],[],
+ [{match,4,{var,4,'Arg'},{nil,4}},
+ {'case',[{location,5},{generated,true}],{var,5,'Arg'},
+ [{clause,[{location,6},{generated,true}],[{map,6,[]}],[],
+ [{atom,6,map}]},
+ {clause,[{location,7},{generated,true}],[{var,7,'_'}],[],
+ [{call,7,{remote,7,{var,7,'Arg'},{atom,7,fn}},[]}]}]}]}]}],
+ Config, [], []),
+ ok.
+
+test(Prog, Config, COpts, DOpts) ->
+ {ok, BeamFile} = compile(Config, Prog, COpts),
+ run_dialyzer(Config, succ_typings, [BeamFile], DOpts).
+
+compile(Config, Prog, CompileOpts) ->
+ OutDir = ?config(priv_dir, Config),
+ Opts = [{outdir, OutDir}, debug_info, return_errors | CompileOpts],
+ {ok, Module, Source} = compile:forms(Prog, Opts),
+ BeamFile = filename:join([OutDir, lists:concat([Module, ".beam"])]),
+ ok = file:write_file(BeamFile, Source),
+ {ok, BeamFile}.
+
+run_dialyzer(Config, Analysis, Files, Opts) ->
+ OutDir = ?config(priv_dir, Config),
+ PltFilename = dialyzer_common:plt_file(OutDir),
+ dialyzer:run([{analysis_type, Analysis},
+ {files, Files},
+ {init_plt, PltFilename},
+ {check_plt, false},
+ {from, byte_code} |
+ Opts]).
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
index 50991c9bc5..365b4798c5 100644
--- a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
@@ -1 +1,2 @@
{dialyzer_options, []}.
+{time_limit, 5}.
diff --git a/lib/dialyzer/test/dialyzer_common.erl b/lib/dialyzer/test/dialyzer_common.erl
index d2b1026c06..48083a2731 100644
--- a/lib/dialyzer/test/dialyzer_common.erl
+++ b/lib/dialyzer/test/dialyzer_common.erl
@@ -7,7 +7,7 @@
-module(dialyzer_common).
--export([check_plt/1, check/4, create_all_suites/0, new_tests/2]).
+-export([check_plt/1, check/4, create_all_suites/0, new_tests/2, plt_file/1]).
-include_lib("kernel/include/file.hrl").
@@ -39,7 +39,7 @@
check_plt(OutDir) ->
io:format("Checking plt:"),
- PltFilename = filename:join(OutDir, ?plt_filename),
+ PltFilename = plt_file(OutDir),
case file:read_file_info(PltFilename) of
{ok, _} -> dialyzer_check_plt(PltFilename);
{error, _ } ->
@@ -63,6 +63,11 @@ check_plt(OutDir) ->
end
end.
+-spec plt_file(string()) -> string().
+
+plt_file(OutDir) ->
+ filename:join(OutDir, ?plt_filename).
+
dialyzer_check_plt(PltFilename) ->
try dialyzer:run([{analysis_type, plt_check},
{init_plt, PltFilename}]) of
@@ -119,7 +124,7 @@ build_plt(PltFilename) ->
'same' | {differ, [term()]}.
check(TestCase, Opts, Dir, OutDir) ->
- PltFilename = filename:join(OutDir, ?plt_filename),
+ PltFilename = plt_file(OutDir),
SrcDir = filename:join(Dir, ?input_files_directory),
ResDir = filename:join(Dir, ?result_files_directory),
Filename = filename:join(SrcDir, atom_to_list(TestCase)),
diff --git a/lib/dialyzer/test/map_SUITE_data/dialyzer_options b/lib/dialyzer/test/map_SUITE_data/dialyzer_options
index 50991c9bc5..02425c33f2 100644
--- a/lib/dialyzer/test/map_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/map_SUITE_data/dialyzer_options
@@ -1 +1,2 @@
{dialyzer_options, []}.
+{time_limit, 30}.
diff --git a/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2 b/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2
index f6fb98a863..46e2e8d36c 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2
+++ b/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2
@@ -2,11 +2,11 @@
map_in_guard2.erl:10: The call map_in_guard2:assoc_guard_clause('not_a_map') will never return since it differs in the 1st argument from the success typing arguments: (map())
map_in_guard2.erl:12: The pattern 'true' can never match the type 'false'
map_in_guard2.erl:14: The call map_in_guard2:exact_guard_clause(#{}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':=_, _=>_})
-map_in_guard2.erl:17: Clause guard cannot succeed. The variable M was matched against the type 'not_a_map'
+map_in_guard2.erl:17: Guard test is_map(M::'not_a_map') can never succeed
map_in_guard2.erl:20: Function assoc_update/1 has no local return
map_in_guard2.erl:20: Guard test is_map(M::'not_a_map') can never succeed
-map_in_guard2.erl:22: Clause guard cannot succeed. The variable M was matched against the type 'not_a_map'
map_in_guard2.erl:22: Function assoc_guard_clause/1 has no local return
+map_in_guard2.erl:22: Guard test is_map(M::'not_a_map') can never succeed
map_in_guard2.erl:24: Clause guard cannot succeed. The variable M was matched against the type #{}
map_in_guard2.erl:27: Clause guard cannot succeed. The variable M was matched against the type #{}
map_in_guard2.erl:27: Function exact_guard_clause/1 has no local return
diff --git a/lib/dialyzer/test/map_SUITE_data/results/opaque_key b/lib/dialyzer/test/map_SUITE_data/results/opaque_key
index fb7080cdc5..2ae0e0c5c6 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/opaque_key
+++ b/lib/dialyzer/test/map_SUITE_data/results/opaque_key
@@ -6,10 +6,10 @@ opaque_key_adt.erl:59: Invalid type specification for function opaque_key_adt:sm
opaque_key_use.erl:13: The test opaque_key_use:t() =:= opaque_key_use:t(integer()) can never evaluate to 'true'
opaque_key_use.erl:24: Attempt to test for equality between a term of type opaque_key_adt:t(integer()) and a term of opaque type opaque_key_adt:t()
opaque_key_use.erl:37: Function adt_mm1/0 has no local return
-opaque_key_use.erl:40: The attempt to match a term of type opaque_key_adt:m() against the pattern #{A:=R} breaks the opaqueness of the term
+opaque_key_use.erl:40: The attempt to match a term of type opaque_key_adt:m() against the pattern #{A:=R} breaks the opacity of the term
opaque_key_use.erl:48: Function adt_mu1/0 has no local return
-opaque_key_use.erl:51: Guard test is_map(M::opaque_key_adt:m()) breaks the opaqueness of its argument
+opaque_key_use.erl:51: Guard test is_map(M::opaque_key_adt:m()) breaks the opacity of its argument
opaque_key_use.erl:53: Function adt_mu2/0 has no local return
-opaque_key_use.erl:56: Guard test is_map(M::opaque_key_adt:m()) breaks the opaqueness of its argument
+opaque_key_use.erl:56: Guard test is_map(M::opaque_key_adt:m()) breaks the opacity of its argument
opaque_key_use.erl:58: Function adt_mu3/0 has no local return
-opaque_key_use.erl:60: Guard test is_map(M::opaque_key_adt:m()) breaks the opaqueness of its argument
+opaque_key_use.erl:60: Guard test is_map(M::opaque_key_adt:m()) breaks the opacity of its argument
diff --git a/lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/a.erl b/lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/a.erl
new file mode 100644
index 0000000000..827984b20b
--- /dev/null
+++ b/lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/a.erl
@@ -0,0 +1,9 @@
+-module(a).
+-export([to_map/1, to_map/2]).
+-type t() :: #{type := b:t()}.
+
+-spec to_map(t()) -> map().
+to_map(Resource) -> to_map(Resource, #{}).
+
+-spec to_map(t(), map()) -> map().
+to_map(_, Map) when is_map(Map) -> #{}.
diff --git a/lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/b.erl b/lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/b.erl
new file mode 100644
index 0000000000..31f9bb6b3e
--- /dev/null
+++ b/lib/dialyzer/test/map_SUITE_data/src/mand_remote_val/b.erl
@@ -0,0 +1,3 @@
+-module(b).
+-export_type([t/0]).
+-type t() :: binary().
diff --git a/lib/dialyzer/test/map_SUITE_data/src/opaque_bif.erl b/lib/dialyzer/test/map_SUITE_data/src/opaque_bif.erl
new file mode 100644
index 0000000000..40214a1887
--- /dev/null
+++ b/lib/dialyzer/test/map_SUITE_data/src/opaque_bif.erl
@@ -0,0 +1,13 @@
+-module(opaque_bif).
+-export([o1/1]).
+-export_type([opaque_any_map/0]).
+-opaque opaque_any_map() :: map().
+
+%% ERL-249: A bug with opaque arguments to maps:merge/2
+%% Reported by Felipe Ripoll on 6/9/2016
+-spec o1(opaque_any_map()) -> opaque_any_map().
+o1(Map) ->
+ maps:merge(o1_c(), Map).
+
+-spec o1_c() -> opaque_any_map().
+o1_c() -> #{}.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options b/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
index 3ff26b87db..cb301ff6a1 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
@@ -1 +1,2 @@
{dialyzer_options, [{warnings, [no_unused, no_return]}]}.
+{time_limit, 40}.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/array b/lib/dialyzer/test/opaque_SUITE_data/results/array
index 9921b61669..6f1aa1ce3d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/array
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/array
@@ -1,3 +1,3 @@
-array_use.erl:12: The type test is_tuple(array:array(_)) breaks the opaqueness of the term array:array(_)
-array_use.erl:9: The attempt to match a term of type array:array(_) against the pattern {'array', _, _, 'undefined', _} breaks the opaqueness of the term
+array_use.erl:12: The type test is_tuple(array:array(_)) breaks the opacity of the term array:array(_)
+array_use.erl:9: The attempt to match a term of type array:array(_) against the pattern {'array', _, _, 'undefined', _} breaks the opacity of the term
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/dict b/lib/dialyzer/test/opaque_SUITE_data/results/dict
index 42f6663191..3f8242c72d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/dict
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/dict
@@ -1,15 +1,15 @@
-dict_use.erl:41: The attempt to match a term of type dict:dict(_,_) against the pattern 'gazonk' breaks the opaqueness of the term
-dict_use.erl:45: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opaqueness of the term
-dict_use.erl:46: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opaqueness of the term
-dict_use.erl:51: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opaqueness of the term
-dict_use.erl:52: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opaqueness of the term
+dict_use.erl:41: The attempt to match a term of type dict:dict(_,_) against the pattern 'gazonk' breaks the opacity of the term
+dict_use.erl:45: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opacity of the term
+dict_use.erl:46: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opacity of the term
+dict_use.erl:51: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opacity of the term
+dict_use.erl:52: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opacity of the term
dict_use.erl:58: Attempt to test for equality between a term of type maybe_improper_list() and a term of opaque type dict:dict(_,_)
dict_use.erl:60: Attempt to test for inequality between a term of type atom() and a term of opaque type dict:dict(_,_)
-dict_use.erl:64: Guard test length(D::dict:dict(_,_)) breaks the opaqueness of its argument
-dict_use.erl:65: Guard test is_atom(D::dict:dict(_,_)) breaks the opaqueness of its argument
-dict_use.erl:66: Guard test is_list(D::dict:dict(_,_)) breaks the opaqueness of its argument
-dict_use.erl:70: The type test is_list(dict:dict(_,_)) breaks the opaqueness of the term dict:dict(_,_)
+dict_use.erl:64: Guard test length(D::dict:dict(_,_)) breaks the opacity of its argument
+dict_use.erl:65: Guard test is_atom(D::dict:dict(_,_)) breaks the opacity of its argument
+dict_use.erl:66: Guard test is_list(D::dict:dict(_,_)) breaks the opacity of its argument
+dict_use.erl:70: The type test is_list(dict:dict(_,_)) breaks the opacity of the term dict:dict(_,_)
dict_use.erl:73: The call dict:fetch('foo',[1 | 2 | 3,...]) does not have an opaque term of type dict:dict(_,_) as 2nd argument
dict_use.erl:76: The call dict:merge(Fun::any(),42,[1 | 2,...]) does not have opaque terms as 2nd and 3rd arguments
dict_use.erl:79: The call dict:store(42,'elli',{'dict',0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}) does not have an opaque term of type dict:dict(_,_) as 3rd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/ets b/lib/dialyzer/test/opaque_SUITE_data/results/ets
index e11c7a8352..5dde23fb15 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/ets
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/ets
@@ -1,4 +1,4 @@
-ets_use.erl:12: Guard test is_integer(T::atom() | ets:tid()) breaks the opaqueness of its argument
-ets_use.erl:20: The type test is_integer(atom() | ets:tid()) breaks the opaqueness of the term atom() | ets:tid()
-ets_use.erl:7: Guard test is_integer(T::ets:tid()) breaks the opaqueness of its argument
+ets_use.erl:12: Guard test is_integer(T::atom() | ets:tid()) breaks the opacity of its argument
+ets_use.erl:20: The type test is_integer(atom() | ets:tid()) breaks the opacity of the term atom() | ets:tid()
+ets_use.erl:7: Guard test is_integer(T::ets:tid()) breaks the opacity of its argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/my_queue b/lib/dialyzer/test/opaque_SUITE_data/results/my_queue
index 1f25a6f9c3..67999b0e20 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/my_queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/my_queue
@@ -1,7 +1,7 @@
my_queue_use.erl:15: The call my_queue_adt:is_empty([]) does not have an opaque term of type my_queue_adt:my_queue() as 1st argument
my_queue_use.erl:19: The call my_queue_adt:add(42,Q0::[]) does not have an opaque term of type my_queue_adt:my_queue() as 2nd argument
-my_queue_use.erl:24: The attempt to match a term of type my_queue_adt:my_queue() against the pattern [42 | Q2] breaks the opaqueness of the term
+my_queue_use.erl:24: The attempt to match a term of type my_queue_adt:my_queue() against the pattern [42 | Q2] breaks the opacity of the term
my_queue_use.erl:30: Attempt to test for equality between a term of type [] and a term of opaque type my_queue_adt:my_queue()
my_queue_use.erl:34: Cons will produce an improper list since its 2nd argument is my_queue_adt:my_queue()
my_queue_use.erl:34: The call my_queue_adt:dequeue(nonempty_maybe_improper_list(42,my_queue_adt:my_queue())) does not have an opaque term of type my_queue_adt:my_queue() as 1st argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/opaque b/lib/dialyzer/test/opaque_SUITE_data/results/opaque
index 5747f9061f..864e0d853c 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/opaque
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/opaque
@@ -1,3 +1,3 @@
opaque_bug3.erl:19: The pattern 'a' can never match the type #c{}
-opaque_bug4.erl:20: The attempt to match a term of type opaque_adt:abc() against the pattern 'a' breaks the opaqueness of the term
+opaque_bug4.erl:20: The attempt to match a term of type opaque_adt:abc() against the pattern 'a' breaks the opacity of the term
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/para b/lib/dialyzer/test/opaque_SUITE_data/results/para
index 8fe67e39ad..37b5b7b44e 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/para
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/para
@@ -16,12 +16,12 @@ para2.erl:88: The test para2:circ(integer()) =:= para2:circ(integer(),integer())
para3.erl:28: Invalid type specification for function para3:ot2/0. The success typing is () -> 'foo'
para3.erl:36: The pattern {{{17}}} can never match the type {{{{{{_,_,_,_,_}}}}}}
para3.erl:55: Invalid type specification for function para3:t2/0. The success typing is () -> 'foo'
-para3.erl:65: The attempt to match a term of type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}} against the pattern {{{{{17}}}}} breaks the opaqueness of para3_adt:ot1(_,_,_,_,_)
+para3.erl:65: The attempt to match a term of type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}} against the pattern {{{{{17}}}}} breaks the opacity of para3_adt:ot1(_,_,_,_,_)
para3.erl:68: The pattern {{{{17}}}} can never match the type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}}
-para3.erl:74: Invalid type specification for function para3:exp_adt/0. The success typing is () -> 3
-para4.erl:21: Invalid type specification for function para4:a/1. The success typing is (dict:dict(atom() | integer(),atom() | integer()) | para4:d_all()) -> [{atom() | integer(),atom() | integer()}]
-para4.erl:26: Invalid type specification for function para4:i/1. The success typing is (dict:dict(atom() | integer(),atom() | integer()) | para4:d_all()) -> [{atom() | integer(),atom() | integer()}]
-para4.erl:31: Invalid type specification for function para4:t/1. The success typing is (dict:dict(atom() | integer(),atom() | integer()) | para4:d_all()) -> [{atom() | integer(),atom() | integer()}]
+para3.erl:74: The specification for para3:exp_adt/0 has an opaque subtype para3_adt:exp1(para3_adt:exp2()) which is violated by the success typing () -> 3
+para4.erl:21: Invalid type specification for function para4:a/1. The success typing is (para4:d_all() | para4:d_atom()) -> [{atom() | integer(),atom() | integer()}]
+para4.erl:26: Invalid type specification for function para4:i/1. The success typing is (para4:d_all() | para4:d_integer()) -> [{atom() | integer(),atom() | integer()}]
+para4.erl:31: Invalid type specification for function para4:t/1. The success typing is (para4:d_all() | para4:d_tuple()) -> [{atom() | integer(),atom() | integer()}]
para4.erl:59: Attempt to test for equality between a term of type para4_adt:t(atom() | integer()) and a term of opaque type para4_adt:t(integer())
para4.erl:64: Attempt to test for equality between a term of type para4_adt:t(atom() | integer()) and a term of opaque type para4_adt:t(atom())
para4.erl:69: Attempt to test for equality between a term of type para4_adt:int(1 | 2 | 3 | 4) and a term of opaque type para4_adt:int(1 | 2)
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/queue b/lib/dialyzer/test/opaque_SUITE_data/results/queue
index 5b3813c418..9822b7168f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/queue
@@ -1,11 +1,11 @@
queue_use.erl:18: The call queue:is_empty({[],[]}) does not have an opaque term of type queue:queue(_) as 1st argument
queue_use.erl:22: The call queue:in(42,Q0::{[],[]}) does not have an opaque term of type queue:queue(_) as 2nd argument
-queue_use.erl:27: The attempt to match a term of type queue:queue(_) against the pattern {"*", Q2} breaks the opaqueness of the term
+queue_use.erl:27: The attempt to match a term of type queue:queue(_) against the pattern {"*", Q2} breaks the opacity of the term
queue_use.erl:33: Attempt to test for equality between a term of type {[42,...],[]} and a term of opaque type queue:queue(_)
-queue_use.erl:36: The attempt to match a term of type queue:queue(_) against the pattern {F, _R} breaks the opaqueness of the term
+queue_use.erl:36: The attempt to match a term of type queue:queue(_) against the pattern {F, _R} breaks the opacity of the term
queue_use.erl:40: The call queue:out({[42,...],[]}) does not have an opaque term of type queue:queue(_) as 1st argument
queue_use.erl:51: The call queue_use:is_in_queue(E::42,DB::#db{p::[],q::queue:queue(_)}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
-queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue:queue(_)} against the pattern {'db', _, {L1, L2}} breaks the opaqueness of queue:queue(_)
+queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue:queue(_)} against the pattern {'db', _, {L1, L2}} breaks the opacity of queue:queue(_)
queue_use.erl:62: The call queue_use:tuple_queue({42,'gazonk'}) does not have a term of type {_,queue:queue(_)} (with opaque subterms) as 1st argument
queue_use.erl:65: The call queue:in(F::42,Q::'gazonk') does not have an opaque term of type queue:queue(_) as 2nd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/rec b/lib/dialyzer/test/opaque_SUITE_data/results/rec
index 72736b3b3c..e9b217a93f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/rec
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/rec
@@ -1,6 +1,6 @@
-rec_use.erl:17: The attempt to match a term of type rec_adt:rec() against the pattern {'rec', _, 42} breaks the opaqueness of the term
-rec_use.erl:18: Guard test tuple_size(R::rec_adt:rec()) breaks the opaqueness of its argument
+rec_use.erl:17: The attempt to match a term of type rec_adt:rec() against the pattern {'rec', _, 42} breaks the opacity of the term
+rec_use.erl:18: Guard test tuple_size(R::rec_adt:rec()) breaks the opacity of its argument
rec_use.erl:23: The call rec_adt:get_a(R::tuple()) does not have an opaque term of type rec_adt:rec() as 1st argument
rec_use.erl:27: Attempt to test for equality between a term of type {'rec','gazonk',42} and a term of opaque type rec_adt:rec()
rec_use.erl:30: The call erlang:tuple_size(rec_adt:rec()) contains an opaque term as 1st argument when a structured term of type tuple() is expected
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/simple b/lib/dialyzer/test/opaque_SUITE_data/results/simple
index 391c37664e..5cd8916aee 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/simple
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/simple
@@ -1,29 +1,29 @@
exact_api.erl:17: The call exact_api:set_type(A::#digraph{vtab::'notable',etab::'notable',ntab::'notable',cyclic::'true'}) does not have an opaque term of type digraph:graph() as 1st argument
exact_api.erl:23: The call digraph:delete(G::#digraph{vtab::'notable',etab::'notable',ntab::'notable',cyclic::'true'}) does not have an opaque term of type digraph:graph() as 1st argument
-exact_api.erl:55: The attempt to match a term of type exact_adt:exact_adt() against the pattern {'exact_adt'} breaks the opaqueness of the term
+exact_api.erl:55: The attempt to match a term of type exact_adt:exact_adt() against the pattern {'exact_adt'} breaks the opacity of the term
exact_api.erl:59: The call exact_adt:exact_adt_set_type2(A::#exact_adt{}) does not have an opaque term of type exact_adt:exact_adt() as 1st argument
is_rec.erl:10: The call erlang:is_record(simple1_adt:d1(),'r',2) contains an opaque term as 1st argument when terms of different types are expected in these positions
is_rec.erl:15: The call erlang:is_record(A::simple1_adt:d1(),'r',I::1 | 2 | 3) contains an opaque term as 1st argument when terms of different types are expected in these positions
-is_rec.erl:19: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opaqueness of its argument
-is_rec.erl:23: Guard test is_record({simple1_adt:d1(),1},'r',2) breaks the opaqueness of its argument
+is_rec.erl:19: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opacity of its argument
+is_rec.erl:23: Guard test is_record({simple1_adt:d1(),1},'r',2) breaks the opacity of its argument
is_rec.erl:41: The call erlang:is_record(A::simple1_adt:d1(),R::'a') contains an opaque term as 1st argument when terms of different types are expected in these positions
is_rec.erl:45: The call erlang:is_record(A::simple1_adt:d1(),A::simple1_adt:d1(),1) contains an opaque term as 2nd argument when terms of different types are expected in these positions
is_rec.erl:49: The call erlang:is_record(A::simple1_adt:d1(),any(),1) contains an opaque term as 1st argument when terms of different types are expected in these positions
is_rec.erl:53: The call erlang:is_record(A::simple1_adt:d1(),A::simple1_adt:d1(),any()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
-is_rec.erl:57: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opaqueness of its argument
+is_rec.erl:57: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opacity of its argument
is_rec.erl:61: The record #r{f1::simple1_adt:d1()} violates the declared type for #r{}
is_rec.erl:65: The call erlang:is_record({simple1_adt:d1(),1},'r',2) contains an opaque term as 1st argument when terms of different types are expected in these positions
rec_api.erl:104: Matching of pattern {'r2', 10} tagged with a record name violates the declared type of #r2{f1::10}
-rec_api.erl:113: The attempt to match a term of type #r3{f1::queue:queue(_)} against the pattern {'r3', 'a'} breaks the opaqueness of queue:queue(_)
+rec_api.erl:113: The attempt to match a term of type #r3{f1::queue:queue(_)} against the pattern {'r3', 'a'} breaks the opacity of queue:queue(_)
rec_api.erl:118: Record construction #r3{f1::10} violates the declared type of field f1::queue:queue(_)
-rec_api.erl:123: The attempt to match a term of type #r3{f1::10} against the pattern {'r3', 10} breaks the opaqueness of queue:queue(_)
+rec_api.erl:123: The attempt to match a term of type #r3{f1::10} against the pattern {'r3', 10} breaks the opacity of queue:queue(_)
rec_api.erl:24: Record construction #r1{f1::10} violates the declared type of field f1::rec_api:a()
rec_api.erl:29: Matching of pattern {'r1', 10} tagged with a record name violates the declared type of #r1{f1::10}
-rec_api.erl:33: The attempt to match a term of type rec_adt:r1() against the pattern {'r1', 'a'} breaks the opaqueness of the term
+rec_api.erl:33: The attempt to match a term of type rec_adt:r1() against the pattern {'r1', 'a'} breaks the opacity of the term
rec_api.erl:35: Invalid type specification for function rec_api:adt_t1/1. The success typing is (#r1{f1::'a'}) -> #r1{f1::'a'}
-rec_api.erl:40: Invalid type specification for function rec_api:adt_r1/0. The success typing is () -> #r1{f1::'a'}
-rec_api.erl:85: The attempt to match a term of type rec_api:f() against the variable _ breaks the opaqueness of rec_adt:f()
+rec_api.erl:40: The specification for rec_api:adt_r1/0 has an opaque subtype rec_adt:r1() which is violated by the success typing () -> #r1{f1::'a'}
+rec_api.erl:85: The attempt to match a term of type rec_adt:f() against the record field 'f' declared to be of type rec_api:f() breaks the opacity of the term
rec_api.erl:99: Record construction #r2{f1::10} violates the declared type of field f1::rec_api:a()
simple1_api.erl:113: The test simple1_api:d1() =:= simple1_api:d2() can never evaluate to 'true'
simple1_api.erl:118: Guard test simple1_api:d2() =:= A::simple1_api:d1() can never succeed
@@ -35,20 +35,20 @@ simple1_api.erl:165: Attempt to test for equality between a term of type simple1
simple1_api.erl:181: Guard test A::simple1_adt:d1() =< B::simple1_adt:d2() contains opaque terms as 1st and 2nd arguments
simple1_api.erl:185: Guard test 'a' =< B::simple1_adt:d2() contains an opaque term as 2nd argument
simple1_api.erl:189: Guard test A::simple1_adt:d1() =< 'd' contains an opaque term as 1st argument
-simple1_api.erl:197: The type test is_integer(A::simple1_adt:d1()) breaks the opaqueness of the term A::simple1_adt:d1()
+simple1_api.erl:197: The type test is_integer(A::simple1_adt:d1()) breaks the opacity of the term A::simple1_adt:d1()
simple1_api.erl:221: Guard test A::simple1_api:i1() > 3 can never succeed
simple1_api.erl:225: Guard test A::simple1_adt:i1() > 3 contains an opaque term as 1st argument
simple1_api.erl:233: Guard test A::simple1_adt:i1() < 3 contains an opaque term as 1st argument
simple1_api.erl:239: Guard test A::1 > 3 can never succeed
simple1_api.erl:243: Guard test A::1 > 3 can never succeed
simple1_api.erl:257: Guard test is_function(T::simple1_api:o1()) can never succeed
-simple1_api.erl:265: Guard test is_function(T::simple1_adt:o1()) breaks the opaqueness of its argument
-simple1_api.erl:269: The type test is_function(T::simple1_adt:o1()) breaks the opaqueness of the term T::simple1_adt:o1()
+simple1_api.erl:265: Guard test is_function(T::simple1_adt:o1()) breaks the opacity of its argument
+simple1_api.erl:269: The type test is_function(T::simple1_adt:o1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:274: Guard test is_function(T::simple1_api:o1(),A::simple1_api:i1()) can never succeed
-simple1_api.erl:284: Guard test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opaqueness of its argument
-simple1_api.erl:289: The type test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opaqueness of the term T::simple1_adt:o1()
+simple1_api.erl:284: Guard test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opacity of its argument
+simple1_api.erl:289: The type test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:294: The call erlang:is_function(T::simple1_api:o1(),A::simple1_adt:i1()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
-simple1_api.erl:300: The type test is_function(T::simple1_adt:o1(),A::simple1_api:i1()) breaks the opaqueness of the term T::simple1_adt:o1()
+simple1_api.erl:300: The type test is_function(T::simple1_adt:o1(),A::simple1_api:i1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:306: Guard test B::simple1_api:b2() =:= 'true' can never succeed
simple1_api.erl:315: Guard test A::simple1_api:b1() =:= 'false' can never succeed
simple1_api.erl:319: Guard test not('and'('true','true')) can never succeed
@@ -60,14 +60,14 @@ simple1_api.erl:365: Clause guard cannot succeed.
simple1_api.erl:368: Invalid type specification for function simple1_api:bool_adt_t8/2. The success typing is (boolean(),boolean()) -> 1
simple1_api.erl:378: Clause guard cannot succeed.
simple1_api.erl:381: Invalid type specification for function simple1_api:bool_adt_t9/2. The success typing is ('false','false') -> 1
-simple1_api.erl:407: The size simple1_adt:i1() breaks the opaqueness of A
-simple1_api.erl:418: The attempt to match a term of type non_neg_integer() against the variable A breaks the opaqueness of simple1_adt:i1()
-simple1_api.erl:425: The attempt to match a term of type non_neg_integer() against the variable B breaks the opaqueness of simple1_adt:i1()
+simple1_api.erl:407: The size simple1_adt:i1() breaks the opacity of A
+simple1_api.erl:418: The attempt to match a term of type non_neg_integer() against the variable A breaks the opacity of simple1_adt:i1()
+simple1_api.erl:425: The attempt to match a term of type non_neg_integer() against the variable B breaks the opacity of simple1_adt:i1()
simple1_api.erl:432: The pattern <<_:B/integer-unit:1>> can never match the type any()
-simple1_api.erl:448: The attempt to match a term of type non_neg_integer() against the variable Sz breaks the opaqueness of simple1_adt:i1()
-simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary-unit:8>> breaks the opaqueness of the term
-simple1_api.erl:478: The call 'foo':A(A::simple1_adt:a()) breaks the opaqueness of the term A :: simple1_adt:a()
-simple1_api.erl:486: The call A:'foo'(A::simple1_adt:a()) breaks the opaqueness of the term A :: simple1_adt:a()
+simple1_api.erl:448: The attempt to match a term of type non_neg_integer() against the variable Sz breaks the opacity of simple1_adt:i1()
+simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary-unit:8>> breaks the opacity of the term
+simple1_api.erl:478: The call 'foo':A(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
+simple1_api.erl:486: The call A:'foo'(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
simple1_api.erl:499: The call 'foo':A(A::simple1_api:i()) requires that A is of type atom() not simple1_api:i()
simple1_api.erl:503: The call 'foo':A(A::simple1_adt:i()) requires that A is of type atom() not simple1_adt:i()
simple1_api.erl:507: The call A:'foo'(A::simple1_api:i()) requires that A is of type atom() not simple1_api:i()
@@ -79,7 +79,7 @@ simple1_api.erl:538: Guard test A::simple1_adt:d1() =:= 3 contains an opaque ter
simple1_api.erl:548: The call erlang:'<'(A::simple1_adt:d1(),3) contains an opaque term as 1st argument when terms of different types are expected in these positions
simple1_api.erl:558: The call erlang:'=<'(A::simple1_adt:d1(),B::simple1_adt:d2()) contains opaque terms as 1st and 2nd arguments when terms of different types are expected in these positions
simple1_api.erl:565: Guard test {digraph:graph(),3} > {digraph:graph(),atom() | ets:tid()} contains an opaque term as 2nd argument
-simple1_api.erl:91: Invalid type specification for function simple1_api:tup/0. The success typing is () -> {'a','b'}
+simple1_api.erl:91: The specification for simple1_api:tup/0 has an opaque subtype simple1_adt:tuple1() which is violated by the success typing () -> {'a','b'}
simple2_api.erl:100: The call lists:flatten(A::simple1_adt:tuple1()) contains an opaque term as 1st argument when a structured term of type [any()] is expected
simple2_api.erl:116: The call lists:flatten({simple1_adt:tuple1()}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
simple2_api.erl:121: Guard test {simple1_adt:d1(),3} > {simple1_adt:d1(),simple1_adt:tuple1()} contains an opaque term as 2nd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/timer b/lib/dialyzer/test/opaque_SUITE_data/results/timer
index b1cfcd4e9f..46c5a86307 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/timer
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/timer
@@ -1,4 +1,4 @@
timer_use.erl:16: The pattern 'gazonk' can never match the type {'error',_} | {'ok',timer:tref()}
-timer_use.erl:17: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {'ok', 42} breaks the opaqueness of timer:tref()
-timer_use.erl:18: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {Tag, 'gazonk'} breaks the opaqueness of timer:tref()
+timer_use.erl:17: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {'ok', 42} breaks the opacity of timer:tref()
+timer_use.erl:18: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {Tag, 'gazonk'} breaks the opacity of timer:tref()
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/union b/lib/dialyzer/test/opaque_SUITE_data/results/union
index 98829b424a..8763088bf0 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/union
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/union
@@ -1,5 +1,5 @@
-union_use.erl:12: The attempt to match a term of type union_adt:u() against the pattern 'aaa' breaks the opaqueness of the term
-union_use.erl:16: The type test is_tuple(union_adt:u()) breaks the opaqueness of the term union_adt:u()
-union_use.erl:7: Guard test is_atom(A::union_adt:u()) breaks the opaqueness of its argument
-union_use.erl:8: Guard test is_tuple(T::union_adt:u()) breaks the opaqueness of its argument
+union_use.erl:12: The attempt to match a term of type union_adt:u() against the pattern 'aaa' breaks the opacity of the term
+union_use.erl:16: The type test is_tuple(union_adt:u()) breaks the opacity of the term union_adt:u()
+union_use.erl:7: Guard test is_atom(A::union_adt:u()) breaks the opacity of its argument
+union_use.erl:8: Guard test is_tuple(T::union_adt:u()) breaks the opacity of its argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/weird b/lib/dialyzer/test/opaque_SUITE_data/results/weird
new file mode 100644
index 0000000000..d7f57cd152
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/weird
@@ -0,0 +1,6 @@
+
+weird_warning1.erl:15: Matching of pattern {'a', Dict} tagged with a record name violates the declared type of #b{q::queue:queue(_)}
+weird_warning2.erl:13: Matching of pattern <{'b', Queue}, Key, Value> tagged with a record name violates the declared type of <#a{d::dict:dict(_,_)},'my_key','my_value'>
+weird_warning3.erl:14: The call weird_warning3:add_element(#a{d::queue:queue(_)},'my_key','my_value') does not have a term of type #a{d::dict:dict(_,_)} | #b{q::queue:queue(_)} (with opaque subterms) as 1st argument
+weird_warning3.erl:16: The attempt to match a term of type #a{d::queue:queue(_)} against the pattern {'a', Dict} breaks the opacity of queue:queue(_)
+weird_warning3.erl:18: Matching of pattern {'b', Queue} tagged with a record name violates the declared type of #a{d::queue:queue(_)}
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/wings b/lib/dialyzer/test/opaque_SUITE_data/results/wings
index 511263b70a..391501d86f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/wings
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/wings
@@ -1,11 +1,11 @@
-wings_dissolve.erl:103: Guard test is_list(List::gb_sets:set(_)) breaks the opaqueness of its argument
-wings_dissolve.erl:19: Guard test is_list(Faces::gb_sets:set(_)) breaks the opaqueness of its argument
-wings_dissolve.erl:272: Guard test is_list(Faces::gb_sets:set(_)) breaks the opaqueness of its argument
+wings_dissolve.erl:103: Guard test is_list(List::gb_sets:set(_)) breaks the opacity of its argument
+wings_dissolve.erl:19: Guard test is_list(Faces::gb_sets:set(_)) breaks the opacity of its argument
+wings_dissolve.erl:272: Guard test is_list(Faces::gb_sets:set(_)) breaks the opacity of its argument
wings_dissolve.erl:31: The call gb_sets:is_empty(Faces::[any(),...]) does not have an opaque term of type gb_sets:set(_) as 1st argument
wings_edge.erl:205: The pattern <Edge, 'hard', Htab> can never match the type <_,'soft',_>
wings_edge_cmd.erl:30: The call gb_trees:size(P::gb_sets:set(_)) does not have an opaque term of type gb_trees:tree(_,_) as 1st argument
wings_edge_cmd.erl:32: The pattern [_ | Parts] can never match the type []
wings_edge_cmd.erl:32: The pattern [{_, P} | _] can never match the type []
-wings_io.erl:30: The attempt to match a term of type {'empty',queue:queue(_)} against the pattern {'empty', {In, Out}} breaks the opaqueness of queue:queue(_)
+wings_io.erl:30: The attempt to match a term of type {'empty',queue:queue(_)} against the pattern {'empty', {In, Out}} breaks the opacity of queue:queue(_)
wings_we.erl:155: The call wings_util:gb_trees_largest_key(Etab::gb_trees:tree(_,_)) contains an opaque term as 1st argument when a structured term of type {_,{_,_,_,'nil' | {_,_,_,'nil' | {_,_,_,_}}}} is expected
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl b/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl
index a4cec065ab..2527f166f2 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl
@@ -34,7 +34,7 @@ middle() ->
{w1(), w2()}.
%%---------------------------------------------------------------------
-%% Cases that are problematic w.r.t. opaqueness of types
+%% Cases that are problematic w.r.t. opacity of types
%%---------------------------------------------------------------------
w1() ->
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_ig_moves.erl b/lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_ig_moves.erl
new file mode 100644
index 0000000000..2a70606dab
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_ig_moves.erl
@@ -0,0 +1,83 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%=============================================================================
+
+-module(hipe_ig_moves).
+-export([new/1,
+ new_move/3,
+ get_moves/1]).
+
+%%-----------------------------------------------------------------------------
+%% The main data structure; its fields are:
+%% - movelist : mapping from temp to set of associated move numbers
+%% - nrmoves : number of distinct move instructions seen so far
+%% - moveinsns : list of move instructions, in descending move number order
+%% - moveset : set of move instructions
+
+-record(ig_moves, {movelist :: movelist(),
+ nrmoves = 0 :: non_neg_integer(),
+ moveinsns = [] :: [{_,_}],
+ moveset = gb_sets:empty() :: gb_sets:set()}).
+
+-type movelist() :: hipe_vectors:vector(ordsets:ordset(non_neg_integer())).
+
+%%-----------------------------------------------------------------------------
+
+-spec new(non_neg_integer()) -> #ig_moves{}.
+
+new(NrTemps) ->
+ MoveList = hipe_vectors:new(NrTemps, ordsets:new()),
+ #ig_moves{movelist = MoveList}.
+
+-spec new_move(_, _, #ig_moves{}) -> #ig_moves{}.
+
+new_move(Dst, Src, IG_moves) ->
+ MoveSet = IG_moves#ig_moves.moveset,
+ MoveInsn = {Dst, Src},
+ case gb_sets:is_member(MoveInsn, MoveSet) of
+ true ->
+ IG_moves;
+ false ->
+ MoveNr = IG_moves#ig_moves.nrmoves,
+ Movelist0 = IG_moves#ig_moves.movelist,
+ Movelist1 = add_movelist(MoveNr, Dst,
+ add_movelist(MoveNr, Src, Movelist0)),
+ IG_moves#ig_moves{nrmoves = MoveNr+1,
+ movelist = Movelist1,
+ moveinsns = [MoveInsn|IG_moves#ig_moves.moveinsns],
+ moveset = gb_sets:insert(MoveInsn, MoveSet)}
+ end.
+
+-spec add_movelist(non_neg_integer(), non_neg_integer(), movelist())
+ -> movelist().
+
+add_movelist(MoveNr, Temp, MoveList) ->
+ AssocMoves = hipe_vectors:get(MoveList, Temp),
+ %% XXX: MoveNr does not occur in moveList[Temp], but the new list must be an
+ %% ordset due to the ordsets:union in hipe_coalescing_regalloc:combine().
+ hipe_vectors:set(MoveList, Temp, ordsets:add_element(MoveNr, AssocMoves)).
+
+-spec get_moves(#ig_moves{}) -> {movelist(), non_neg_integer(), tuple()}.
+
+get_moves(IG_moves) -> % -> {MoveList, NrMoves, MoveInsns}
+ {IG_moves#ig_moves.movelist,
+ IG_moves#ig_moves.nrmoves,
+ list_to_tuple(lists:reverse(IG_moves#ig_moves.moveinsns))}.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_vectors.erl b/lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_vectors.erl
new file mode 100644
index 0000000000..279f244586
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/hipe_vectors/hipe_vectors.erl
@@ -0,0 +1,136 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% VECTORS IN ERLANG
+%%
+%% Abstract interface to vectors, indexed from 0 to size-1.
+
+-module(hipe_vectors).
+-export([new/2,
+ set/3,
+ get/2,
+ size/1,
+ vector_to_list/1,
+ %% list_to_vector/1,
+ list/1]).
+
+%%-define(USE_TUPLES, true).
+%%-define(USE_GBTREES, true).
+-define(USE_ARRAYS, true).
+
+-type vector() :: vector(_).
+-export_type([vector/0, vector/1]).
+
+-spec new(non_neg_integer(), V) -> vector(E) when V :: E.
+-spec set(vector(E), non_neg_integer(), V :: E) -> vector(E).
+-spec get(vector(E), non_neg_integer()) -> E.
+-spec size(vector(_)) -> non_neg_integer().
+-spec vector_to_list(vector(E)) -> [E].
+%% -spec list_to_vector([E]) -> vector(E).
+-spec list(vector(E)) -> [{non_neg_integer(), E}].
+
+%% ---------------------------------------------------------------------
+
+-ifdef(USE_TUPLES).
+-opaque vector(_) :: tuple().
+
+new(N, V) ->
+ erlang:make_tuple(N, V).
+
+size(V) -> erlang:tuple_size(V).
+
+list(Vec) ->
+ index(tuple_to_list(Vec), 0).
+
+index([X|Xs],N) ->
+ [{N,X} | index(Xs,N+1)];
+index([],_) ->
+ [].
+
+%% list_to_vector(Xs) ->
+%% list_to_tuple(Xs).
+
+vector_to_list(V) ->
+ tuple_to_list(V).
+
+set(Vec, Ix, V) ->
+ setelement(Ix+1, Vec, V).
+
+get(Vec, Ix) -> element(Ix+1, Vec).
+
+-endif. %% ifdef USE_TUPLES
+
+%% ---------------------------------------------------------------------
+
+-ifdef(USE_GBTREES).
+-opaque vector(E) :: gb_trees:tree(non_neg_integer(), E).
+
+new(N, V) when is_integer(N), N >= 0 ->
+ gb_trees:from_orddict(mklist(N, V)).
+
+mklist(N, V) ->
+ mklist(0, N, V).
+
+mklist(M, N, V) when M < N ->
+ [{M, V} | mklist(M+1, N, V)];
+mklist(_, _, _) ->
+ [].
+
+size(V) -> gb_trees:size(V).
+
+list(Vec) ->
+ gb_trees:to_list(Vec).
+
+%% list_to_vector(Xs) ->
+%% gb_trees:from_orddict(index(Xs, 0)).
+%%
+%% index([X|Xs], N) ->
+%% [{N, X} | index(Xs, N+1)];
+%% index([],_) ->
+%% [].
+
+vector_to_list(V) ->
+ gb_trees:values(V).
+
+set(Vec, Ix, V) ->
+ gb_trees:update(Ix, V, Vec).
+
+get(Vec, Ix) ->
+ gb_trees:get(Ix, Vec).
+
+-endif. %% ifdef USE_GBTREES
+
+%% ---------------------------------------------------------------------
+
+-ifdef(USE_ARRAYS).
+-opaque vector(E) :: array:array(E).
+%%-type vector(E) :: array:array(E). % Work around dialyzer bug
+
+new(N, V) -> array:new(N, {default, V}).
+size(V) -> array:size(V).
+list(Vec) -> array:to_orddict(Vec).
+%% list_to_vector(Xs) -> array:from_list(Xs).
+vector_to_list(V) -> array:to_list(V).
+set(Vec, Ix, V) -> array:set(Ix, V, Vec).
+get(Vec, Ix) -> array:get(Ix, Vec).
+
+-endif. %% ifdef USE_ARRAYS
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl
index 102215b28d..d8c1f561f7 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl
@@ -62,7 +62,7 @@ t2() ->
%% Shows that the list TypeNames in t_from_form must include ArgsLen.
t1_adt() ->
- {{{{{17}}}}} = para3_adt:t1(3). % breaks the opaqueness
+ {{{{{17}}}}} = para3_adt:t1(3). % breaks the opacity
t2_adt() ->
{{{{17}}}} = para3_adt:t1(3). % can never match
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/cerl.erl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/cerl.erl
new file mode 100644
index 0000000000..a4fdbfd5f0
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/cerl.erl
@@ -0,0 +1,4602 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+
+%% =====================================================================
+%% @doc Core Erlang abstract syntax trees.
+%%
+%% <p> This module defines an abstract data type for representing Core
+%% Erlang source code as syntax trees.</p>
+%%
+%% <p>A recommended starting point for the first-time user is the
+%% documentation of the function <a
+%% href="#type-1"><code>type/1</code></a>.</p>
+%%
+%% <h3><b>NOTES:</b></h3>
+%%
+%% <p>This module deals with the composition and decomposition of
+%% <em>syntactic</em> entities (as opposed to semantic ones); its
+%% purpose is to hide all direct references to the data structures
+%% used to represent these entities. With few exceptions, the
+%% functions in this module perform no semantic interpretation of
+%% their inputs, and in general, the user is assumed to pass
+%% type-correct arguments - if this is not done, the effects are not
+%% defined.</p>
+%%
+%% <p>Currently, the internal data structure used is the same as
+%% the record-based data structures used traditionally in the Beam
+%% compiler.</p>
+%%
+%% <p>The internal representations of abstract syntax trees are
+%% subject to change without notice, and should not be documented
+%% outside this module. Furthermore, we do not give any guarantees on
+%% how an abstract syntax tree may or may not be represented, <em>with
+%% the following exceptions</em>: no syntax tree is represented by a
+%% single atom, such as <code>none</code>, by a list constructor
+%% <code>[X | Y]</code>, or by the empty list <code>[]</code>. This
+%% can be relied on when writing functions that operate on syntax
+%% trees.</p>
+%%
+%% @type cerl(). An abstract Core Erlang syntax tree.
+%%
+%% <p>Every abstract syntax tree has a <em>type</em>, given by the
+%% function <a href="#type-1"><code>type/1</code></a>. In addition,
+%% each syntax tree has a list of <em>user annotations</em> (cf. <a
+%% href="#get_ann-1"><code>get_ann/1</code></a>), which are included
+%% in the Core Erlang syntax.</p>
+
+-module(cerl).
+
+-export([abstract/1, add_ann/2, alias_pat/1, alias_var/1,
+ ann_abstract/2, ann_c_alias/3, ann_c_apply/3, ann_c_atom/2,
+ ann_c_call/4, ann_c_case/3, ann_c_catch/2, ann_c_char/2,
+ ann_c_clause/3, ann_c_clause/4, ann_c_cons/3, ann_c_float/2,
+ ann_c_fname/3, ann_c_fun/3, ann_c_int/2, ann_c_let/4,
+ ann_c_letrec/3, ann_c_module/4, ann_c_module/5, ann_c_nil/1,
+ ann_c_cons_skel/3, ann_c_tuple_skel/2, ann_c_primop/3,
+ ann_c_receive/2, ann_c_receive/4, ann_c_seq/3, ann_c_string/2,
+ ann_c_try/6, ann_c_tuple/2, ann_c_values/2, ann_c_var/2,
+ ann_make_data/3, ann_make_list/2, ann_make_list/3,
+ ann_make_data_skel/3, ann_make_tree/3, apply_args/1,
+ apply_arity/1, apply_op/1, atom_lit/1, atom_name/1, atom_val/1,
+ c_alias/2, c_apply/2, c_atom/1, c_call/3, c_case/2, c_catch/1,
+ c_char/1, c_clause/2, c_clause/3, c_cons/2, c_float/1,
+ c_fname/2, c_fun/2, c_int/1, c_let/3, c_letrec/2, c_module/3,
+ c_module/4, c_nil/0, c_cons_skel/2, c_tuple_skel/1, c_primop/2,
+ c_receive/1, c_receive/3, c_seq/2, c_string/1, c_try/5,
+ c_tuple/1, c_values/1, c_var/1, call_args/1, call_arity/1,
+ call_module/1, call_name/1, case_arg/1, case_arity/1,
+ case_clauses/1, catch_body/1, char_lit/1, char_val/1,
+ clause_arity/1, clause_body/1, clause_guard/1, clause_pats/1,
+ clause_vars/1, concrete/1, cons_hd/1, cons_tl/1, copy_ann/2,
+ data_arity/1, data_es/1, data_type/1, float_lit/1, float_val/1,
+ fname_arity/1, fname_id/1, fold_literal/1, from_records/1,
+ fun_arity/1, fun_body/1, fun_vars/1, get_ann/1, int_lit/1,
+ int_val/1, is_c_alias/1, is_c_apply/1, is_c_atom/1,
+ is_c_call/1, is_c_case/1, is_c_catch/1, is_c_char/1,
+ is_c_clause/1, is_c_cons/1, is_c_float/1, is_c_fname/1,
+ is_c_fun/1, is_c_int/1, is_c_let/1, is_c_letrec/1, is_c_list/1,
+ is_c_module/1, is_c_nil/1, is_c_primop/1, is_c_receive/1,
+ is_c_seq/1, is_c_string/1, is_c_try/1, is_c_tuple/1,
+ is_c_values/1, is_c_var/1, is_data/1, is_leaf/1, is_literal/1,
+ is_literal_term/1, is_print_char/1, is_print_string/1,
+ let_arg/1, let_arity/1, let_body/1, let_vars/1, letrec_body/1,
+ letrec_defs/1, letrec_vars/1, list_elements/1, list_length/1,
+ make_data/2, make_list/1, make_list/2, make_data_skel/2,
+ make_tree/2, meta/1, module_attrs/1, module_defs/1,
+ module_exports/1, module_name/1, module_vars/1,
+ pat_list_vars/1, pat_vars/1, primop_args/1, primop_arity/1,
+ primop_name/1, receive_action/1, receive_clauses/1,
+ receive_timeout/1, seq_arg/1, seq_body/1, set_ann/2,
+ string_lit/1, string_val/1, subtrees/1, to_records/1,
+ try_arg/1, try_body/1, try_vars/1, try_evars/1, try_handler/1,
+ tuple_arity/1, tuple_es/1, type/1, unfold_literal/1,
+ update_c_alias/3, update_c_apply/3, update_c_call/4,
+ update_c_case/3, update_c_catch/2, update_c_clause/4,
+ update_c_cons/3, update_c_cons_skel/3, update_c_fname/2,
+ update_c_fname/3, update_c_fun/3, update_c_let/4,
+ update_c_letrec/3, update_c_module/5, update_c_primop/3,
+ update_c_receive/4, update_c_seq/3, update_c_try/6,
+ update_c_tuple/2, update_c_tuple_skel/2, update_c_values/2,
+ update_c_var/2, update_data/3, update_list/2, update_list/3,
+ update_data_skel/3, update_tree/2, update_tree/3,
+ values_arity/1, values_es/1, var_name/1, c_binary/1,
+ update_c_binary/2, ann_c_binary/2, is_c_binary/1,
+ binary_segments/1, c_bitstr/3, c_bitstr/4, c_bitstr/5,
+ update_c_bitstr/5, update_c_bitstr/6, ann_c_bitstr/5,
+ ann_c_bitstr/6, is_c_bitstr/1, bitstr_val/1, bitstr_size/1,
+ bitstr_bitsize/1, bitstr_unit/1, bitstr_type/1, bitstr_flags/1,
+
+ %% keep map exports here for now
+ c_map_pattern/1,
+ is_c_map/1,
+ is_c_map_pattern/1,
+ map_es/1,
+ map_arg/1,
+ update_c_map/3,
+ c_map/1, is_c_map_empty/1,
+ ann_c_map/2, ann_c_map/3,
+ ann_c_map_pattern/2,
+ map_pair_op/1,map_pair_key/1,map_pair_val/1,
+ update_c_map_pair/4,
+ c_map_pair/2, c_map_pair_exact/2,
+ ann_c_map_pair/4
+ ]).
+
+-export_type([c_binary/0, c_bitstr/0, c_call/0, c_clause/0, c_cons/0, c_fun/0,
+ c_let/0, c_literal/0, c_map/0, c_map_pair/0,
+ c_module/0, c_tuple/0,
+ c_values/0, c_var/0, cerl/0,
+ anns/0, attrs/0, defs/0, litval/0, var_name/0]).
+
+-include("core_parse.hrl").
+
+-type c_alias() :: #c_alias{}.
+-type c_apply() :: #c_apply{}.
+-type c_binary() :: #c_binary{}.
+-type c_bitstr() :: #c_bitstr{}.
+-type c_call() :: #c_call{}.
+-type c_case() :: #c_case{}.
+-type c_catch() :: #c_catch{}.
+-type c_clause() :: #c_clause{}.
+-type c_cons() :: #c_cons{}.
+-type c_fun() :: #c_fun{}.
+-type c_let() :: #c_let{}.
+-type c_letrec() :: #c_letrec{}.
+-type c_literal() :: #c_literal{}.
+-type c_map() :: #c_map{}.
+-type c_map_pair() :: #c_map_pair{}.
+-type c_module() :: #c_module{}.
+-type c_primop() :: #c_primop{}.
+-type c_receive() :: #c_receive{}.
+-type c_seq() :: #c_seq{}.
+-type c_try() :: #c_try{}.
+-type c_tuple() :: #c_tuple{}.
+-type c_values() :: #c_values{}.
+-type c_var() :: #c_var{}.
+
+-type cerl() :: c_alias() | c_apply() | c_binary() | c_bitstr()
+ | c_call() | c_case() | c_catch() | c_clause() | c_cons()
+ | c_fun() | c_let() | c_letrec() | c_literal()
+ | c_map() | c_map_pair()
+ | c_module() | c_primop() | c_receive() | c_seq()
+ | c_try() | c_tuple() | c_values() | c_var().
+
+-type anns() :: [term()].
+-type attr() :: {c_literal(), c_literal()}.
+-type attrs() :: [attr()].
+-type def() :: {c_var(), c_fun()}.
+-type defs() :: [def()].
+
+-type litval() :: atom() | bitstring() | map() | number()
+ | string() | tuple() | [litval()].
+
+-type var_name() :: integer() | atom() | {atom(), arity()}.
+
+
+%% =====================================================================
+%% Representation (general)
+%%
+%% All nodes are represented by tuples of arity 2 or (generally)
+%% greater, whose first element is an atom which uniquely identifies the
+%% type of the node, and whose second element is a (proper) list of
+%% annotation terms associated with the node - this is by default empty.
+%%
+%% For most node constructor functions, there are analogous functions
+%% named 'ann_...', taking one extra argument 'As' (always the first
+%% argument), specifying an annotation list at node creation time.
+%% Similarly, there are also functions named 'update_...', taking one
+%% extra argument 'Old', specifying a node from which all fields not
+%% explicitly given as arguments should be copied (generally, this is
+%% the annotation field only).
+%% =====================================================================
+
+%% @spec type(Node::cerl()) -> atom()
+%%
+%% @doc Returns the type tag of <code>Node</code>. Current node types
+%% are:
+%%
+%% <p><center><table border="1">
+%% <tr>
+%% <td>alias</td>
+%% <td>apply</td>
+%% <td>binary</td>
+%% <td>bitstr</td>
+%% <td>call</td>
+%% <td>case</td>
+%% <td>catch</td>
+%% <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>
+%% <td>receive</td>
+%% <td>seq</td>
+%% <td>try</td>
+%% <td>tuple</td>
+%% <td>values</td>
+%% <td>var</td>
+%% </tr>
+%% </table></center></p>
+%%
+%% <p>Note: The name of the primary constructor function for a node
+%% type is always the name of the type itself, prefixed by
+%% "<code>c_</code>"; recognizer predicates are correspondingly
+%% prefixed by "<code>is_c_</code>". Furthermore, to simplify
+%% preservation of annotations (cf. <code>get_ann/1</code>), there are
+%% analogous constructor functions prefixed by "<code>ann_c_</code>"
+%% and "<code>update_c_</code>", for setting the annotation list of
+%% the new node to either a specific value or to the annotations of an
+%% existing node, respectively.</p>
+%%
+%% @see abstract/1
+%% @see c_alias/2
+%% @see c_apply/2
+%% @see c_binary/1
+%% @see c_bitstr/5
+%% @see c_call/3
+%% @see c_case/2
+%% @see c_catch/1
+%% @see c_clause/3
+%% @see c_cons/2
+%% @see c_fun/2
+%% @see c_let/3
+%% @see c_letrec/2
+%% @see c_module/3
+%% @see c_primop/2
+%% @see c_receive/1
+%% @see c_seq/2
+%% @see c_try/5
+%% @see c_tuple/1
+%% @see c_values/1
+%% @see c_var/1
+%% @see get_ann/1
+%% @see to_records/1
+%% @see from_records/1
+%% @see data_type/1
+%% @see subtrees/1
+%% @see meta/1
+
+-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().
+
+type(#c_alias{}) -> alias;
+type(#c_apply{}) -> apply;
+type(#c_binary{}) -> binary;
+type(#c_bitstr{}) -> bitstr;
+type(#c_call{}) -> call;
+type(#c_case{}) -> 'case';
+type(#c_catch{}) -> 'catch';
+type(#c_clause{}) -> clause;
+type(#c_cons{}) -> cons;
+type(#c_fun{}) -> 'fun';
+type(#c_let{}) -> 'let';
+type(#c_letrec{}) -> letrec;
+type(#c_literal{}) -> literal;
+type(#c_map{}) -> map;
+type(#c_map_pair{}) -> map_pair;
+type(#c_module{}) -> module;
+type(#c_primop{}) -> primop;
+type(#c_receive{}) -> 'receive';
+type(#c_seq{}) -> seq;
+type(#c_try{}) -> 'try';
+type(#c_tuple{}) -> tuple;
+type(#c_values{}) -> values;
+type(#c_var{}) -> var.
+
+
+%% @spec is_leaf(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is a leaf node,
+%% otherwise <code>false</code>. The current leaf node types are
+%% <code>literal</code> and <code>var</code>.
+%%
+%% <p>Note: all literals (cf. <code>is_literal/1</code>) are leaf
+%% nodes, even if they represent structured (constant) values such as
+%% <code>{foo, [bar, baz]}</code>. Also note that variables are leaf
+%% nodes but not literals.</p>
+%%
+%% @see type/1
+%% @see is_literal/1
+
+-spec is_leaf(cerl()) -> boolean().
+
+is_leaf(Node) ->
+ case type(Node) of
+ literal -> true;
+ var -> true;
+ _ -> false
+ end.
+
+
+%% @spec get_ann(cerl()) -> anns()
+%%
+%% @doc Returns the list of user annotations associated with a syntax
+%% tree node. For a newly created node, this is the empty list. The
+%% annotations may be any terms.
+%%
+%% @see set_ann/2
+
+-spec get_ann(cerl()) -> anns().
+
+get_ann(Node) ->
+ element(2, Node).
+
+
+%% @spec set_ann(Node::cerl(), Annotations::anns()) -> cerl()
+%%
+%% @doc Sets the list of user annotations of <code>Node</code> to
+%% <code>Annotations</code>.
+%%
+%% @see get_ann/1
+%% @see add_ann/2
+%% @see copy_ann/2
+
+-spec set_ann(cerl(), anns()) -> cerl().
+
+set_ann(Node, List) ->
+ setelement(2, Node, List).
+
+
+%% @spec add_ann(Annotations::anns(), Node::cerl()) -> cerl()
+%%
+%% @doc Appends <code>Annotations</code> to the list of user
+%% annotations of <code>Node</code>.
+%%
+%% <p>Note: this is equivalent to <code>set_ann(Node, Annotations ++
+%% get_ann(Node))</code>, but potentially more efficient.</p>
+%%
+%% @see get_ann/1
+%% @see set_ann/2
+
+-spec add_ann(anns(), cerl()) -> cerl().
+
+add_ann(Terms, Node) ->
+ set_ann(Node, Terms ++ get_ann(Node)).
+
+
+%% @spec copy_ann(Source::cerl(), Target::cerl()) -> cerl()
+%%
+%% @doc Copies the list of user annotations from <code>Source</code>
+%% to <code>Target</code>.
+%%
+%% <p>Note: this is equivalent to <code>set_ann(Target,
+%% get_ann(Source))</code>, but potentially more efficient.</p>
+%%
+%% @see get_ann/1
+%% @see set_ann/2
+
+-spec copy_ann(cerl(), cerl()) -> cerl().
+
+copy_ann(Source, Target) ->
+ set_ann(Target, get_ann(Source)).
+
+
+%% @spec abstract(Term::litval()) -> cerl()
+%%
+%% @doc Creates a syntax tree corresponding to an Erlang term.
+%% <code>Term</code> must be a literal term, i.e., one that can be
+%% represented as a source code literal. Thus, it may not contain a
+%% process identifier, port, reference or function value as a subterm.
+%%
+%% <p>Note: This is a constant time operation.</p>
+%%
+%% @see ann_abstract/2
+%% @see concrete/1
+%% @see is_literal/1
+%% @see is_literal_term/1
+
+-spec abstract(litval()) -> c_literal().
+
+abstract(T) ->
+ #c_literal{val = T}.
+
+
+%% @spec ann_abstract(Annotations::anns(), Term::litval()) -> cerl()
+%% @see abstract/1
+
+-spec ann_abstract(anns(), litval()) -> c_literal().
+
+ann_abstract(As, T) ->
+ #c_literal{val = T, anno = As}.
+
+
+%% @spec is_literal_term(Term::term()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Term</code> can be
+%% represented as a literal, otherwise <code>false</code>. This
+%% function takes time proportional to the size of <code>Term</code>.
+%%
+%% @see abstract/1
+
+-spec is_literal_term(term()) -> boolean().
+
+is_literal_term(T) when is_integer(T) -> true;
+is_literal_term(T) when is_float(T) -> true;
+is_literal_term(T) when is_atom(T) -> true;
+is_literal_term([]) -> true;
+is_literal_term([H | T]) ->
+ is_literal_term(H) andalso is_literal_term(T);
+is_literal_term(T) when is_tuple(T) ->
+ is_literal_term_list(tuple_to_list(T));
+is_literal_term(B) when is_bitstring(B) -> true;
+is_literal_term(M) when is_map(M) ->
+ is_literal_term_list(maps:to_list(M));
+is_literal_term(_) ->
+ false.
+
+-spec is_literal_term_list([term()]) -> boolean().
+
+is_literal_term_list([T | Ts]) ->
+ case is_literal_term(T) of
+ true ->
+ is_literal_term_list(Ts);
+ false ->
+ false
+ end;
+is_literal_term_list([]) ->
+ true.
+
+
+%% @spec concrete(Node::c_literal()) -> litval()
+%%
+%% @doc Returns the Erlang term represented by a syntax tree. An
+%% exception is thrown if <code>Node</code> does not represent a
+%% literal term.
+%%
+%% <p>Note: This is a constant time operation.</p>
+%%
+%% @see abstract/1
+%% @see is_literal/1
+
+%% Because the normal tuple and list constructor operations always
+%% return a literal if the arguments are literals, 'concrete' and
+%% 'is_literal' never need to traverse the structure.
+
+-spec concrete(c_literal()) -> litval().
+
+concrete(#c_literal{val = V}) ->
+ V.
+
+
+%% @spec is_literal(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> represents a
+%% literal term, otherwise <code>false</code>. This function returns
+%% <code>true</code> if and only if the value of
+%% <code>concrete(Node)</code> is defined.
+%%
+%% <p>Note: This is a constant time operation.</p>
+%%
+%% @see abstract/1
+%% @see concrete/1
+%% @see fold_literal/1
+
+-spec is_literal(cerl()) -> boolean().
+
+is_literal(#c_literal{}) ->
+ true;
+is_literal(_) ->
+ false.
+
+
+%% @spec fold_literal(Node::cerl()) -> cerl()
+%%
+%% @doc Assures that literals have a compact representation. This is
+%% occasionally useful if <code>c_cons_skel/2</code>,
+%% <code>c_tuple_skel/1</code> or <code>unfold_literal/1</code> were
+%% used in the construction of <code>Node</code>, and you want to revert
+%% to the normal "folded" representation of literals. If
+%% <code>Node</code> represents a tuple or list constructor, its
+%% elements are rewritten recursively, and the node is reconstructed
+%% using <code>c_cons/2</code> or <code>c_tuple/1</code>, respectively;
+%% otherwise, <code>Node</code> is not changed.
+%%
+%% @see is_literal/1
+%% @see c_cons_skel/2
+%% @see c_tuple_skel/1
+%% @see c_cons/2
+%% @see c_tuple/1
+%% @see unfold_literal/1
+
+-spec fold_literal(cerl()) -> cerl().
+
+fold_literal(Node) ->
+ case type(Node) of
+ tuple ->
+ update_c_tuple(Node, fold_literal_list(tuple_es(Node)));
+ cons ->
+ update_c_cons(Node, fold_literal(cons_hd(Node)),
+ fold_literal(cons_tl(Node)));
+ _ ->
+ Node
+ end.
+
+fold_literal_list([E | Es]) ->
+ [fold_literal(E) | fold_literal_list(Es)];
+fold_literal_list([]) ->
+ [].
+
+
+%% @spec unfold_literal(Node::cerl()) -> cerl()
+%%
+%% @doc Assures that literals have a fully expanded representation. If
+%% <code>Node</code> represents a literal tuple or list constructor, its
+%% elements are rewritten recursively, and the node is reconstructed
+%% using <code>c_cons_skel/2</code> or <code>c_tuple_skel/1</code>,
+%% respectively; otherwise, <code>Node</code> is not changed. The {@link
+%% fold_literal/1} can be used to revert to the normal compact
+%% representation.
+%%
+%% @see is_literal/1
+%% @see c_cons_skel/2
+%% @see c_tuple_skel/1
+%% @see c_cons/2
+%% @see c_tuple/1
+%% @see fold_literal/1
+
+-spec unfold_literal(cerl()) -> cerl().
+
+unfold_literal(Node) ->
+ case type(Node) of
+ literal ->
+ copy_ann(Node, unfold_concrete(concrete(Node)));
+ _ ->
+ Node
+ end.
+
+unfold_concrete(Val) ->
+ case Val of
+ _ when is_tuple(Val) ->
+ c_tuple_skel(unfold_concrete_list(tuple_to_list(Val)));
+ [H|T] ->
+ c_cons_skel(unfold_concrete(H), unfold_concrete(T));
+ _ ->
+ abstract(Val)
+ end.
+
+unfold_concrete_list([E | Es]) ->
+ [unfold_concrete(E) | unfold_concrete_list(Es)];
+unfold_concrete_list([]) ->
+ [].
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_module(Name::c_literal(), Exports, Definitions) -> c_module()
+%%
+%% Exports = [c_var()]
+%% Definitions = defs()
+%%
+%% @equiv c_module(Name, Exports, [], Definitions)
+
+-spec c_module(c_literal(), [c_var()], defs()) -> c_module().
+
+c_module(Name, Exports, Defs) ->
+ #c_module{name = Name, exports = Exports, attrs = [], defs = Defs}.
+
+
+%% @spec c_module(Name::c_literal(), Exports, Attributes, Definitions) ->
+%% c_module()
+%%
+%% Exports = [c_var()]
+%% Attributes = attrs()
+%% Definitions = defs()
+%%
+%% @doc Creates an abstract module definition. The result represents
+%% <pre>
+%% module <em>Name</em> [<em>E1</em>, ..., <em>Ek</em>]
+%% attributes [<em>K1</em> = <em>T1</em>, ...,
+%% <em>Km</em> = <em>Tm</em>]
+%% <em>V1</em> = <em>F1</em>
+%% ...
+%% <em>Vn</em> = <em>Fn</em>
+%% end</pre>
+%%
+%% if <code>Exports</code> = <code>[E1, ..., Ek]</code>,
+%% <code>Attributes</code> = <code>[{K1, T1}, ..., {Km, Tm}]</code>,
+%% and <code>Definitions</code> = <code>[{V1, F1}, ..., {Vn,
+%% Fn}]</code>.
+%%
+%% <p><code>Name</code> and all the <code>Ki</code> must be atom
+%% literals, and all the <code>Ti</code> must be constant literals. All
+%% the <code>Vi</code> and <code>Ei</code> must have type
+%% <code>var</code> and represent function names. All the
+%% <code>Fi</code> must have type <code>'fun'</code>.</p>
+%%
+%% @see c_module/3
+%% @see module_name/1
+%% @see module_exports/1
+%% @see module_attrs/1
+%% @see module_defs/1
+%% @see module_vars/1
+%% @see ann_c_module/4
+%% @see ann_c_module/5
+%% @see update_c_module/5
+%% @see c_atom/1
+%% @see c_var/1
+%% @see c_fun/2
+%% @see is_literal/1
+
+-spec c_module(c_literal(), [c_var()], attrs(), defs()) -> c_module().
+
+c_module(Name, Exports, Attrs, Defs) ->
+ #c_module{name = Name, exports = Exports, attrs = Attrs, defs = Defs}.
+
+
+%% @spec ann_c_module(As::anns(), Name::c_literal(), Exports,
+%% Definitions) -> c_module()
+%%
+%% Exports = [c_var()]
+%% Definitions = defs()
+%%
+%% @see c_module/3
+%% @see ann_c_module/5
+
+-spec ann_c_module(anns(), c_literal(), [c_var()], defs()) -> c_module().
+
+ann_c_module(As, Name, Exports, Defs) ->
+ #c_module{name = Name, exports = Exports, attrs = [], defs = Defs,
+ anno = As}.
+
+
+%% @spec ann_c_module(As::anns(), Name::c_literal(), Exports,
+%% Attributes, Definitions) -> c_module()
+%%
+%% Exports = [c_var()]
+%% Attributes = attrs()
+%% Definitions = defs()
+%%
+%% @see c_module/4
+%% @see ann_c_module/4
+
+-spec ann_c_module(anns(), c_literal(), [c_var()], attrs(), defs()) ->
+ c_module().
+
+ann_c_module(As, Name, Exports, Attrs, Defs) ->
+ #c_module{name = Name, exports = Exports, attrs = Attrs, defs = Defs,
+ anno = As}.
+
+
+%% @spec update_c_module(Old::cerl(), Name::c_literal(), Exports,
+%% Attributes, Definitions) -> c_module()
+%%
+%% Exports = [c_var()]
+%% Attributes = attrs()
+%% Definitions = defs()
+%%
+%% @see c_module/4
+
+-spec update_c_module(c_module(), c_literal(), [c_var()], attrs(), defs()) ->
+ c_module().
+
+update_c_module(Node, Name, Exports, Attrs, Defs) ->
+ #c_module{name = Name, exports = Exports, attrs = Attrs, defs = Defs,
+ anno = get_ann(Node)}.
+
+
+%% @spec is_c_module(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% module definition, otherwise <code>false</code>.
+%%
+%% @see type/1
+
+-spec is_c_module(cerl()) -> boolean().
+
+is_c_module(#c_module{}) ->
+ true;
+is_c_module(_) ->
+ false.
+
+
+%% @spec module_name(Node::c_module()) -> c_literal()
+%%
+%% @doc Returns the name subtree of an abstract module definition.
+%%
+%% @see c_module/4
+
+-spec module_name(c_module()) -> c_literal().
+
+module_name(Node) ->
+ Node#c_module.name.
+
+
+%% @spec module_exports(Node::c_module()) -> [c_var()]
+%%
+%% @doc Returns the list of exports subtrees of an abstract module
+%% definition.
+%%
+%% @see c_module/4
+
+-spec module_exports(c_module()) -> [c_var()].
+
+module_exports(Node) ->
+ Node#c_module.exports.
+
+
+%% @spec module_attrs(Node::c_module()) -> [{cerl(), cerl()}]
+%%
+%% @doc Returns the list of pairs of attribute key/value subtrees of
+%% an abstract module definition.
+%%
+%% @see c_module/4
+
+-spec module_attrs(c_module()) -> attrs().
+
+module_attrs(Node) ->
+ Node#c_module.attrs.
+
+
+%% @spec module_defs(Node::c_module()) -> defs()
+%%
+%% @doc Returns the list of function definitions of an abstract module
+%% definition.
+%%
+%% @see c_module/4
+
+-spec module_defs(c_module()) -> defs().
+
+module_defs(Node) ->
+ Node#c_module.defs.
+
+
+%% @spec module_vars(Node::c_module()) -> [c_var()]
+%%
+%% @doc Returns the list of left-hand side function variable subtrees
+%% of an abstract module definition.
+%%
+%% @see c_module/4
+
+-spec module_vars(c_module()) -> [c_var()].
+
+module_vars(Node) ->
+ [F || {F, _} <- module_defs(Node)].
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_int(Value::integer()) -> c_literal()
+%%
+%% @doc Creates an abstract integer literal. The lexical
+%% representation is the canonical decimal numeral of
+%% <code>Value</code>.
+%%
+%% @see ann_c_int/2
+%% @see is_c_int/1
+%% @see int_val/1
+%% @see int_lit/1
+%% @see c_char/1
+
+-spec c_int(integer()) -> c_literal().
+
+c_int(Value) ->
+ #c_literal{val = Value}.
+
+
+%% @spec ann_c_int(As::anns(), Value::integer()) -> c_literal()
+%% @see c_int/1
+
+-spec ann_c_int(anns(), integer()) -> c_literal().
+
+ann_c_int(As, Value) ->
+ #c_literal{val = Value, anno = As}.
+
+
+%% @spec is_c_int(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> represents an
+%% integer literal, otherwise <code>false</code>.
+%% @see c_int/1
+
+-spec is_c_int(cerl()) -> boolean().
+
+is_c_int(#c_literal{val = V}) when is_integer(V) ->
+ true;
+is_c_int(_) ->
+ false.
+
+
+%% @spec int_val(c_literal()) -> integer()
+%%
+%% @doc Returns the value represented by an integer literal node.
+%% @see c_int/1
+
+-spec int_val(c_literal()) -> integer().
+
+int_val(Node) ->
+ Node#c_literal.val.
+
+
+%% @spec int_lit(c_literal()) -> string()
+%%
+%% @doc Returns the numeral string represented by an integer literal
+%% node.
+%% @see c_int/1
+
+-spec int_lit(c_literal()) -> string().
+
+int_lit(Node) ->
+ integer_to_list(int_val(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_float(Value::float()) -> c_literal()
+%%
+%% @doc Creates an abstract floating-point literal. The lexical
+%% representation is the decimal floating-point numeral of
+%% <code>Value</code>.
+%%
+%% @see ann_c_float/2
+%% @see is_c_float/1
+%% @see float_val/1
+%% @see float_lit/1
+
+%% Note that not all floating-point numerals can be represented with
+%% full precision.
+
+-spec c_float(float()) -> c_literal().
+
+c_float(Value) ->
+ #c_literal{val = Value}.
+
+
+%% @spec ann_c_float(As::anns(), Value::float()) -> c_literal()
+%% @see c_float/1
+
+-spec ann_c_float(anns(), float()) -> c_literal().
+
+ann_c_float(As, Value) ->
+ #c_literal{val = Value, anno = As}.
+
+
+%% @spec is_c_float(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> represents a
+%% floating-point literal, otherwise <code>false</code>.
+%% @see c_float/1
+
+-spec is_c_float(cerl()) -> boolean().
+
+is_c_float(#c_literal{val = V}) when is_float(V) ->
+ true;
+is_c_float(_) ->
+ false.
+
+
+%% @spec float_val(c_literal()) -> float()
+%%
+%% @doc Returns the value represented by a floating-point literal
+%% node.
+%% @see c_float/1
+
+-spec float_val(c_literal()) -> float().
+
+float_val(Node) ->
+ Node#c_literal.val.
+
+
+%% @spec float_lit(c_literal()) -> string()
+%%
+%% @doc Returns the numeral string represented by a floating-point
+%% literal node.
+%% @see c_float/1
+
+-spec float_lit(c_literal()) -> string().
+
+float_lit(Node) ->
+ float_to_list(float_val(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_atom(Name) -> c_literal()
+%% Name = atom() | string()
+%%
+%% @doc Creates an abstract atom literal. The print name of the atom
+%% is the character sequence represented by <code>Name</code>.
+%%
+%% <p>Note: passing a string as argument to this function causes a
+%% corresponding atom to be created for the internal representation.</p>
+%%
+%% @see ann_c_atom/2
+%% @see is_c_atom/1
+%% @see atom_val/1
+%% @see atom_name/1
+%% @see atom_lit/1
+
+-spec c_atom(atom() | string()) -> c_literal().
+
+c_atom(Name) when is_atom(Name) ->
+ #c_literal{val = Name};
+c_atom(Name) ->
+ #c_literal{val = list_to_atom(Name)}.
+
+
+%% @spec ann_c_atom(As::anns(), Name) -> cerl()
+%% Name = atom() | string()
+%% @see c_atom/1
+
+-spec ann_c_atom(anns(), atom() | string()) -> c_literal().
+
+ann_c_atom(As, Name) when is_atom(Name) ->
+ #c_literal{val = Name, anno = As};
+ann_c_atom(As, Name) ->
+ #c_literal{val = list_to_atom(Name), anno = As}.
+
+
+%% @spec is_c_atom(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> represents an
+%% atom literal, otherwise <code>false</code>.
+%%
+%% @see c_atom/1
+
+-spec is_c_atom(cerl()) -> boolean().
+
+is_c_atom(#c_literal{val = V}) when is_atom(V) ->
+ true;
+is_c_atom(_) ->
+ false.
+
+%% @spec atom_val(c_literal()) -> atom()
+%%
+%% @doc Returns the value represented by an abstract atom.
+%%
+%% @see c_atom/1
+
+-spec atom_val(c_literal()) -> atom().
+
+atom_val(Node) ->
+ Node#c_literal.val.
+
+
+%% @spec atom_name(c_literal()) -> string()
+%%
+%% @doc Returns the printname of an abstract atom.
+%%
+%% @see c_atom/1
+
+-spec atom_name(c_literal()) -> string().
+
+atom_name(Node) ->
+ atom_to_list(atom_val(Node)).
+
+
+%% @spec atom_lit(cerl()) -> string()
+%%
+%% @doc Returns the literal string represented by an abstract
+%% atom. This always includes surrounding single-quote characters.
+%%
+%% <p>Note that an abstract atom may have several literal
+%% representations, and that the representation yielded by this
+%% function is not fixed; e.g.,
+%% <code>atom_lit(c_atom("a\012b"))</code> could yield the string
+%% <code>"\'a\\nb\'"</code>.</p>
+%%
+%% @see c_atom/1
+
+%% TODO: replace the use of the unofficial 'write_string/2'.
+
+-spec atom_lit(cerl()) -> nonempty_string().
+
+atom_lit(Node) ->
+ io_lib:write_string(atom_name(Node), $'). %' stupid Emacs.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_char(Value) -> c_literal()
+%%
+%% Value = char() | integer()
+%%
+%% @doc Creates an abstract character literal. If the local
+%% implementation of Erlang defines <code>char()</code> as a subset of
+%% <code>integer()</code>, this function is equivalent to
+%% <code>c_int/1</code>. Otherwise, if the given value is an integer,
+%% it will be converted to the character with the corresponding
+%% code. The lexical representation of a character is
+%% "<code>$<em>Char</em></code>", where <code>Char</code> is a single
+%% printing character or an escape sequence.
+%%
+%% @see c_int/1
+%% @see c_string/1
+%% @see ann_c_char/2
+%% @see is_c_char/1
+%% @see char_val/1
+%% @see char_lit/1
+%% @see is_print_char/1
+
+-spec c_char(non_neg_integer()) -> c_literal().
+
+c_char(Value) when is_integer(Value), Value >= 0 ->
+ #c_literal{val = Value}.
+
+
+%% @spec ann_c_char(As::anns(), Value::char()) -> c_literal()
+%% @see c_char/1
+
+-spec ann_c_char(anns(), char()) -> c_literal().
+
+ann_c_char(As, Value) ->
+ #c_literal{val = Value, anno = As}.
+
+
+%% @spec is_c_char(Node::c_literal()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> may represent a
+%% character literal, otherwise <code>false</code>.
+%%
+%% <p>If the local implementation of Erlang defines
+%% <code>char()</code> as a subset of <code>integer()</code>, then
+%% <code>is_c_int(<em>Node</em>)</code> will also yield
+%% <code>true</code>.</p>
+%%
+%% @see c_char/1
+%% @see is_print_char/1
+
+-spec is_c_char(c_literal()) -> boolean().
+
+is_c_char(#c_literal{val = V}) when is_integer(V), V >= 0 ->
+ is_char_value(V);
+is_c_char(_) ->
+ false.
+
+
+%% @spec is_print_char(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> may represent a
+%% "printing" character, otherwise <code>false</code>. (Cf.
+%% <code>is_c_char/1</code>.) A "printing" character has either a
+%% given graphical representation, or a "named" escape sequence such
+%% as "<code>\n</code>". Currently, only ISO 8859-1 (Latin-1)
+%% character values are recognized.
+%%
+%% @see c_char/1
+%% @see is_c_char/1
+
+-spec is_print_char(cerl()) -> boolean().
+
+is_print_char(#c_literal{val = V}) when is_integer(V), V >= 0 ->
+ is_print_char_value(V);
+is_print_char(_) ->
+ false.
+
+
+%% @spec char_val(c_literal()) -> char()
+%%
+%% @doc Returns the value represented by an abstract character literal.
+%%
+%% @see c_char/1
+
+-spec char_val(c_literal()) -> char().
+
+char_val(Node) ->
+ Node#c_literal.val.
+
+
+%% @spec char_lit(c_literal()) -> string()
+%%
+%% @doc Returns the literal string represented by an abstract
+%% character. This includes a leading <code>$</code>
+%% character. Currently, all characters that are not in the set of ISO
+%% 8859-1 (Latin-1) "printing" characters will be escaped.
+%%
+%% @see c_char/1
+
+-spec char_lit(c_literal()) -> nonempty_string().
+
+char_lit(Node) ->
+ io_lib:write_char(char_val(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_string(Value::string()) -> c_literal()
+%%
+%% @doc Creates an abstract string literal. Equivalent to creating an
+%% abstract list of the corresponding character literals
+%% (cf. <code>is_c_string/1</code>), but is typically more
+%% efficient. The lexical representation of a string is
+%% "<code>"<em>Chars</em>"</code>", where <code>Chars</code> is a
+%% sequence of printing characters or spaces.
+%%
+%% @see c_char/1
+%% @see ann_c_string/2
+%% @see is_c_string/1
+%% @see string_val/1
+%% @see string_lit/1
+%% @see is_print_string/1
+
+-spec c_string(string()) -> c_literal().
+
+c_string(Value) ->
+ #c_literal{val = Value}.
+
+
+%% @spec ann_c_string(As::anns(), Value::string()) -> c_literal()
+%% @see c_string/1
+
+-spec ann_c_string(anns(), string()) -> c_literal().
+
+ann_c_string(As, Value) ->
+ #c_literal{val = Value, anno = As}.
+
+
+%% @spec is_c_string(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> may represent a
+%% string literal, otherwise <code>false</code>. Strings are defined
+%% as lists of characters; see <code>is_c_char/1</code> for details.
+%%
+%% @see c_string/1
+%% @see is_c_char/1
+%% @see is_print_string/1
+
+-spec is_c_string(cerl()) -> boolean().
+
+is_c_string(#c_literal{val = V}) ->
+ is_char_list(V);
+is_c_string(_) ->
+ false.
+
+
+%% @spec is_print_string(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> may represent a
+%% string literal containing only "printing" characters, otherwise
+%% <code>false</code>. See <code>is_c_string/1</code> and
+%% <code>is_print_char/1</code> for details. Currently, only ISO
+%% 8859-1 (Latin-1) character values are recognized.
+%%
+%% @see c_string/1
+%% @see is_c_string/1
+%% @see is_print_char/1
+
+-spec is_print_string(cerl()) -> boolean().
+
+is_print_string(#c_literal{val = V}) ->
+ is_print_char_list(V);
+is_print_string(_) ->
+ false.
+
+
+%% @spec string_val(cerl()) -> string()
+%%
+%% @doc Returns the value represented by an abstract string literal.
+%%
+%% @see c_string/1
+
+-spec string_val(c_literal()) -> string().
+
+string_val(Node) ->
+ Node#c_literal.val.
+
+
+%% @spec string_lit(cerl()) -> string()
+%%
+%% @doc Returns the literal string represented by an abstract string.
+%% This includes surrounding double-quote characters
+%% <code>"..."</code>. Currently, characters that are not in the set
+%% of ISO 8859-1 (Latin-1) "printing" characters will be escaped,
+%% except for spaces.
+%%
+%% @see c_string/1
+
+-spec string_lit(c_literal()) -> nonempty_string().
+
+string_lit(Node) ->
+ io_lib:write_string(string_val(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_nil() -> cerl()
+%%
+%% @doc Creates an abstract empty list. The result represents
+%% "<code>[]</code>". The empty list is traditionally called "nil".
+%%
+%% @see ann_c_nil/1
+%% @see is_c_list/1
+%% @see c_cons/2
+
+-spec c_nil() -> c_literal().
+
+c_nil() ->
+ #c_literal{val = []}.
+
+
+%% @spec ann_c_nil(As::anns()) -> cerl()
+%% @see c_nil/0
+
+-spec ann_c_nil(anns()) -> c_literal().
+
+ann_c_nil(As) ->
+ #c_literal{val = [], anno = As}.
+
+
+%% @spec is_c_nil(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% empty list, otherwise <code>false</code>.
+
+-spec is_c_nil(cerl()) -> boolean().
+
+is_c_nil(#c_literal{val = []}) ->
+ true;
+is_c_nil(_) ->
+ false.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_cons(Head::cerl(), Tail::cerl()) -> cerl()
+%%
+%% @doc Creates an abstract list constructor. The result represents
+%% "<code>[<em>Head</em> | <em>Tail</em>]</code>". Note that if both
+%% <code>Head</code> and <code>Tail</code> have type
+%% <code>literal</code>, then the result will also have type
+%% <code>literal</code>, and annotations on <code>Head</code> and
+%% <code>Tail</code> are lost.
+%%
+%% <p>Recall that in Erlang, the tail element of a list constructor is
+%% not necessarily a list.</p>
+%%
+%% @see ann_c_cons/3
+%% @see update_c_cons/3
+%% @see c_cons_skel/2
+%% @see is_c_cons/1
+%% @see cons_hd/1
+%% @see cons_tl/1
+%% @see is_c_list/1
+%% @see c_nil/0
+%% @see list_elements/1
+%% @see list_length/1
+%% @see make_list/2
+
+%% *Always* collapse literals.
+
+-spec c_cons(cerl(), cerl()) -> c_literal() | c_cons().
+
+c_cons(#c_literal{val = Head}, #c_literal{val = Tail}) ->
+ #c_literal{val = [Head | Tail]};
+c_cons(Head, Tail) ->
+ #c_cons{hd = Head, tl = Tail}.
+
+
+%% @spec ann_c_cons(As::anns(), Head::cerl(), Tail::cerl()) -> cerl()
+%% @see c_cons/2
+
+-spec ann_c_cons(anns(), cerl(), cerl()) -> c_literal() | c_cons().
+
+ann_c_cons(As, #c_literal{val = Head}, #c_literal{val = Tail}) ->
+ #c_literal{val = [Head | Tail], anno = As};
+ann_c_cons(As, Head, Tail) ->
+ #c_cons{hd = Head, tl = Tail, anno = As}.
+
+
+%% @spec update_c_cons(Old::cerl(), Head::cerl(), Tail::cerl()) ->
+%% cerl()
+%% @see c_cons/2
+
+-spec update_c_cons(c_literal() | c_cons(), cerl(), cerl()) ->
+ c_literal() | c_cons().
+
+update_c_cons(Node, #c_literal{val = Head}, #c_literal{val = Tail}) ->
+ #c_literal{val = [Head | Tail], anno = get_ann(Node)};
+update_c_cons(Node, Head, Tail) ->
+ #c_cons{hd = Head, tl = Tail, anno = get_ann(Node)}.
+
+
+%% @spec c_cons_skel(Head::cerl(), Tail::cerl()) -> c_cons()
+%%
+%% @doc Creates an abstract list constructor skeleton. Does not fold
+%% constant literals, i.e., the result always has type
+%% <code>cons</code>, representing "<code>[<em>Head</em> |
+%% <em>Tail</em>]</code>".
+%%
+%% <p>This function is occasionally useful when it is necessary to have
+%% annotations on the subnodes of a list constructor node, even when the
+%% subnodes are constant literals. Note however that
+%% <code>is_literal/1</code> will yield <code>false</code> and
+%% <code>concrete/1</code> will fail if passed the result from this
+%% function.</p>
+%%
+%% <p><code>fold_literal/1</code> can be used to revert a node to the
+%% normal-form representation.</p>
+%%
+%% @see ann_c_cons_skel/3
+%% @see update_c_cons_skel/3
+%% @see c_cons/2
+%% @see is_c_cons/1
+%% @see is_c_list/1
+%% @see c_nil/0
+%% @see is_literal/1
+%% @see fold_literal/1
+%% @see concrete/1
+
+%% *Never* collapse literals.
+
+-spec c_cons_skel(cerl(), cerl()) -> c_cons().
+
+c_cons_skel(Head, Tail) ->
+ #c_cons{hd = Head, tl = Tail}.
+
+
+%% @spec ann_c_cons_skel(As::anns(), Head::cerl(), Tail::cerl()) ->
+%% c_cons()
+%% @see c_cons_skel/2
+
+-spec ann_c_cons_skel(anns(), cerl(), cerl()) -> c_cons().
+
+ann_c_cons_skel(As, Head, Tail) ->
+ #c_cons{hd = Head, tl = Tail, anno = As}.
+
+
+%% @spec update_c_cons_skel(Old::cerl(), Head::cerl(), Tail::cerl()) ->
+%% c_cons()
+%% @see c_cons_skel/2
+
+-spec update_c_cons_skel(c_cons() | c_literal(), cerl(), cerl()) -> c_cons().
+
+update_c_cons_skel(Node, Head, Tail) ->
+ #c_cons{hd = Head, tl = Tail, anno = get_ann(Node)}.
+
+
+%% @spec is_c_cons(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% list constructor, otherwise <code>false</code>.
+
+-spec is_c_cons(cerl()) -> boolean().
+
+is_c_cons(#c_cons{}) ->
+ true;
+is_c_cons(#c_literal{val = [_ | _]}) ->
+ true;
+is_c_cons(_) ->
+ false.
+
+
+%% @spec cons_hd(cerl()) -> cerl()
+%%
+%% @doc Returns the head subtree of an abstract list constructor.
+%%
+%% @see c_cons/2
+
+-spec cons_hd(c_cons() | c_literal()) -> cerl().
+
+cons_hd(#c_cons{hd = Head}) ->
+ Head;
+cons_hd(#c_literal{val = [Head | _]}) ->
+ #c_literal{val = Head}.
+
+
+%% @spec cons_tl(c_cons() | c_literal()) -> cerl()
+%%
+%% @doc Returns the tail subtree of an abstract list constructor.
+%%
+%% <p>Recall that the tail does not necessarily represent a proper
+%% list.</p>
+%%
+%% @see c_cons/2
+
+-spec cons_tl(c_cons() | c_literal()) -> cerl().
+
+cons_tl(#c_cons{tl = Tail}) ->
+ Tail;
+cons_tl(#c_literal{val = [_ | Tail]}) ->
+ #c_literal{val = Tail}.
+
+
+%% @spec is_c_list(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> represents a
+%% proper list, otherwise <code>false</code>. A proper list is either
+%% the empty list <code>[]</code>, or a cons cell <code>[<em>Head</em> |
+%% <em>Tail</em>]</code>, where recursively <code>Tail</code> is a
+%% proper list.
+%%
+%% <p>Note: Because <code>Node</code> is a syntax tree, the actual
+%% run-time values corresponding to its subtrees may often be partially
+%% or completely unknown. Thus, if <code>Node</code> represents e.g.
+%% "<code>[... | Ns]</code>" (where <code>Ns</code> is a variable), then
+%% the function will return <code>false</code>, because it is not known
+%% whether <code>Ns</code> will be bound to a list at run-time. If
+%% <code>Node</code> instead represents e.g. "<code>[1, 2, 3]</code>" or
+%% "<code>[A | []]</code>", then the function will return
+%% <code>true</code>.</p>
+%%
+%% @see c_cons/2
+%% @see c_nil/0
+%% @see list_elements/1
+%% @see list_length/1
+
+-spec is_c_list(cerl()) -> boolean().
+
+is_c_list(#c_cons{tl = Tail}) ->
+ is_c_list(Tail);
+is_c_list(#c_literal{val = V}) ->
+ is_proper_list(V);
+is_c_list(_) ->
+ false.
+
+is_proper_list([_ | Tail]) ->
+ is_proper_list(Tail);
+is_proper_list([]) ->
+ true;
+is_proper_list(_) ->
+ false.
+
+%% @spec list_elements(c_cons() | c_literal()) -> [cerl()]
+%%
+%% @doc Returns the list of element subtrees of an abstract list.
+%% <code>Node</code> must represent a proper list. E.g., if
+%% <code>Node</code> represents "<code>[<em>X1</em>, <em>X2</em> |
+%% [<em>X3</em>, <em>X4</em> | []]</code>", then
+%% <code>list_elements(Node)</code> yields the list <code>[X1, X2, X3,
+%% X4]</code>.
+%%
+%% @see c_cons/2
+%% @see c_nil/0
+%% @see is_c_list/1
+%% @see list_length/1
+%% @see make_list/2
+
+-spec list_elements(c_cons() | c_literal()) -> [cerl()].
+
+list_elements(#c_cons{hd = Head, tl = Tail}) ->
+ [Head | list_elements(Tail)];
+list_elements(#c_literal{val = V}) ->
+ abstract_list(V).
+
+abstract_list([X | Xs]) ->
+ [abstract(X) | abstract_list(Xs)];
+abstract_list([]) ->
+ [].
+
+
+%% @spec list_length(Node::c_cons() | c_literal()) -> integer()
+%%
+%% @doc Returns the number of element subtrees of an abstract list.
+%% <code>Node</code> must represent a proper list. E.g., if
+%% <code>Node</code> represents "<code>[X1 | [X2, X3 | [X4, X5,
+%% X6]]]</code>", then <code>list_length(Node)</code> returns the
+%% integer 6.
+%%
+%% <p>Note: this is equivalent to
+%% <code>length(list_elements(Node))</code>, but potentially more
+%% efficient.</p>
+%%
+%% @see c_cons/2
+%% @see c_nil/0
+%% @see is_c_list/1
+%% @see list_elements/1
+
+-spec list_length(c_cons() | c_literal()) -> non_neg_integer().
+
+list_length(L) ->
+ list_length(L, 0).
+
+list_length(#c_cons{tl = Tail}, A) ->
+ list_length(Tail, A + 1);
+list_length(#c_literal{val = V}, A) ->
+ A + length(V).
+
+
+%% @spec make_list(List) -> Node
+%% @equiv make_list(List, none)
+
+-spec make_list([cerl()]) -> cerl().
+
+make_list(List) ->
+ ann_make_list([], List).
+
+
+%% @spec make_list(List::[cerl()], Tail) -> cerl()
+%%
+%% Tail = cerl() | none
+%%
+%% @doc Creates an abstract list from the elements in <code>List</code>
+%% and the optional <code>Tail</code>. If <code>Tail</code> is
+%% <code>none</code>, the result will represent a nil-terminated list,
+%% otherwise it represents "<code>[... | <em>Tail</em>]</code>".
+%%
+%% @see c_cons/2
+%% @see c_nil/0
+%% @see ann_make_list/3
+%% @see update_list/3
+%% @see list_elements/1
+
+-spec make_list([cerl()], cerl() | 'none') -> cerl().
+
+make_list(List, Tail) ->
+ ann_make_list([], List, Tail).
+
+
+%% @spec update_list(Old::cerl(), List::[cerl()]) -> cerl()
+%% @equiv update_list(Old, List, none)
+
+-spec update_list(cerl(), [cerl()]) -> cerl().
+
+update_list(Node, List) ->
+ ann_make_list(get_ann(Node), List).
+
+
+%% @spec update_list(Old::cerl(), List::[cerl()], Tail) -> cerl()
+%%
+%% Tail = cerl() | none
+%%
+%% @see make_list/2
+%% @see update_list/2
+
+-spec update_list(cerl(), [cerl()], cerl() | 'none') -> cerl().
+
+update_list(Node, List, Tail) ->
+ ann_make_list(get_ann(Node), List, Tail).
+
+
+%% @spec ann_make_list(As::anns(), List::[cerl()]) -> cerl()
+%% @equiv ann_make_list(As, List, none)
+
+-spec ann_make_list(anns(), [cerl()]) -> cerl().
+
+ann_make_list(As, List) ->
+ ann_make_list(As, List, none).
+
+
+%% @spec ann_make_list(As::anns(), List::[cerl()], Tail) -> cerl()
+%%
+%% Tail = cerl() | none
+%%
+%% @see make_list/2
+%% @see ann_make_list/2
+
+-spec ann_make_list(anns(), [cerl()], cerl() | 'none') -> cerl().
+
+ann_make_list(As, [H | T], Tail) ->
+ ann_c_cons(As, H, make_list(T, Tail)); % `c_cons' folds literals
+ann_make_list(As, [], none) ->
+ ann_c_nil(As);
+ann_make_list(_, [], Node) ->
+ Node.
+
+
+%% ---------------------------------------------------------------------
+%% maps
+
+%% @spec is_c_map(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% map constructor, otherwise <code>false</code>.
+
+-spec is_c_map(cerl()) -> boolean().
+
+is_c_map(#c_map{}) ->
+ true;
+is_c_map(#c_literal{val = V}) when is_map(V) ->
+ true;
+is_c_map(_) ->
+ false.
+
+-spec map_es(c_map() | c_literal()) -> [c_map_pair()].
+
+map_es(#c_literal{anno=As,val=M}) when is_map(M) ->
+ [ann_c_map_pair(As,
+ #c_literal{anno=As,val='assoc'},
+ #c_literal{anno=As,val=K},
+ #c_literal{anno=As,val=V}) || {K,V} <- maps:to_list(M)];
+map_es(#c_map{es = Es}) ->
+ Es.
+
+-spec map_arg(c_map() | c_literal()) -> c_map() | c_literal().
+
+map_arg(#c_literal{anno=As,val=M}) when is_map(M) ->
+ #c_literal{anno=As,val=#{}};
+map_arg(#c_map{arg=M}) ->
+ M.
+
+-spec c_map([c_map_pair()]) -> c_map().
+
+c_map(Pairs) ->
+ ann_c_map([], Pairs).
+
+-spec c_map_pattern([c_map_pair()]) -> c_map().
+
+c_map_pattern(Pairs) ->
+ #c_map{es=Pairs, is_pat=true}.
+
+-spec ann_c_map_pattern([term()], [c_map_pair()]) -> c_map().
+
+ann_c_map_pattern(As, Pairs) ->
+ #c_map{anno=As, es=Pairs, is_pat=true}.
+
+-spec is_c_map_empty(c_map() | c_literal()) -> boolean().
+
+is_c_map_empty(#c_map{ es=[] }) -> true;
+is_c_map_empty(#c_literal{val=M}) when is_map(M),map_size(M) =:= 0 -> true;
+is_c_map_empty(_) -> false.
+
+-spec is_c_map_pattern(c_map()) -> boolean().
+
+is_c_map_pattern(#c_map{is_pat=IsPat}) ->
+ IsPat.
+
+-spec ann_c_map([term()], [c_map_pair()]) -> c_map() | c_literal().
+
+ann_c_map(As, Es) ->
+ ann_c_map(As, #c_literal{val=#{}}, Es).
+
+-spec ann_c_map(anns(), c_map() | c_literal(), [c_map_pair()]) -> c_map() | c_literal().
+
+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{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.
+
+-spec update_c_map(c_map(), cerl(), [cerl()]) -> c_map() | c_literal().
+
+update_c_map(#c_map{is_pat=true}=Old, M, Es) ->
+ Old#c_map{arg=M, es=Es};
+update_c_map(#c_map{is_pat=false}=Old, M, Es) ->
+ ann_c_map(get_ann(Old), M, Es).
+
+map_pair_key(#c_map_pair{key=K}) -> K.
+map_pair_val(#c_map_pair{val=V}) -> V.
+map_pair_op(#c_map_pair{op=Op}) -> Op.
+
+-spec c_map_pair(cerl(), cerl()) -> c_map_pair().
+
+c_map_pair(Key,Val) ->
+ #c_map_pair{op=#c_literal{val=assoc},key=Key,val=Val}.
+
+-spec c_map_pair_exact(cerl(), cerl()) -> c_map_pair().
+
+c_map_pair_exact(Key,Val) ->
+ #c_map_pair{op=#c_literal{val=exact},key=Key,val=Val}.
+
+-spec ann_c_map_pair(anns(), cerl(), cerl(), cerl()) ->
+ c_map_pair().
+
+ann_c_map_pair(As,Op,K,V) ->
+ #c_map_pair{op = Op, key = K, val = V, anno = As}.
+
+update_c_map_pair(Old,Op,K,V) ->
+ #c_map_pair{op = Op, key = K, val = V, anno = get_ann(Old)}.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_tuple(Elements::[cerl()]) -> cerl()
+%%
+%% @doc Creates an abstract tuple. If <code>Elements</code> is
+%% <code>[E1, ..., En]</code>, the result represents
+%% "<code>{<em>E1</em>, ..., <em>En</em>}</code>". Note that if all
+%% nodes in <code>Elements</code> have type <code>literal</code>, or if
+%% <code>Elements</code> is empty, then the result will also have type
+%% <code>literal</code> and annotations on nodes in
+%% <code>Elements</code> are lost.
+%%
+%% <p>Recall that Erlang has distinct 1-tuples, i.e., <code>{X}</code>
+%% is always distinct from <code>X</code> itself.</p>
+%%
+%% @see ann_c_tuple/2
+%% @see update_c_tuple/2
+%% @see is_c_tuple/1
+%% @see tuple_es/1
+%% @see tuple_arity/1
+%% @see c_tuple_skel/1
+
+%% *Always* collapse literals.
+
+-spec c_tuple([cerl()]) -> c_tuple() | c_literal().
+
+c_tuple(Es) ->
+ case is_lit_list(Es) of
+ false ->
+ #c_tuple{es = Es};
+ true ->
+ #c_literal{val = list_to_tuple(lit_list_vals(Es))}
+ end.
+
+
+%% @spec ann_c_tuple(As::anns(), Elements::[cerl()]) -> cerl()
+%% @see c_tuple/1
+
+-spec ann_c_tuple(anns(), [cerl()]) -> c_tuple() | c_literal().
+
+ann_c_tuple(As, Es) ->
+ case is_lit_list(Es) of
+ false ->
+ #c_tuple{es = Es, anno = As};
+ true ->
+ #c_literal{val = list_to_tuple(lit_list_vals(Es)), anno = As}
+ end.
+
+
+%% @spec update_c_tuple(Old::cerl(), Elements::[cerl()]) -> cerl()
+%% @see c_tuple/1
+
+-spec update_c_tuple(c_tuple() | c_literal(), [cerl()]) -> c_tuple() | c_literal().
+
+update_c_tuple(Node, Es) ->
+ case is_lit_list(Es) of
+ false ->
+ #c_tuple{es = Es, anno = get_ann(Node)};
+ true ->
+ #c_literal{val = list_to_tuple(lit_list_vals(Es)),
+ anno = get_ann(Node)}
+ end.
+
+
+%% @spec c_tuple_skel(Elements::[cerl()]) -> cerl()
+%%
+%% @doc Creates an abstract tuple skeleton. Does not fold constant
+%% literals, i.e., the result always has type <code>tuple</code>,
+%% representing "<code>{<em>E1</em>, ..., <em>En</em>}</code>", if
+%% <code>Elements</code> is <code>[E1, ..., En]</code>.
+%%
+%% <p>This function is occasionally useful when it is necessary to have
+%% annotations on the subnodes of a tuple node, even when all the
+%% subnodes are constant literals. Note however that
+%% <code>is_literal/1</code> will yield <code>false</code> and
+%% <code>concrete/1</code> will fail if passed the result from this
+%% function.</p>
+%%
+%% <p><code>fold_literal/1</code> can be used to revert a node to the
+%% normal-form representation.</p>
+%%
+%% @see ann_c_tuple_skel/2
+%% @see update_c_tuple_skel/2
+%% @see c_tuple/1
+%% @see tuple_es/1
+%% @see is_c_tuple/1
+%% @see is_literal/1
+%% @see fold_literal/1
+%% @see concrete/1
+
+%% *Never* collapse literals.
+
+-spec c_tuple_skel([cerl()]) -> c_tuple().
+
+c_tuple_skel(Es) ->
+ #c_tuple{es = Es}.
+
+
+%% @spec ann_c_tuple_skel(As::anns(), Elements::[cerl()]) -> cerl()
+%% @see c_tuple_skel/1
+
+-spec ann_c_tuple_skel(anns(), [cerl()]) -> c_tuple().
+
+ann_c_tuple_skel(As, Es) ->
+ #c_tuple{es = Es, anno = As}.
+
+
+%% @spec update_c_tuple_skel(Old::cerl(), Elements::[cerl()]) -> cerl()
+%% @see c_tuple_skel/1
+
+-spec update_c_tuple_skel(c_tuple(), [cerl()]) -> c_tuple().
+
+update_c_tuple_skel(Old, Es) ->
+ #c_tuple{es = Es, anno = get_ann(Old)}.
+
+
+%% @spec is_c_tuple(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% tuple, otherwise <code>false</code>.
+%%
+%% @see c_tuple/1
+
+-spec is_c_tuple(cerl()) -> boolean().
+
+is_c_tuple(#c_tuple{}) ->
+ true;
+is_c_tuple(#c_literal{val = V}) when is_tuple(V) ->
+ true;
+is_c_tuple(_) ->
+ false.
+
+
+%% @spec tuple_es(cerl()) -> [cerl()]
+%%
+%% @doc Returns the list of element subtrees of an abstract tuple.
+%%
+%% @see c_tuple/1
+
+-spec tuple_es(c_tuple() | c_literal()) -> [cerl()].
+
+tuple_es(#c_tuple{es = Es}) ->
+ Es;
+tuple_es(#c_literal{val = V}) ->
+ make_lit_list(tuple_to_list(V)).
+
+
+%% @spec tuple_arity(Node::cerl()) -> integer()
+%%
+%% @doc Returns the number of element subtrees of an abstract tuple.
+%%
+%% <p>Note: this is equivalent to <code>length(tuple_es(Node))</code>,
+%% but potentially more efficient.</p>
+%%
+%% @see tuple_es/1
+%% @see c_tuple/1
+
+-spec tuple_arity(c_tuple() | c_literal()) -> non_neg_integer().
+
+tuple_arity(#c_tuple{es = Es}) ->
+ length(Es);
+tuple_arity(#c_literal{val = V}) when is_tuple(V) ->
+ tuple_size(V).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_var(Name::var_name()) -> cerl()
+%%
+%% var_name() = integer() | atom() | {atom(), arity()}
+%%
+%% @doc Creates an abstract variable. A variable is identified by its
+%% name, given by the <code>Name</code> parameter.
+%%
+%% <p>If a name is given by a single atom, it should either be a
+%% "simple" atom which does not need to be single-quoted in Erlang, or
+%% otherwise its print name should correspond to a proper Erlang
+%% variable, i.e., begin with an uppercase character or an
+%% underscore. Names on the form <code>{A, N}</code> represent
+%% function name variables "<code><em>A</em>/<em>N</em></code>"; these
+%% are special variables which may be bound only in the function
+%% definitions of a module or a <code>letrec</code>. They may not be
+%% bound in <code>let</code> expressions and cannot occur in clause
+%% patterns. The atom <code>A</code> in a function name may be any
+%% atom; the integer <code>N</code> must be nonnegative. The functions
+%% <code>c_fname/2</code> etc. are utilities for handling function
+%% name variables.</p>
+%%
+%% <p>When printing variable names, they must have the form of proper
+%% Core Erlang variables and function names. E.g., a name represented
+%% by an integer such as <code>42</code> could be formatted as
+%% "<code>_42</code>", an atom <code>'Xxx'</code> simply as
+%% "<code>Xxx</code>", and an atom <code>foo</code> as
+%% "<code>_foo</code>". However, one must assure that any two valid
+%% distinct names are never mapped to the same strings. Tuples such
+%% as <code>{foo, 2}</code> representing function names can simply by
+%% formatted as "<code>'foo'/2</code>", with no risk of conflicts.</p>
+%%
+%% @see ann_c_var/2
+%% @see update_c_var/2
+%% @see is_c_var/1
+%% @see var_name/1
+%% @see c_fname/2
+%% @see c_module/4
+%% @see c_letrec/2
+
+-spec c_var(var_name()) -> c_var().
+
+c_var(Name) ->
+ #c_var{name = Name}.
+
+
+%% @spec ann_c_var(As::anns(), Name::var_name()) -> c_var()
+%%
+%% @see c_var/1
+
+-spec ann_c_var(anns(), var_name()) -> c_var().
+
+ann_c_var(As, Name) ->
+ #c_var{name = Name, anno = As}.
+
+%% @spec update_c_var(Old::cerl(), Name::var_name()) -> c_var()
+%%
+%% @see c_var/1
+
+-spec update_c_var(c_var(), var_name()) -> c_var().
+
+update_c_var(Node, Name) ->
+ #c_var{name = Name, anno = get_ann(Node)}.
+
+
+%% @spec is_c_var(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% variable, otherwise <code>false</code>.
+%%
+%% @see c_var/1
+
+-spec is_c_var(cerl()) -> boolean().
+
+is_c_var(#c_var{}) ->
+ true;
+is_c_var(_) ->
+ false.
+
+
+%% @spec c_fname(Name::atom(), Arity::arity()) -> c_var()
+%% @equiv c_var({Name, Arity})
+%% @see fname_id/1
+%% @see fname_arity/1
+%% @see is_c_fname/1
+%% @see ann_c_fname/3
+%% @see update_c_fname/3
+
+-spec c_fname(atom(), arity()) -> c_var().
+
+c_fname(Atom, Arity) ->
+ c_var({Atom, Arity}).
+
+
+%% @spec ann_c_fname(As::anns(), Name::atom(), Arity::arity()) -> c_var()
+%%
+%% @equiv ann_c_var(As, {Atom, Arity})
+%% @see c_fname/2
+
+-spec ann_c_fname(anns(), atom(), arity()) -> c_var().
+
+ann_c_fname(As, Atom, Arity) ->
+ ann_c_var(As, {Atom, Arity}).
+
+
+%% @spec update_c_fname(Old::c_var(), Name::atom()) -> c_var()
+%% @doc Like <code>update_c_fname/3</code>, but takes the arity from
+%% <code>Node</code>.
+%% @see update_c_fname/3
+%% @see c_fname/2
+
+-spec update_c_fname(c_var(), atom()) -> c_var().
+
+update_c_fname(#c_var{name = {_, Arity}, anno = As}, Atom) ->
+ #c_var{name = {Atom, Arity}, anno = As}.
+
+
+%% @spec update_c_fname(Old::var(), Name::atom(), Arity::arity()) -> c_var()
+%%
+%% @equiv update_c_var(Old, {Atom, Arity})
+%% @see update_c_fname/2
+%% @see c_fname/2
+
+-spec update_c_fname(c_var(), atom(), arity()) -> c_var().
+
+update_c_fname(Node, Atom, Arity) ->
+ update_c_var(Node, {Atom, Arity}).
+
+
+%% @spec is_c_fname(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% function name variable, otherwise <code>false</code>.
+%%
+%% @see c_fname/2
+%% @see c_var/1
+%% @see var_name/1
+
+-spec is_c_fname(cerl()) -> boolean().
+
+is_c_fname(#c_var{name = {A, N}}) when is_atom(A), is_integer(N), N >= 0 ->
+ true;
+is_c_fname(_) ->
+ false.
+
+
+%% @spec var_name(c_var()) -> var_name()
+%%
+%% @doc Returns the name of an abstract variable.
+%%
+%% @see c_var/1
+
+-spec var_name(c_var()) -> var_name().
+
+var_name(Node) ->
+ Node#c_var.name.
+
+
+%% @spec fname_id(c_var()) -> atom()
+%%
+%% @doc Returns the identifier part of an abstract function name
+%% variable.
+%%
+%% @see fname_arity/1
+%% @see c_fname/2
+
+-spec fname_id(c_var()) -> atom().
+
+fname_id(#c_var{name={A,_}}) ->
+ A.
+
+
+%% @spec fname_arity(c_var()) -> arity()
+%%
+%% @doc Returns the arity part of an abstract function name variable.
+%%
+%% @see fname_id/1
+%% @see c_fname/2
+
+-spec fname_arity(c_var()) -> arity().
+
+fname_arity(#c_var{name={_,N}}) ->
+ N.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_values(Elements::[cerl()]) -> c_values()
+%%
+%% @doc Creates an abstract value list. If <code>Elements</code> is
+%% <code>[E1, ..., En]</code>, the result represents
+%% "<code>&lt;<em>E1</em>, ..., <em>En</em>&gt;</code>".
+%%
+%% @see ann_c_values/2
+%% @see update_c_values/2
+%% @see is_c_values/1
+%% @see values_es/1
+%% @see values_arity/1
+
+-spec c_values([cerl()]) -> c_values().
+
+c_values(Es) ->
+ #c_values{es = Es}.
+
+
+%% @spec ann_c_values(As::anns(), Elements::[cerl()]) -> c_values()
+%% @see c_values/1
+
+-spec ann_c_values(anns(), [cerl()]) -> c_values().
+
+ann_c_values(As, Es) ->
+ #c_values{es = Es, anno = As}.
+
+
+%% @spec update_c_values(Old::cerl(), Elements::[cerl()]) -> c_values()
+%% @see c_values/1
+
+-spec update_c_values(c_values(), [cerl()]) -> c_values().
+
+update_c_values(Node, Es) ->
+ #c_values{es = Es, anno = get_ann(Node)}.
+
+
+%% @spec is_c_values(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% value list; otherwise <code>false</code>.
+%%
+%% @see c_values/1
+
+-spec is_c_values(cerl()) -> boolean().
+
+is_c_values(#c_values{}) ->
+ true;
+is_c_values(_) ->
+ false.
+
+
+%% @spec values_es(c_values()) -> [cerl()]
+%%
+%% @doc Returns the list of element subtrees of an abstract value
+%% list.
+%%
+%% @see c_values/1
+%% @see values_arity/1
+
+-spec values_es(c_values()) -> [cerl()].
+
+values_es(Node) ->
+ Node#c_values.es.
+
+
+%% @spec values_arity(Node::c_values()) -> non_neg_integer()
+%%
+%% @doc Returns the number of element subtrees of an abstract value
+%% list.
+%%
+%% <p>Note: This is equivalent to
+%% <code>length(values_es(Node))</code>, but potentially more
+%% efficient.</p>
+%%
+%% @see c_values/1
+%% @see values_es/1
+
+-spec values_arity(c_values()) -> non_neg_integer().
+
+values_arity(Node) ->
+ length(values_es(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_binary(Segments::[c_bitstr()]) -> c_binary()
+%%
+%% @doc Creates an abstract binary-template. A binary object is a
+%% sequence of 8-bit bytes. It is specified by zero or more bit-string
+%% template <em>segments</em> of arbitrary lengths (in number of bits),
+%% such that the sum of the lengths is evenly divisible by 8. If
+%% <code>Segments</code> is <code>[S1, ..., Sn]</code>, the result
+%% represents "<code>#{<em>S1</em>, ..., <em>Sn</em>}#</code>". All the
+%% <code>Si</code> must have type <code>bitstr</code>.
+%%
+%% @see ann_c_binary/2
+%% @see update_c_binary/2
+%% @see is_c_binary/1
+%% @see binary_segments/1
+%% @see c_bitstr/5
+
+-spec c_binary([c_bitstr()]) -> c_binary().
+
+c_binary(Segments) ->
+ #c_binary{segments = Segments}.
+
+
+%% @spec ann_c_binary(As::anns(), Segments::[c_bitstr()]) -> c_binary()
+%% @see c_binary/1
+
+-spec ann_c_binary(anns(), [c_bitstr()]) -> c_binary().
+
+ann_c_binary(As, Segments) ->
+ #c_binary{segments = Segments, anno = As}.
+
+
+%% @spec update_c_binary(Old::cerl(), Segments::[c_bitstr()]) -> cerl()
+%% @see c_binary/1
+
+-spec update_c_binary(c_binary(), [c_bitstr()]) -> c_binary().
+
+update_c_binary(Node, Segments) ->
+ #c_binary{segments = Segments, anno = get_ann(Node)}.
+
+
+%% @spec is_c_binary(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% binary-template; otherwise <code>false</code>.
+%%
+%% @see c_binary/1
+
+-spec is_c_binary(cerl()) -> boolean().
+
+is_c_binary(#c_binary{}) ->
+ true;
+is_c_binary(_) ->
+ false.
+
+
+%% @spec binary_segments(cerl()) -> [c_bitstr()]
+%%
+%% @doc Returns the list of segment subtrees of an abstract
+%% binary-template.
+%%
+%% @see c_binary/1
+%% @see c_bitstr/5
+
+-spec binary_segments(c_binary()) -> [c_bitstr()].
+
+binary_segments(Node) ->
+ Node#c_binary.segments.
+
+
+%% @spec c_bitstr(Value::cerl(), Size::cerl(), Unit::cerl(),
+%% Type::cerl(), Flags::cerl()) -> c_bitstr()
+%%
+%% @doc Creates an abstract bit-string template. These can only occur as
+%% components of an abstract binary-template (see {@link c_binary/1}).
+%% The result represents "<code>#&lt;<em>Value</em>&gt;(<em>Size</em>,
+%% <em>Unit</em>, <em>Type</em>, <em>Flags</em>)</code>", where
+%% <code>Unit</code> must represent a positive integer constant,
+%% <code>Type</code> must represent a constant atom (one of
+%% <code>'integer'</code>, <code>'float'</code>, or
+%% <code>'binary'</code>), and <code>Flags</code> must represent a
+%% constant list <code>"[<em>F1</em>, ..., <em>Fn</em>]"</code> where
+%% all the <code>Fi</code> are atoms.
+%%
+%% @see c_binary/1
+%% @see ann_c_bitstr/6
+%% @see update_c_bitstr/6
+%% @see is_c_bitstr/1
+%% @see bitstr_val/1
+%% @see bitstr_size/1
+%% @see bitstr_unit/1
+%% @see bitstr_type/1
+%% @see bitstr_flags/1
+
+-spec c_bitstr(cerl(), cerl(), cerl(), cerl(), cerl()) -> c_bitstr().
+
+c_bitstr(Val, Size, Unit, Type, Flags) ->
+ #c_bitstr{val = Val, size = Size, unit = Unit, type = Type,
+ flags = Flags}.
+
+
+%% @spec c_bitstr(Value::cerl(), Size::cerl(), Type::cerl(),
+%% Flags::cerl()) -> c_bitstr()
+%% @equiv c_bitstr(Value, Size, abstract(1), Type, Flags)
+
+-spec c_bitstr(cerl(), cerl(), cerl(), cerl()) -> c_bitstr().
+
+c_bitstr(Val, Size, Type, Flags) ->
+ c_bitstr(Val, Size, abstract(1), Type, Flags).
+
+
+%% @spec c_bitstr(Value::cerl(), Type::cerl(),
+%% Flags::cerl()) -> c_bitstr()
+%% @equiv c_bitstr(Value, abstract(all), abstract(1), Type, Flags)
+
+-spec c_bitstr(cerl(), cerl(), cerl()) -> c_bitstr().
+
+c_bitstr(Val, Type, Flags) ->
+ c_bitstr(Val, abstract(all), abstract(1), Type, Flags).
+
+
+%% @spec ann_c_bitstr(As::anns(), Value::cerl(), Size::cerl(),
+%% Unit::cerl(), Type::cerl(), Flags::cerl()) -> cerl()
+%% @see c_bitstr/5
+%% @see ann_c_bitstr/5
+
+-spec ann_c_bitstr(anns(), cerl(), cerl(), cerl(), cerl(), cerl()) ->
+ c_bitstr().
+
+ann_c_bitstr(As, Val, Size, Unit, Type, Flags) ->
+ #c_bitstr{val = Val, size = Size, unit = Unit, type = Type,
+ flags = Flags, anno = As}.
+
+%% @spec ann_c_bitstr(As::anns(), Value::cerl(), Size::cerl(),
+%% Type::cerl(), Flags::cerl()) -> c_bitstr()
+%% @equiv ann_c_bitstr(As, Value, Size, abstract(1), Type, Flags)
+
+-spec ann_c_bitstr(anns(), cerl(), cerl(), cerl(), cerl()) -> c_bitstr().
+
+ann_c_bitstr(As, Value, Size, Type, Flags) ->
+ ann_c_bitstr(As, Value, Size, abstract(1), Type, Flags).
+
+
+%% @spec update_c_bitstr(Old::c_bitstr(), Value::cerl(), Size::cerl(),
+%% Unit::cerl(), Type::cerl(), Flags::cerl()) -> c_bitstr()
+%% @see c_bitstr/5
+%% @see update_c_bitstr/5
+
+-spec update_c_bitstr(c_bitstr(), cerl(), cerl(), cerl(), cerl(), cerl()) ->
+ c_bitstr().
+
+update_c_bitstr(Node, Val, Size, Unit, Type, Flags) ->
+ #c_bitstr{val = Val, size = Size, unit = Unit, type = Type,
+ flags = Flags, anno = get_ann(Node)}.
+
+
+%% @spec update_c_bitstr(Old::c_bitstr(), Value::cerl(), Size::cerl(),
+%% Type::cerl(), Flags::cerl()) -> c_bitstr()
+%% @equiv update_c_bitstr(Node, Value, Size, abstract(1), Type, Flags)
+
+-spec update_c_bitstr(c_bitstr(), cerl(), cerl(), cerl(), cerl()) -> c_bitstr().
+
+update_c_bitstr(Node, Value, Size, Type, Flags) ->
+ update_c_bitstr(Node, Value, Size, abstract(1), Type, Flags).
+
+%% @spec is_c_bitstr(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% bit-string template; otherwise <code>false</code>.
+%%
+%% @see c_bitstr/5
+
+-spec is_c_bitstr(cerl()) -> boolean().
+
+is_c_bitstr(#c_bitstr{}) ->
+ true;
+is_c_bitstr(_) ->
+ false.
+
+
+%% @spec bitstr_val(c_bitstr()) -> cerl()
+%%
+%% @doc Returns the value subtree of an abstract bit-string template.
+%%
+%% @see c_bitstr/5
+
+-spec bitstr_val(c_bitstr()) -> cerl().
+
+bitstr_val(Node) ->
+ Node#c_bitstr.val.
+
+
+%% @spec bitstr_size(c_bitstr()) -> cerl()
+%%
+%% @doc Returns the size subtree of an abstract bit-string template.
+%%
+%% @see c_bitstr/5
+
+-spec bitstr_size(c_bitstr()) -> cerl().
+
+bitstr_size(Node) ->
+ Node#c_bitstr.size.
+
+
+%% @spec bitstr_bitsize(c_bitstr()) -> any | all | utf | integer()
+%%
+%% @doc Returns the total size in bits of an abstract bit-string
+%% template. If the size field is an integer literal, the result is the
+%% product of the size and unit values; if the size field is the atom
+%% literal <code>all</code>, the atom <code>all</code> is returned.
+%% If the size is not a literal, the atom <code>any</code> is returned.
+%%
+%% @see c_bitstr/5
+
+-spec bitstr_bitsize(c_bitstr()) -> 'all' | 'any' | 'utf' | non_neg_integer().
+
+bitstr_bitsize(Node) ->
+ Size = Node#c_bitstr.size,
+ case is_literal(Size) of
+ true ->
+ case concrete(Size) of
+ all ->
+ all;
+ undefined ->
+ %% just an assertion below
+ "utf" ++ _ = atom_to_list(concrete(Node#c_bitstr.type)),
+ utf;
+ S when is_integer(S) ->
+ S * concrete(Node#c_bitstr.unit)
+ end;
+ false ->
+ any
+ end.
+
+
+%% @spec bitstr_unit(c_bitstr()) -> cerl()
+%%
+%% @doc Returns the unit subtree of an abstract bit-string template.
+%%
+%% @see c_bitstr/5
+
+-spec bitstr_unit(c_bitstr()) -> cerl().
+
+bitstr_unit(Node) ->
+ Node#c_bitstr.unit.
+
+
+%% @spec bitstr_type(c_bitstr()) -> cerl()
+%%
+%% @doc Returns the type subtree of an abstract bit-string template.
+%%
+%% @see c_bitstr/5
+
+-spec bitstr_type(c_bitstr()) -> cerl().
+
+bitstr_type(Node) ->
+ Node#c_bitstr.type.
+
+
+%% @spec bitstr_flags(c_bitstr()) -> cerl()
+%%
+%% @doc Returns the flags subtree of an abstract bit-string template.
+%%
+%% @see c_bitstr/5
+
+-spec bitstr_flags(c_bitstr()) -> cerl().
+
+bitstr_flags(Node) ->
+ Node#c_bitstr.flags.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_fun(Variables::[c_var()], Body::cerl()) -> c_fun()
+%%
+%% @doc Creates an abstract fun-expression. If <code>Variables</code>
+%% is <code>[V1, ..., Vn]</code>, the result represents "<code>fun
+%% (<em>V1</em>, ..., <em>Vn</em>) -> <em>Body</em></code>". All the
+%% <code>Vi</code> must have type <code>var</code>.
+%%
+%% @see ann_c_fun/3
+%% @see update_c_fun/3
+%% @see is_c_fun/1
+%% @see fun_vars/1
+%% @see fun_body/1
+%% @see fun_arity/1
+
+-spec c_fun([c_var()], cerl()) -> c_fun().
+
+c_fun(Variables, Body) ->
+ #c_fun{vars = Variables, body = Body}.
+
+
+%% @spec ann_c_fun(As::anns(), Variables::[c_var()], Body::cerl()) ->
+%% c_fun()
+%% @see c_fun/2
+
+-spec ann_c_fun(anns(), [c_var()], cerl()) -> c_fun().
+
+ann_c_fun(As, Variables, Body) ->
+ #c_fun{vars = Variables, body = Body, anno = As}.
+
+
+%% @spec update_c_fun(Old::c_fun(), Variables::[c_var()],
+%% Body::cerl()) -> c_fun()
+%% @see c_fun/2
+
+-spec update_c_fun(c_fun(), [c_var()], cerl()) -> c_fun().
+
+update_c_fun(Node, Variables, Body) ->
+ #c_fun{vars = Variables, body = Body, anno = get_ann(Node)}.
+
+
+%% @spec is_c_fun(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% fun-expression, otherwise <code>false</code>.
+%%
+%% @see c_fun/2
+
+-spec is_c_fun(cerl()) -> boolean().
+
+is_c_fun(#c_fun{}) ->
+ true; % Now this is fun!
+is_c_fun(_) ->
+ false.
+
+
+%% @spec fun_vars(c_fun()) -> [c_var()]
+%%
+%% @doc Returns the list of parameter subtrees of an abstract
+%% fun-expression.
+%%
+%% @see c_fun/2
+%% @see fun_arity/1
+
+-spec fun_vars(c_fun()) -> [c_var()].
+
+fun_vars(Node) ->
+ Node#c_fun.vars.
+
+
+%% @spec fun_body(c_fun()) -> cerl()
+%%
+%% @doc Returns the body subtree of an abstract fun-expression.
+%%
+%% @see c_fun/2
+
+-spec fun_body(c_fun()) -> cerl().
+
+fun_body(Node) ->
+ Node#c_fun.body.
+
+
+%% @spec fun_arity(Node::c_fun()) -> arity()
+%%
+%% @doc Returns the number of parameter subtrees of an abstract
+%% fun-expression.
+%%
+%% <p>Note: this is equivalent to <code>length(fun_vars(Node))</code>,
+%% but potentially more efficient.</p>
+%%
+%% @see c_fun/2
+%% @see fun_vars/1
+
+-spec fun_arity(c_fun()) -> arity().
+
+fun_arity(Node) ->
+ length(fun_vars(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_seq(Argument::cerl(), Body::cerl()) -> c_seq()
+%%
+%% @doc Creates an abstract sequencing expression. The result
+%% represents "<code>do <em>Argument</em> <em>Body</em></code>".
+%%
+%% @see ann_c_seq/3
+%% @see update_c_seq/3
+%% @see is_c_seq/1
+%% @see seq_arg/1
+%% @see seq_body/1
+
+-spec c_seq(cerl(), cerl()) -> c_seq().
+
+c_seq(Argument, Body) ->
+ #c_seq{arg = Argument, body = Body}.
+
+
+%% @spec ann_c_seq(As::anns(), Argument::cerl(), Body::cerl()) -> c_seq()
+%%
+%% @see c_seq/2
+
+-spec ann_c_seq(anns(), cerl(), cerl()) -> c_seq().
+
+ann_c_seq(As, Argument, Body) ->
+ #c_seq{arg = Argument, body = Body, anno = As}.
+
+
+%% @spec update_c_seq(Old::c_seq(), Argument::cerl(), Body::cerl()) ->
+%% c_seq()
+%% @see c_seq/2
+
+-spec update_c_seq(c_seq(), cerl(), cerl()) -> c_seq().
+
+update_c_seq(Node, Argument, Body) ->
+ #c_seq{arg = Argument, body = Body, anno = get_ann(Node)}.
+
+
+%% @spec is_c_seq(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% sequencing expression, otherwise <code>false</code>.
+%%
+%% @see c_seq/2
+
+-spec is_c_seq(cerl()) -> boolean().
+
+is_c_seq(#c_seq{}) ->
+ true;
+is_c_seq(_) ->
+ false.
+
+
+%% @spec seq_arg(c_seq()) -> cerl()
+%%
+%% @doc Returns the argument subtree of an abstract sequencing
+%% expression.
+%%
+%% @see c_seq/2
+
+-spec seq_arg(c_seq()) -> cerl().
+
+seq_arg(Node) ->
+ Node#c_seq.arg.
+
+
+%% @spec seq_body(c_seq()) -> cerl()
+%%
+%% @doc Returns the body subtree of an abstract sequencing expression.
+%%
+%% @see c_seq/2
+
+-spec seq_body(c_seq()) -> cerl().
+
+seq_body(Node) ->
+ Node#c_seq.body.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_let(Variables::[c_var()], Argument::cerl(), Body::cerl()) ->
+%% c_let()
+%%
+%% @doc Creates an abstract let-expression. If <code>Variables</code>
+%% is <code>[V1, ..., Vn]</code>, the result represents "<code>let
+%% &lt;<em>V1</em>, ..., <em>Vn</em>&gt; = <em>Argument</em> in
+%% <em>Body</em></code>". All the <code>Vi</code> must have type
+%% <code>var</code>.
+%%
+%% @see ann_c_let/4
+%% @see update_c_let/4
+%% @see is_c_let/1
+%% @see let_vars/1
+%% @see let_arg/1
+%% @see let_body/1
+%% @see let_arity/1
+
+-spec c_let([c_var()], cerl(), cerl()) -> c_let().
+
+c_let(Variables, Argument, Body) ->
+ #c_let{vars = Variables, arg = Argument, body = Body}.
+
+
+%% ann_c_let(As, Variables, Argument, Body) -> c_let()
+%% @see c_let/3
+
+-spec ann_c_let(anns(), [c_var()], cerl(), cerl()) -> c_let().
+
+ann_c_let(As, Variables, Argument, Body) ->
+ #c_let{vars = Variables, arg = Argument, body = Body, anno = As}.
+
+
+%% update_c_let(Old, Variables, Argument, Body) -> c_let()
+%% @see c_let/3
+
+-spec update_c_let(c_let(), [c_var()], cerl(), cerl()) -> c_let().
+
+update_c_let(Node, Variables, Argument, Body) ->
+ #c_let{vars = Variables, arg = Argument, body = Body,
+ anno = get_ann(Node)}.
+
+
+%% @spec is_c_let(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% let-expression, otherwise <code>false</code>.
+%%
+%% @see c_let/3
+
+-spec is_c_let(cerl()) -> boolean().
+
+is_c_let(#c_let{}) ->
+ true;
+is_c_let(_) ->
+ false.
+
+
+%% @spec let_vars(c_let()) -> [c_var()]
+%%
+%% @doc Returns the list of left-hand side variables of an abstract
+%% let-expression.
+%%
+%% @see c_let/3
+%% @see let_arity/1
+
+-spec let_vars(c_let()) -> [c_var()].
+
+let_vars(Node) ->
+ Node#c_let.vars.
+
+
+%% @spec let_arg(c_let()) -> cerl()
+%%
+%% @doc Returns the argument subtree of an abstract let-expression.
+%%
+%% @see c_let/3
+
+-spec let_arg(c_let()) -> cerl().
+
+let_arg(Node) ->
+ Node#c_let.arg.
+
+
+%% @spec let_body(c_let()) -> cerl()
+%%
+%% @doc Returns the body subtree of an abstract let-expression.
+%%
+%% @see c_let/3
+
+-spec let_body(c_let()) -> cerl().
+
+let_body(Node) ->
+ Node#c_let.body.
+
+
+%% @spec let_arity(Node::c_let()) -> non_neg_integer()
+%%
+%% @doc Returns the number of left-hand side variables of an abstract
+%% let-expression.
+%%
+%% <p>Note: this is equivalent to <code>length(let_vars(Node))</code>,
+%% but potentially more efficient.</p>
+%%
+%% @see c_let/3
+%% @see let_vars/1
+
+-spec let_arity(c_let()) -> non_neg_integer().
+
+let_arity(Node) ->
+ length(let_vars(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_letrec(Definitions::defs(), Body::cerl()) -> c_letrec()
+%%
+%% @doc Creates an abstract letrec-expression. If
+%% <code>Definitions</code> is <code>[{V1, F1}, ..., {Vn, Fn}]</code>,
+%% the result represents "<code>letrec <em>V1</em> = <em>F1</em>
+%% ... <em>Vn</em> = <em>Fn</em> in <em>Body</em></code>. All the
+%% <code>Vi</code> must have type <code>var</code> and represent
+%% function names. All the <code>Fi</code> must have type
+%% <code>'fun'</code>.
+%%
+%% @see ann_c_letrec/3
+%% @see update_c_letrec/3
+%% @see is_c_letrec/1
+%% @see letrec_defs/1
+%% @see letrec_body/1
+%% @see letrec_vars/1
+
+-spec c_letrec(defs(), cerl()) -> c_letrec().
+
+c_letrec(Defs, Body) ->
+ #c_letrec{defs = Defs, body = Body}.
+
+
+%% @spec ann_c_letrec(As::anns(), Definitions::defs(),
+%% Body::cerl()) -> c_letrec()
+%% @see c_letrec/2
+
+-spec ann_c_letrec(anns(), defs(), cerl()) -> c_letrec().
+
+ann_c_letrec(As, Defs, Body) ->
+ #c_letrec{defs = Defs, body = Body, anno = As}.
+
+
+%% @spec update_c_letrec(Old::c_letrec(), Definitions::defs(),
+%% Body::cerl()) -> c_letrec()
+%% @see c_letrec/2
+
+-spec update_c_letrec(c_letrec(), defs(), cerl()) -> c_letrec().
+
+update_c_letrec(Node, Defs, Body) ->
+ #c_letrec{defs = Defs, body = Body, anno = get_ann(Node)}.
+
+
+%% @spec is_c_letrec(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% letrec-expression, otherwise <code>false</code>.
+%%
+%% @see c_letrec/2
+
+-spec is_c_letrec(cerl()) -> boolean().
+
+is_c_letrec(#c_letrec{}) ->
+ true;
+is_c_letrec(_) ->
+ false.
+
+
+%% @spec letrec_defs(Node::c_letrec()) -> defs()
+%%
+%% @doc Returns the list of definitions of an abstract
+%% letrec-expression. If <code>Node</code> represents "<code>letrec
+%% <em>V1</em> = <em>F1</em> ... <em>Vn</em> = <em>Fn</em> in
+%% <em>Body</em></code>", the returned value is <code>[{V1, F1}, ...,
+%% {Vn, Fn}]</code>.
+%%
+%% @see c_letrec/2
+
+-spec letrec_defs(c_letrec()) -> defs().
+
+letrec_defs(Node) ->
+ Node#c_letrec.defs.
+
+
+%% @spec letrec_body(c_letrec()) -> cerl()
+%%
+%% @doc Returns the body subtree of an abstract letrec-expression.
+%%
+%% @see c_letrec/2
+
+-spec letrec_body(c_letrec()) -> cerl().
+
+letrec_body(Node) ->
+ Node#c_letrec.body.
+
+
+%% @spec letrec_vars(c_letrec()) -> [cerl()]
+%%
+%% @doc Returns the list of left-hand side function variable subtrees
+%% of a letrec-expression. If <code>Node</code> represents
+%% "<code>letrec <em>V1</em> = <em>F1</em> ... <em>Vn</em> =
+%% <em>Fn</em> in <em>Body</em></code>", the returned value is
+%% <code>[V1, ..., Vn]</code>.
+%%
+%% @see c_letrec/2
+
+-spec letrec_vars(c_letrec()) -> [cerl()].
+
+letrec_vars(Node) ->
+ [F || {F, _} <- letrec_defs(Node)].
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_case(Argument::cerl(), Clauses::[cerl()]) -> c_case()
+%%
+%% @doc Creates an abstract case-expression. If <code>Clauses</code>
+%% is <code>[C1, ..., Cn]</code>, the result represents "<code>case
+%% <em>Argument</em> of <em>C1</em> ... <em>Cn</em>
+%% end</code>". <code>Clauses</code> must not be empty.
+%%
+%% @see ann_c_case/3
+%% @see update_c_case/3
+%% @see is_c_case/1
+%% @see c_clause/3
+%% @see case_arg/1
+%% @see case_clauses/1
+%% @see case_arity/1
+
+-spec c_case(cerl(), [cerl()]) -> c_case().
+
+c_case(Expr, Clauses) ->
+ #c_case{arg = Expr, clauses = Clauses}.
+
+
+%% @spec ann_c_case(As::anns(), Argument::cerl(),
+%% Clauses::[cerl()]) -> c_case()
+%% @see c_case/2
+
+-spec ann_c_case(anns(), cerl(), [cerl()]) -> c_case().
+
+ann_c_case(As, Expr, Clauses) ->
+ #c_case{arg = Expr, clauses = Clauses, anno = As}.
+
+
+%% @spec update_c_case(Old::cerl(), Argument::cerl(),
+%% Clauses::[cerl()]) -> c_case()
+%% @see c_case/2
+
+-spec update_c_case(c_case(), cerl(), [cerl()]) -> c_case().
+
+update_c_case(Node, Expr, Clauses) ->
+ #c_case{arg = Expr, clauses = Clauses, anno = get_ann(Node)}.
+
+
+%% is_c_case(Node) -> boolean()
+%%
+%% Node = cerl()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% case-expression; otherwise <code>false</code>.
+%%
+%% @see c_case/2
+
+-spec is_c_case(cerl()) -> boolean().
+
+is_c_case(#c_case{}) ->
+ true;
+is_c_case(_) ->
+ false.
+
+
+%% @spec case_arg(c_case()) -> cerl()
+%%
+%% @doc Returns the argument subtree of an abstract case-expression.
+%%
+%% @see c_case/2
+
+-spec case_arg(c_case()) -> cerl().
+
+case_arg(Node) ->
+ Node#c_case.arg.
+
+
+%% @spec case_clauses(c_case()) -> [cerl()]
+%%
+%% @doc Returns the list of clause subtrees of an abstract
+%% case-expression.
+%%
+%% @see c_case/2
+%% @see case_arity/1
+
+-spec case_clauses(c_case()) -> [cerl()].
+
+case_clauses(Node) ->
+ Node#c_case.clauses.
+
+
+%% @spec case_arity(Node::c_case()) -> non_neg_integer()
+%%
+%% @doc Equivalent to
+%% <code>clause_arity(hd(case_clauses(Node)))</code>, but potentially
+%% more efficient.
+%%
+%% @see c_case/2
+%% @see case_clauses/1
+%% @see clause_arity/1
+
+-spec case_arity(c_case()) -> non_neg_integer().
+
+case_arity(Node) ->
+ clause_arity(hd(case_clauses(Node))).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_clause(Patterns::[cerl()], Body::cerl()) -> c_clause()
+%% @equiv c_clause(Patterns, c_atom(true), Body)
+%% @see c_atom/1
+
+-spec c_clause([cerl()], cerl()) -> c_clause().
+
+c_clause(Patterns, Body) ->
+ c_clause(Patterns, c_atom(true), Body).
+
+
+%% @spec c_clause(Patterns::[cerl()], Guard::cerl(), Body::cerl()) ->
+%% c_clause()
+%%
+%% @doc Creates an an abstract clause. If <code>Patterns</code> is
+%% <code>[P1, ..., Pn]</code>, the result represents
+%% "<code>&lt;<em>P1</em>, ..., <em>Pn</em>&gt; when <em>Guard</em> ->
+%% <em>Body</em></code>".
+%%
+%% @see c_clause/2
+%% @see ann_c_clause/4
+%% @see update_c_clause/4
+%% @see is_c_clause/1
+%% @see c_case/2
+%% @see c_receive/3
+%% @see clause_pats/1
+%% @see clause_guard/1
+%% @see clause_body/1
+%% @see clause_arity/1
+%% @see clause_vars/1
+
+-spec c_clause([cerl()], cerl(), cerl()) -> c_clause().
+
+c_clause(Patterns, Guard, Body) ->
+ #c_clause{pats = Patterns, guard = Guard, body = Body}.
+
+
+%% @spec ann_c_clause(As::anns(), Patterns::[cerl()],
+%% Body::cerl()) -> c_clause()
+%% @equiv ann_c_clause(As, Patterns, c_atom(true), Body)
+%% @see c_clause/3
+
+-spec ann_c_clause(anns(), [cerl()], cerl()) -> c_clause().
+
+ann_c_clause(As, Patterns, Body) ->
+ ann_c_clause(As, Patterns, c_atom(true), Body).
+
+
+%% @spec ann_c_clause(As::anns(), Patterns::[cerl()], Guard::cerl(),
+%% Body::cerl()) -> c_clause()
+%% @see ann_c_clause/3
+%% @see c_clause/3
+
+-spec ann_c_clause(anns(), [cerl()], cerl(), cerl()) -> c_clause().
+
+ann_c_clause(As, Patterns, Guard, Body) ->
+ #c_clause{pats = Patterns, guard = Guard, body = Body, anno = As}.
+
+
+%% @spec update_c_clause(Old::c_clause(), Patterns::[cerl()],
+%% Guard::cerl(), Body::cerl()) -> c_clause()
+%% @see c_clause/3
+
+-spec update_c_clause(c_clause(), [cerl()], cerl(), cerl()) -> c_clause().
+
+update_c_clause(Node, Patterns, Guard, Body) ->
+ #c_clause{pats = Patterns, guard = Guard, body = Body,
+ anno = get_ann(Node)}.
+
+
+%% @spec is_c_clause(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% clause, otherwise <code>false</code>.
+%%
+%% @see c_clause/3
+
+-spec is_c_clause(cerl()) -> boolean().
+
+is_c_clause(#c_clause{}) ->
+ true;
+is_c_clause(_) ->
+ false.
+
+
+%% @spec clause_pats(c_clause()) -> [cerl()]
+%%
+%% @doc Returns the list of pattern subtrees of an abstract clause.
+%%
+%% @see c_clause/3
+%% @see clause_arity/1
+
+-spec clause_pats(c_clause()) -> [cerl()].
+
+clause_pats(Node) ->
+ Node#c_clause.pats.
+
+
+%% @spec clause_guard(c_clause()) -> cerl()
+%%
+%% @doc Returns the guard subtree of an abstract clause.
+%%
+%% @see c_clause/3
+
+-spec clause_guard(c_clause()) -> cerl().
+
+clause_guard(Node) ->
+ Node#c_clause.guard.
+
+
+%% @spec clause_body(c_clause()) -> cerl()
+%%
+%% @doc Returns the body subtree of an abstract clause.
+%%
+%% @see c_clause/3
+
+-spec clause_body(c_clause()) -> cerl().
+
+clause_body(Node) ->
+ Node#c_clause.body.
+
+
+%% @spec clause_arity(Node::c_clause()) -> non_neg_integer()
+%%
+%% @doc Returns the number of pattern subtrees of an abstract clause.
+%%
+%% <p>Note: this is equivalent to
+%% <code>length(clause_pats(Node))</code>, but potentially more
+%% efficient.</p>
+%%
+%% @see c_clause/3
+%% @see clause_pats/1
+
+-spec clause_arity(c_clause()) -> non_neg_integer().
+
+clause_arity(Node) ->
+ length(clause_pats(Node)).
+
+
+%% @spec clause_vars(c_clause()) -> [cerl()]
+%%
+%% @doc Returns the list of all abstract variables in the patterns of
+%% an abstract clause. The order of listing is not defined.
+%%
+%% @see c_clause/3
+%% @see pat_list_vars/1
+
+-spec clause_vars(c_clause()) -> [cerl()].
+
+clause_vars(Clause) ->
+ pat_list_vars(clause_pats(Clause)).
+
+
+%% @spec pat_vars(Pattern::cerl()) -> [cerl()]
+%%
+%% @doc Returns the list of all abstract variables in a pattern. An
+%% exception is thrown if <code>Node</code> does not represent a
+%% well-formed Core Erlang clause pattern. The order of listing is not
+%% defined.
+%%
+%% @see pat_list_vars/1
+%% @see clause_vars/1
+
+-spec pat_vars(cerl()) -> [cerl()].
+
+pat_vars(Node) ->
+ pat_vars(Node, []).
+
+pat_vars(Node, Vs) ->
+ case type(Node) of
+ var ->
+ [Node | Vs];
+ literal ->
+ Vs;
+ cons ->
+ pat_vars(cons_hd(Node), pat_vars(cons_tl(Node), Vs));
+ tuple ->
+ pat_list_vars(tuple_es(Node), Vs);
+ map ->
+ pat_list_vars(map_es(Node), Vs);
+ map_pair ->
+ %% map_pair_key is not a pattern var, excluded
+ pat_list_vars([map_pair_op(Node),map_pair_val(Node)],Vs);
+ binary ->
+ pat_list_vars(binary_segments(Node), Vs);
+ bitstr ->
+ %% bitstr_size is not a pattern var, excluded
+ pat_vars(bitstr_val(Node), Vs);
+ alias ->
+ pat_vars(alias_pat(Node), [alias_var(Node) | Vs])
+ end.
+
+
+%% @spec pat_list_vars(Patterns::[cerl()]) -> [cerl()]
+%%
+%% @doc Returns the list of all abstract variables in the given
+%% patterns. An exception is thrown if some element in
+%% <code>Patterns</code> does not represent a well-formed Core Erlang
+%% clause pattern. The order of listing is not defined.
+%%
+%% @see pat_vars/1
+%% @see clause_vars/1
+
+-spec pat_list_vars([cerl()]) -> [cerl()].
+
+pat_list_vars(Ps) ->
+ pat_list_vars(Ps, []).
+
+pat_list_vars([P | Ps], Vs) ->
+ pat_list_vars(Ps, pat_vars(P, Vs));
+pat_list_vars([], Vs) ->
+ Vs.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_alias(Variable::c_var(), Pattern::cerl()) -> c_alias()
+%%
+%% @doc Creates an abstract pattern alias. The result represents
+%% "<code><em>Variable</em> = <em>Pattern</em></code>".
+%%
+%% @see ann_c_alias/3
+%% @see update_c_alias/3
+%% @see is_c_alias/1
+%% @see alias_var/1
+%% @see alias_pat/1
+%% @see c_clause/3
+
+-spec c_alias(c_var(), cerl()) -> c_alias().
+
+c_alias(Var, Pattern) ->
+ #c_alias{var = Var, pat = Pattern}.
+
+
+%% @spec ann_c_alias(As::anns(), Variable::c_var(),
+%% Pattern::cerl()) -> c_alias()
+%% @see c_alias/2
+
+-spec ann_c_alias(anns(), c_var(), cerl()) -> c_alias().
+
+ann_c_alias(As, Var, Pattern) ->
+ #c_alias{var = Var, pat = Pattern, anno = As}.
+
+
+%% @spec update_c_alias(Old::cerl(), Variable::c_var(),
+%% Pattern::cerl()) -> c_alias()
+%% @see c_alias/2
+
+-spec update_c_alias(c_alias(), c_var(), cerl()) -> c_alias().
+
+update_c_alias(Node, Var, Pattern) ->
+ #c_alias{var = Var, pat = Pattern, anno = get_ann(Node)}.
+
+
+%% @spec is_c_alias(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% pattern alias, otherwise <code>false</code>.
+%%
+%% @see c_alias/2
+
+-spec is_c_alias(cerl()) -> boolean().
+
+is_c_alias(#c_alias{}) ->
+ true;
+is_c_alias(_) ->
+ false.
+
+
+%% @spec alias_var(c_alias()) -> c_var()
+%%
+%% @doc Returns the variable subtree of an abstract pattern alias.
+%%
+%% @see c_alias/2
+
+-spec alias_var(c_alias()) -> c_var().
+
+alias_var(Node) ->
+ Node#c_alias.var.
+
+
+%% @spec alias_pat(c_alias()) -> cerl()
+%%
+%% @doc Returns the pattern subtree of an abstract pattern alias.
+%%
+%% @see c_alias/2
+
+-spec alias_pat(c_alias()) -> cerl().
+
+alias_pat(Node) ->
+ Node#c_alias.pat.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_receive(Clauses::[cerl()]) -> c_receive()
+%% @equiv c_receive(Clauses, c_atom(infinity), c_atom(true))
+%% @see c_atom/1
+
+-spec c_receive([cerl()]) -> c_receive().
+
+c_receive(Clauses) ->
+ c_receive(Clauses, c_atom(infinity), c_atom(true)).
+
+
+%% @spec c_receive(Clauses::[cerl()], Timeout::cerl(),
+%% Action::cerl()) -> c_receive()
+%%
+%% @doc Creates an abstract receive-expression. If
+%% <code>Clauses</code> is <code>[C1, ..., Cn]</code>, the result
+%% represents "<code>receive <em>C1</em> ... <em>Cn</em> after
+%% <em>Timeout</em> -> <em>Action</em> end</code>".
+%%
+%% @see c_receive/1
+%% @see ann_c_receive/4
+%% @see update_c_receive/4
+%% @see is_c_receive/1
+%% @see receive_clauses/1
+%% @see receive_timeout/1
+%% @see receive_action/1
+
+-spec c_receive([cerl()], cerl(), cerl()) -> c_receive().
+
+c_receive(Clauses, Timeout, Action) ->
+ #c_receive{clauses = Clauses, timeout = Timeout, action = Action}.
+
+
+%% @spec ann_c_receive(As::anns(), Clauses::[cerl()]) -> c_receive()
+%% @equiv ann_c_receive(As, Clauses, c_atom(infinity), c_atom(true))
+%% @see c_receive/3
+%% @see c_atom/1
+
+-spec ann_c_receive(anns(), [cerl()]) -> c_receive().
+
+ann_c_receive(As, Clauses) ->
+ ann_c_receive(As, Clauses, c_atom(infinity), c_atom(true)).
+
+
+%% @spec ann_c_receive(As::anns(), Clauses::[cerl()],
+%% Timeout::cerl(), Action::cerl()) -> c_receive()
+%% @see ann_c_receive/2
+%% @see c_receive/3
+
+-spec ann_c_receive(anns(), [cerl()], cerl(), cerl()) -> c_receive().
+
+ann_c_receive(As, Clauses, Timeout, Action) ->
+ #c_receive{clauses = Clauses, timeout = Timeout, action = Action,
+ anno = As}.
+
+
+%% @spec update_c_receive(Old::cerl(), Clauses::[cerl()],
+%% Timeout::cerl(), Action::cerl()) -> c_receive()
+%% @see c_receive/3
+
+-spec update_c_receive(c_receive(), [cerl()], cerl(), cerl()) -> c_receive().
+
+update_c_receive(Node, Clauses, Timeout, Action) ->
+ #c_receive{clauses = Clauses, timeout = Timeout, action = Action,
+ anno = get_ann(Node)}.
+
+
+%% @spec is_c_receive(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% receive-expression, otherwise <code>false</code>.
+%%
+%% @see c_receive/3
+
+-spec is_c_receive(cerl()) -> boolean().
+
+is_c_receive(#c_receive{}) ->
+ true;
+is_c_receive(_) ->
+ false.
+
+
+%% @spec receive_clauses(c_receive()) -> [cerl()]
+%%
+%% @doc Returns the list of clause subtrees of an abstract
+%% receive-expression.
+%%
+%% @see c_receive/3
+
+-spec receive_clauses(c_receive()) -> [cerl()].
+
+receive_clauses(Node) ->
+ Node#c_receive.clauses.
+
+
+%% @spec receive_timeout(c_receive()) -> cerl()
+%%
+%% @doc Returns the timeout subtree of an abstract receive-expression.
+%%
+%% @see c_receive/3
+
+-spec receive_timeout(c_receive()) -> cerl().
+
+receive_timeout(Node) ->
+ Node#c_receive.timeout.
+
+
+%% @spec receive_action(c_receive()) -> cerl()
+%%
+%% @doc Returns the action subtree of an abstract receive-expression.
+%%
+%% @see c_receive/3
+
+-spec receive_action(c_receive()) -> cerl().
+
+receive_action(Node) ->
+ Node#c_receive.action.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_apply(Operator::c_var(), Arguments::[cerl()]) -> c_apply()
+%%
+%% @doc Creates an abstract function application. If
+%% <code>Arguments</code> is <code>[A1, ..., An]</code>, the result
+%% represents "<code>apply <em>Operator</em>(<em>A1</em>, ...,
+%% <em>An</em>)</code>".
+%%
+%% @see ann_c_apply/3
+%% @see update_c_apply/3
+%% @see is_c_apply/1
+%% @see apply_op/1
+%% @see apply_args/1
+%% @see apply_arity/1
+%% @see c_call/3
+%% @see c_primop/2
+
+-spec c_apply(c_var(), [cerl()]) -> c_apply().
+
+c_apply(Operator, Arguments) ->
+ #c_apply{op = Operator, args = Arguments}.
+
+
+%% @spec ann_c_apply(As::anns(), Operator::c_var(),
+%% Arguments::[cerl()]) -> c_apply()
+%% @see c_apply/2
+
+-spec ann_c_apply(anns(), c_var(), [cerl()]) -> c_apply().
+
+ann_c_apply(As, Operator, Arguments) ->
+ #c_apply{op = Operator, args = Arguments, anno = As}.
+
+
+%% @spec update_c_apply(Old::c_apply(), Operator::cerl(),
+%% Arguments::[cerl()]) -> c_apply()
+%% @see c_apply/2
+
+-spec update_c_apply(c_apply(), c_var(), [cerl()]) -> c_apply().
+
+update_c_apply(Node, Operator, Arguments) ->
+ #c_apply{op = Operator, args = Arguments, anno = get_ann(Node)}.
+
+
+%% @spec is_c_apply(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% function application, otherwise <code>false</code>.
+%%
+%% @see c_apply/2
+
+-spec is_c_apply(cerl()) -> boolean().
+
+is_c_apply(#c_apply{}) ->
+ true;
+is_c_apply(_) ->
+ false.
+
+
+%% @spec apply_op(c_apply()) -> c_var()
+%%
+%% @doc Returns the operator subtree of an abstract function
+%% application.
+%%
+%% @see c_apply/2
+
+-spec apply_op(c_apply()) -> c_var().
+
+apply_op(Node) ->
+ Node#c_apply.op.
+
+
+%% @spec apply_args(c_apply()) -> [cerl()]
+%%
+%% @doc Returns the list of argument subtrees of an abstract function
+%% application.
+%%
+%% @see c_apply/2
+%% @see apply_arity/1
+
+-spec apply_args(c_apply()) -> [cerl()].
+
+apply_args(Node) ->
+ Node#c_apply.args.
+
+
+%% @spec apply_arity(Node::c_apply()) -> arity()
+%%
+%% @doc Returns the number of argument subtrees of an abstract
+%% function application.
+%%
+%% <p>Note: this is equivalent to
+%% <code>length(apply_args(Node))</code>, but potentially more
+%% efficient.</p>
+%%
+%% @see c_apply/2
+%% @see apply_args/1
+
+-spec apply_arity(c_apply()) -> arity().
+
+apply_arity(Node) ->
+ length(apply_args(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_call(Module::cerl(), Name::cerl(), Arguments::[cerl()]) ->
+%% c_call()
+%%
+%% @doc Creates an abstract inter-module call. If
+%% <code>Arguments</code> is <code>[A1, ..., An]</code>, the result
+%% represents "<code>call <em>Module</em>:<em>Name</em>(<em>A1</em>,
+%% ..., <em>An</em>)</code>".
+%%
+%% @see ann_c_call/4
+%% @see update_c_call/4
+%% @see is_c_call/1
+%% @see call_module/1
+%% @see call_name/1
+%% @see call_args/1
+%% @see call_arity/1
+%% @see c_apply/2
+%% @see c_primop/2
+
+-spec c_call(cerl(), cerl(), [cerl()]) -> c_call().
+
+c_call(Module, Name, Arguments) ->
+ #c_call{module = Module, name = Name, args = Arguments}.
+
+
+%% @spec ann_c_call(As::anns(), Module::cerl(), Name::cerl(),
+%% Arguments::[cerl()]) -> c_call()
+%% @see c_call/3
+
+-spec ann_c_call(anns(), cerl(), cerl(), [cerl()]) -> c_call().
+
+ann_c_call(As, Module, Name, Arguments) ->
+ #c_call{module = Module, name = Name, args = Arguments, anno = As}.
+
+
+%% @spec update_c_call(Old::cerl(), Module::cerl(), Name::cerl(),
+%% Arguments::[cerl()]) -> c_call()
+%% @see c_call/3
+
+-spec update_c_call(cerl(), cerl(), cerl(), [cerl()]) -> c_call().
+
+update_c_call(Node, Module, Name, Arguments) ->
+ #c_call{module = Module, name = Name, args = Arguments,
+ anno = get_ann(Node)}.
+
+
+%% @spec is_c_call(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% inter-module call expression; otherwise <code>false</code>.
+%%
+%% @see c_call/3
+
+-spec is_c_call(cerl()) -> boolean().
+
+is_c_call(#c_call{}) ->
+ true;
+is_c_call(_) ->
+ false.
+
+
+%% @spec call_module(c_call()) -> cerl()
+%%
+%% @doc Returns the module subtree of an abstract inter-module call.
+%%
+%% @see c_call/3
+
+-spec call_module(c_call()) -> cerl().
+
+call_module(Node) ->
+ Node#c_call.module.
+
+
+%% @spec call_name(c_call()) -> cerl()
+%%
+%% @doc Returns the name subtree of an abstract inter-module call.
+%%
+%% @see c_call/3
+
+-spec call_name(c_call()) -> cerl().
+
+call_name(Node) ->
+ Node#c_call.name.
+
+
+%% @spec call_args(c_call()) -> [cerl()]
+%%
+%% @doc Returns the list of argument subtrees of an abstract
+%% inter-module call.
+%%
+%% @see c_call/3
+%% @see call_arity/1
+
+-spec call_args(c_call()) -> [cerl()].
+
+call_args(Node) ->
+ Node#c_call.args.
+
+
+%% @spec call_arity(Node::c_call()) -> arity()
+%%
+%% @doc Returns the number of argument subtrees of an abstract
+%% inter-module call.
+%%
+%% <p>Note: this is equivalent to
+%% <code>length(call_args(Node))</code>, but potentially more
+%% efficient.</p>
+%%
+%% @see c_call/3
+%% @see call_args/1
+
+-spec call_arity(c_call()) -> arity().
+
+call_arity(Node) ->
+ length(call_args(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_primop(Name::c_literal(), Arguments::[cerl()]) -> c_primop()
+%%
+%% @doc Creates an abstract primitive operation call. If
+%% <code>Arguments</code> is <code>[A1, ..., An]</code>, the result
+%% represents "<code>primop <em>Name</em>(<em>A1</em>, ...,
+%% <em>An</em>)</code>". <code>Name</code> must be an atom literal.
+%%
+%% @see ann_c_primop/3
+%% @see update_c_primop/3
+%% @see is_c_primop/1
+%% @see primop_name/1
+%% @see primop_args/1
+%% @see primop_arity/1
+%% @see c_apply/2
+%% @see c_call/3
+
+-spec c_primop(c_literal(), [cerl()]) -> c_primop().
+
+c_primop(Name, Arguments) ->
+ #c_primop{name = Name, args = Arguments}.
+
+
+%% @spec ann_c_primop(As::anns(), Name::c_literal(),
+%% Arguments::[cerl()]) -> c_primop()
+%% @see c_primop/2
+
+-spec ann_c_primop(anns(), c_literal(), [cerl()]) -> c_primop().
+
+ann_c_primop(As, Name, Arguments) ->
+ #c_primop{name = Name, args = Arguments, anno = As}.
+
+
+%% @spec update_c_primop(Old::cerl(), Name::c_literal(),
+%% Arguments::[cerl()]) -> c_primop()
+%% @see c_primop/2
+
+-spec update_c_primop(cerl(), c_literal(), [cerl()]) -> c_primop().
+
+update_c_primop(Node, Name, Arguments) ->
+ #c_primop{name = Name, args = Arguments, anno = get_ann(Node)}.
+
+
+%% @spec is_c_primop(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% primitive operation call, otherwise <code>false</code>.
+%%
+%% @see c_primop/2
+
+-spec is_c_primop(cerl()) -> boolean().
+
+is_c_primop(#c_primop{}) ->
+ true;
+is_c_primop(_) ->
+ false.
+
+
+%% @spec primop_name(c_primop()) -> c_literal()
+%%
+%% @doc Returns the name subtree of an abstract primitive operation
+%% call.
+%%
+%% @see c_primop/2
+
+-spec primop_name(c_primop()) -> c_literal().
+
+primop_name(Node) ->
+ Node#c_primop.name.
+
+
+%% @spec primop_args(c_primop()) -> [cerl()]
+%%
+%% @doc Returns the list of argument subtrees of an abstract primitive
+%% operation call.
+%%
+%% @see c_primop/2
+%% @see primop_arity/1
+
+-spec primop_args(c_primop()) -> [cerl()].
+
+primop_args(Node) ->
+ Node#c_primop.args.
+
+
+%% @spec primop_arity(Node::c_primop()) -> arity()
+%%
+%% @doc Returns the number of argument subtrees of an abstract
+%% primitive operation call.
+%%
+%% <p>Note: this is equivalent to
+%% <code>length(primop_args(Node))</code>, but potentially more
+%% efficient.</p>
+%%
+%% @see c_primop/2
+%% @see primop_args/1
+
+-spec primop_arity(c_primop()) -> arity().
+
+primop_arity(Node) ->
+ length(primop_args(Node)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_try(Argument::cerl(), Variables::[c_var()], Body::cerl(),
+%% ExceptionVars::[c_var()], Handler::cerl()) -> c_try()
+%%
+%% @doc Creates an abstract try-expression. If <code>Variables</code> is
+%% <code>[V1, ..., Vn]</code> and <code>ExceptionVars</code> is
+%% <code>[X1, ..., Xm]</code>, the result represents "<code>try
+%% <em>Argument</em> of &lt;<em>V1</em>, ..., <em>Vn</em>&gt; ->
+%% <em>Body</em> catch &lt;<em>X1</em>, ..., <em>Xm</em>&gt; ->
+%% <em>Handler</em></code>". All the <code>Vi</code> and <code>Xi</code>
+%% must have type <code>var</code>.
+%%
+%% @see ann_c_try/6
+%% @see update_c_try/6
+%% @see is_c_try/1
+%% @see try_arg/1
+%% @see try_vars/1
+%% @see try_body/1
+%% @see c_catch/1
+
+-spec c_try(cerl(), [c_var()], cerl(), [c_var()], cerl()) -> c_try().
+
+c_try(Expr, Vs, Body, Evs, Handler) ->
+ #c_try{arg = Expr, vars = Vs, body = Body,
+ evars = Evs, handler = Handler}.
+
+
+%% @spec ann_c_try(As::[term()], Expression::cerl(),
+%% Variables::[c_var()], Body::cerl(),
+%% EVars::[c_var()], Handler::cerl()) -> c_try()
+%% @see c_try/5
+
+-spec ann_c_try(anns(), cerl(), [c_var()], cerl(), [c_var()], cerl()) ->
+ c_try().
+
+ann_c_try(As, Expr, Vs, Body, Evs, Handler) ->
+ #c_try{arg = Expr, vars = Vs, body = Body,
+ evars = Evs, handler = Handler, anno = As}.
+
+
+%% @spec update_c_try(Old::c_try(), Expression::cerl(),
+%% Variables::[c_var()], Body::cerl(),
+%% EVars::[c_var()], Handler::cerl()) -> cerl()
+%% @see c_try/5
+
+-spec update_c_try(c_try(), cerl(), [c_var()], cerl(), [c_var()], cerl()) ->
+ c_try().
+
+update_c_try(Node, Expr, Vs, Body, Evs, Handler) ->
+ #c_try{arg = Expr, vars = Vs, body = Body,
+ evars = Evs, handler = Handler, anno = get_ann(Node)}.
+
+
+%% @spec is_c_try(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% try-expression, otherwise <code>false</code>.
+%%
+%% @see c_try/5
+
+-spec is_c_try(cerl()) -> boolean().
+
+is_c_try(#c_try{}) ->
+ true;
+is_c_try(_) ->
+ false.
+
+
+%% @spec try_arg(c_try()) -> cerl()
+%%
+%% @doc Returns the expression subtree of an abstract try-expression.
+%%
+%% @see c_try/5
+
+-spec try_arg(c_try()) -> cerl().
+
+try_arg(Node) ->
+ Node#c_try.arg.
+
+
+%% @spec try_vars(c_try()) -> [c_var()]
+%%
+%% @doc Returns the list of success variable subtrees of an abstract
+%% try-expression.
+%%
+%% @see c_try/5
+
+-spec try_vars(c_try()) -> [c_var()].
+
+try_vars(Node) ->
+ Node#c_try.vars.
+
+
+%% @spec try_body(c_try()) -> cerl()
+%%
+%% @doc Returns the success body subtree of an abstract try-expression.
+%%
+%% @see c_try/5
+
+-spec try_body(c_try()) -> cerl().
+
+try_body(Node) ->
+ Node#c_try.body.
+
+
+%% @spec try_evars(c_try()) -> [c_var()]
+%%
+%% @doc Returns the list of exception variable subtrees of an abstract
+%% try-expression.
+%%
+%% @see c_try/5
+
+-spec try_evars(c_try()) -> [c_var()].
+
+try_evars(Node) ->
+ Node#c_try.evars.
+
+
+%% @spec try_handler(c_try()) -> cerl()
+%%
+%% @doc Returns the exception body subtree of an abstract
+%% try-expression.
+%%
+%% @see c_try/5
+
+-spec try_handler(c_try()) -> cerl().
+
+try_handler(Node) ->
+ Node#c_try.handler.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec c_catch(Body::cerl()) -> c_catch()
+%%
+%% @doc Creates an abstract catch-expression. The result represents
+%% "<code>catch <em>Body</em></code>".
+%%
+%% <p>Note: catch-expressions can be rewritten as try-expressions, and
+%% will eventually be removed from Core Erlang.</p>
+%%
+%% @see ann_c_catch/2
+%% @see update_c_catch/2
+%% @see is_c_catch/1
+%% @see catch_body/1
+%% @see c_try/5
+
+-spec c_catch(cerl()) -> c_catch().
+
+c_catch(Body) ->
+ #c_catch{body = Body}.
+
+
+%% @spec ann_c_catch(As::anns(), Body::cerl()) -> c_catch()
+%% @see c_catch/1
+
+-spec ann_c_catch(anns(), cerl()) -> c_catch().
+
+ann_c_catch(As, Body) ->
+ #c_catch{body = Body, anno = As}.
+
+
+%% @spec update_c_catch(Old::c_catch(), Body::cerl()) -> c_catch()
+%% @see c_catch/1
+
+-spec update_c_catch(c_catch(), cerl()) -> c_catch().
+
+update_c_catch(Node, Body) ->
+ #c_catch{body = Body, anno = get_ann(Node)}.
+
+
+%% @spec is_c_catch(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
+%% catch-expression, otherwise <code>false</code>.
+%%
+%% @see c_catch/1
+
+-spec is_c_catch(cerl()) -> boolean().
+
+is_c_catch(#c_catch{}) ->
+ true;
+is_c_catch(_) ->
+ false.
+
+
+%% @spec catch_body(Node::c_catch()) -> cerl()
+%%
+%% @doc Returns the body subtree of an abstract catch-expression.
+%%
+%% @see c_catch/1
+
+-spec catch_body(c_catch()) -> cerl().
+
+catch_body(Node) ->
+ Node#c_catch.body.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec to_records(Tree::cerl()) -> record(record_types())
+%%
+%% @doc Translates an abstract syntax tree to a corresponding explicit
+%% record representation. The records are defined in the file
+%% "<code>cerl.hrl</code>".
+%%
+%% @see type/1
+%% @see from_records/1
+
+-spec to_records(cerl()) -> cerl().
+
+to_records(Node) ->
+ Node.
+
+%% @spec from_records(Tree::record(record_types())) -> cerl()
+%%
+%% record_types() = c_alias | c_apply | c_binary | c_bitstr | c_call |
+%% c_case | c_catch | c_clause | c_cons | c_fun |
+%% c_let | c_letrec | c_literal | c_map | c_map_pair |
+%% c_module | c_primop | c_receive | c_seq |
+%% c_try | c_tuple | c_values | c_var
+%%
+%% @doc Translates an explicit record representation to a
+%% corresponding abstract syntax tree. The records are defined in the
+%% file "<code>core_parse.hrl</code>".
+%%
+%% @see type/1
+%% @see to_records/1
+
+-spec from_records(cerl()) -> cerl().
+
+from_records(Node) ->
+ Node.
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec is_data(Node::cerl()) -> boolean()
+%%
+%% @doc Returns <code>true</code> if <code>Node</code> represents a
+%% data constructor, otherwise <code>false</code>. Data constructors
+%% are cons cells, tuples, and atomic literals.
+%%
+%% @see data_type/1
+%% @see data_es/1
+%% @see data_arity/1
+
+-spec is_data(cerl()) -> boolean().
+
+is_data(#c_literal{}) ->
+ true;
+is_data(#c_cons{}) ->
+ true;
+is_data(#c_tuple{}) ->
+ true;
+is_data(_) ->
+ false.
+
+
+%% @spec data_type(Node::cerl()) -> dtype()
+%%
+%% dtype() = cons | tuple | {atomic, Value}
+%% Value = integer() | float() | atom() | []
+%%
+%% @doc Returns a type descriptor for a data constructor
+%% node. (Cf. <code>is_data/1</code>.) This is mainly useful for
+%% comparing types and for constructing new nodes of the same type
+%% (cf. <code>make_data/2</code>). If <code>Node</code> represents an
+%% integer, floating-point number, atom or empty list, the result is
+%% <code>{atomic, Value}</code>, where <code>Value</code> is the value
+%% of <code>concrete(Node)</code>, otherwise the result is either
+%% <code>cons</code> or <code>tuple</code>.
+%%
+%% <p>Type descriptors can be compared for equality or order (in the
+%% Erlang term order), but remember that floating-point values should
+%% in general never be tested for equality.</p>
+%%
+%% @see is_data/1
+%% @see make_data/2
+%% @see type/1
+%% @see concrete/1
+
+-type value() :: integer() | float() | atom() | [].
+-type dtype() :: 'cons' | 'tuple' | {'atomic', value()}.
+-type c_lct() :: c_literal() | c_cons() | c_tuple().
+
+-spec data_type(c_lct()) -> dtype().
+
+data_type(#c_literal{val = V}) ->
+ case V of
+ [_ | _] ->
+ cons;
+ _ when is_tuple(V) ->
+ tuple;
+ _ ->
+ {atomic, V}
+ end;
+data_type(#c_cons{}) ->
+ cons;
+data_type(#c_tuple{}) ->
+ tuple.
+
+%% @spec data_es(Node::cerl()) -> [cerl()]
+%%
+%% @doc Returns the list of subtrees of a data constructor node. If
+%% the arity of the constructor is zero, the result is the empty list.
+%%
+%% <p>Note: if <code>data_type(Node)</code> is <code>cons</code>, the
+%% number of subtrees is exactly two. If <code>data_type(Node)</code>
+%% is <code>{atomic, Value}</code>, the number of subtrees is
+%% zero.</p>
+%%
+%% @see is_data/1
+%% @see data_type/1
+%% @see data_arity/1
+%% @see make_data/2
+
+-spec data_es(c_lct()) -> [cerl()].
+
+data_es(#c_literal{val = V}) ->
+ case V of
+ [Head | Tail] ->
+ [#c_literal{val = Head}, #c_literal{val = Tail}];
+ _ when is_tuple(V) ->
+ make_lit_list(tuple_to_list(V));
+ _ ->
+ []
+ end;
+data_es(#c_cons{hd = H, tl = T}) ->
+ [H, T];
+data_es(#c_tuple{es = Es}) ->
+ Es.
+
+%% @spec data_arity(Node::cerl()) -> non_neg_integer()
+%%
+%% @doc Returns the number of subtrees of a data constructor
+%% node. This is equivalent to <code>length(data_es(Node))</code>, but
+%% potentially more efficient.
+%%
+%% @see is_data/1
+%% @see data_es/1
+
+-spec data_arity(c_lct()) -> non_neg_integer().
+
+data_arity(#c_literal{val = V}) ->
+ case V of
+ [_ | _] ->
+ 2;
+ _ when is_tuple(V) ->
+ tuple_size(V);
+ _ ->
+ 0
+ end;
+data_arity(#c_cons{}) ->
+ 2;
+data_arity(#c_tuple{es = Es}) ->
+ length(Es).
+
+
+%% @spec make_data(Type::dtype(), Elements::[cerl()]) -> cerl()
+%%
+%% @doc Creates a data constructor node with the specified type and
+%% subtrees. (Cf. <code>data_type/1</code>.) An exception is thrown
+%% if the length of <code>Elements</code> is invalid for the given
+%% <code>Type</code>; see <code>data_es/1</code> for arity constraints
+%% on constructor types.
+%%
+%% @see data_type/1
+%% @see data_es/1
+%% @see ann_make_data/3
+%% @see update_data/3
+%% @see make_data_skel/2
+
+-spec make_data(dtype(), [cerl()]) -> c_lct().
+
+make_data(CType, Es) ->
+ ann_make_data([], CType, Es).
+
+
+%% @spec ann_make_data(As::anns(), Type::dtype(),
+%% Elements::[cerl()]) -> cerl()
+%% @see make_data/2
+
+-spec ann_make_data(anns(), dtype(), [cerl()]) -> c_lct().
+
+ann_make_data(As, {atomic, V}, []) -> #c_literal{val = V, anno = As};
+ann_make_data(As, cons, [H, T]) -> ann_c_cons(As, H, T);
+ann_make_data(As, tuple, Es) -> ann_c_tuple(As, Es).
+
+%% @spec update_data(Old::cerl(), Type::dtype(),
+%% Elements::[cerl()]) -> cerl()
+%% @see make_data/2
+
+-spec update_data(cerl(), dtype(), [cerl()]) -> c_lct().
+
+update_data(Node, CType, Es) ->
+ ann_make_data(get_ann(Node), CType, Es).
+
+
+%% @spec make_data_skel(Type::dtype(), Elements::[cerl()]) -> cerl()
+%%
+%% @doc Like <code>make_data/2</code>, but analogous to
+%% <code>c_tuple_skel/1</code> and <code>c_cons_skel/2</code>.
+%%
+%% @see ann_make_data_skel/3
+%% @see update_data_skel/3
+%% @see make_data/2
+%% @see c_tuple_skel/1
+%% @see c_cons_skel/2
+
+-spec make_data_skel(dtype(), [cerl()]) -> c_lct().
+
+make_data_skel(CType, Es) ->
+ ann_make_data_skel([], CType, Es).
+
+
+%% @spec ann_make_data_skel(As::anns(), Type::dtype(),
+%% Elements::[cerl()]) -> cerl()
+%% @see make_data_skel/2
+
+-spec ann_make_data_skel(anns(), dtype(), [cerl()]) -> c_lct().
+
+ann_make_data_skel(As, {atomic, V}, []) -> #c_literal{val = V, anno = As};
+ann_make_data_skel(As, cons, [H, T]) -> ann_c_cons_skel(As, H, T);
+ann_make_data_skel(As, tuple, Es) -> ann_c_tuple_skel(As, Es).
+
+
+%% @spec update_data_skel(Old::cerl(), Type::dtype(),
+%% Elements::[cerl()]) -> cerl()
+%% @see make_data_skel/2
+
+-spec update_data_skel(cerl(), dtype(), [cerl()]) -> c_lct().
+
+update_data_skel(Node, CType, Es) ->
+ ann_make_data_skel(get_ann(Node), CType, Es).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec subtrees(Node::cerl()) -> [[cerl()]]
+%%
+%% @doc Returns the grouped list of all subtrees of a node. If
+%% <code>Node</code> is a leaf node (cf. <code>is_leaf/1</code>), this
+%% is the empty list, otherwise the result is always a nonempty list,
+%% containing the lists of subtrees of <code>Node</code>, in
+%% left-to-right order as they occur in the printed program text, and
+%% grouped by category. Often, each group contains only a single
+%% subtree.
+%%
+%% <p>Depending on the type of <code>Node</code>, the size of some
+%% groups may be variable (e.g., the group consisting of all the
+%% elements of a tuple), while others always contain the same number
+%% of elements - usually exactly one (e.g., the group containing the
+%% argument expression of a case-expression). Note, however, that the
+%% exact structure of the returned list (for a given node type) should
+%% in general not be depended upon, since it might be subject to
+%% change without notice.</p>
+%%
+%% <p>The function <code>subtrees/1</code> and the constructor functions
+%% <code>make_tree/2</code> and <code>update_tree/2</code> can be a
+%% great help if one wants to traverse a syntax tree, visiting all its
+%% subtrees, but treat nodes of the tree in a uniform way in most or all
+%% cases. Using these functions makes this simple, and also assures that
+%% your code is not overly sensitive to extensions of the syntax tree
+%% data type, because any node types not explicitly handled by your code
+%% can be left to a default case.</p>
+%%
+%% <p>For example:
+%% <pre>
+%% postorder(F, Tree) ->
+%% F(case subtrees(Tree) of
+%% [] -> Tree;
+%% List -> update_tree(Tree,
+%% [[postorder(F, Subtree)
+%% || Subtree &lt;- Group]
+%% || Group &lt;- List])
+%% end).
+%% </pre>
+%% maps the function <code>F</code> on <code>Tree</code> and all its
+%% subtrees, doing a post-order traversal of the syntax tree. (Note
+%% the use of <code>update_tree/2</code> to preserve annotations.) For
+%% a simple function like:
+%% <pre>
+%% f(Node) ->
+%% case type(Node) of
+%% atom -> atom("a_" ++ atom_name(Node));
+%% _ -> Node
+%% end.
+%% </pre>
+%% the call <code>postorder(fun f/1, Tree)</code> will yield a new
+%% representation of <code>Tree</code> in which all atom names have
+%% been extended with the prefix "a_", but nothing else (including
+%% annotations) has been changed.</p>
+%%
+%% @see is_leaf/1
+%% @see make_tree/2
+%% @see update_tree/2
+
+-spec subtrees(cerl()) -> [[cerl()]].
+
+subtrees(T) ->
+ case is_leaf(T) of
+ true ->
+ [];
+ false ->
+ case type(T) of
+ values ->
+ [values_es(T)];
+ binary ->
+ [binary_segments(T)];
+ bitstr ->
+ [[bitstr_val(T)], [bitstr_size(T)],
+ [bitstr_unit(T)], [bitstr_type(T)],
+ [bitstr_flags(T)]];
+ cons ->
+ [[cons_hd(T)], [cons_tl(T)]];
+ tuple ->
+ [tuple_es(T)];
+ map ->
+ [map_es(T)];
+ map_pair ->
+ [[map_pair_op(T)],[map_pair_key(T)],[map_pair_val(T)]];
+ 'let' ->
+ [let_vars(T), [let_arg(T)], [let_body(T)]];
+ seq ->
+ [[seq_arg(T)], [seq_body(T)]];
+ apply ->
+ [[apply_op(T)], apply_args(T)];
+ call ->
+ [[call_module(T)], [call_name(T)],
+ call_args(T)];
+ primop ->
+ [[primop_name(T)], primop_args(T)];
+ 'case' ->
+ [[case_arg(T)], case_clauses(T)];
+ clause ->
+ [clause_pats(T), [clause_guard(T)],
+ [clause_body(T)]];
+ alias ->
+ [[alias_var(T)], [alias_pat(T)]];
+ 'fun' ->
+ [fun_vars(T), [fun_body(T)]];
+ 'receive' ->
+ [receive_clauses(T), [receive_timeout(T)],
+ [receive_action(T)]];
+ 'try' ->
+ [[try_arg(T)], try_vars(T), [try_body(T)],
+ try_evars(T), [try_handler(T)]];
+ 'catch' ->
+ [[catch_body(T)]];
+ letrec ->
+ Es = unfold_tuples(letrec_defs(T)),
+ [Es, [letrec_body(T)]];
+ module ->
+ As = unfold_tuples(module_attrs(T)),
+ Es = unfold_tuples(module_defs(T)),
+ [[module_name(T)], module_exports(T), As, Es]
+ end
+ end.
+
+
+%% @spec update_tree(Old::cerl(), Groups::[[cerl()]]) -> cerl()
+%%
+%% @doc Creates a syntax tree with the given subtrees, and the same
+%% type and annotations as the <code>Old</code> node. This is
+%% equivalent to <code>ann_make_tree(get_ann(Node), type(Node),
+%% Groups)</code>, but potentially more efficient.
+%%
+%% @see update_tree/3
+%% @see ann_make_tree/3
+%% @see get_ann/1
+%% @see type/1
+
+-spec update_tree(cerl(), [[cerl()],...]) -> cerl().
+
+update_tree(Node, Gs) ->
+ ann_make_tree(get_ann(Node), type(Node), Gs).
+
+
+%% @spec update_tree(Old::cerl(), Type::ctype(), Groups::[[cerl()]]) ->
+%% cerl()
+%%
+%% @doc Creates a syntax tree with the given type and subtrees, and
+%% the same annotations as the <code>Old</code> node. This is
+%% equivalent to <code>ann_make_tree(get_ann(Node), Type,
+%% Groups)</code>, but potentially more efficient.
+%%
+%% @see update_tree/2
+%% @see ann_make_tree/3
+%% @see get_ann/1
+
+-spec update_tree(cerl(), ctype(), [[cerl()],...]) -> cerl().
+
+update_tree(Node, Type, Gs) ->
+ ann_make_tree(get_ann(Node), Type, Gs).
+
+
+%% @spec make_tree(Type::ctype(), Groups::[[cerl()]]) -> cerl()
+%%
+%% @doc Creates a syntax tree with the given type and subtrees.
+%% <code>Type</code> must be a node type name
+%% (cf. <code>type/1</code>) that does not denote a leaf node type
+%% (cf. <code>is_leaf/1</code>). <code>Groups</code> must be a
+%% <em>nonempty</em> list of groups of syntax trees, representing the
+%% subtrees of a node of the given type, in left-to-right order as
+%% they would occur in the printed program text, grouped by category
+%% as done by <code>subtrees/1</code>.
+%%
+%% <p>The result of <code>ann_make_tree(get_ann(Node), type(Node),
+%% subtrees(Node))</code> (cf. <code>update_tree/2</code>) represents
+%% the same source code text as the original <code>Node</code>,
+%% assuming that <code>subtrees(Node)</code> yields a nonempty
+%% list. However, it does not necessarily have the exact same data
+%% representation as <code>Node</code>.</p>
+%%
+%% @see ann_make_tree/3
+%% @see type/1
+%% @see is_leaf/1
+%% @see subtrees/1
+%% @see update_tree/2
+
+-spec make_tree(ctype(), [[cerl()],...]) -> cerl().
+
+make_tree(Type, Gs) ->
+ ann_make_tree([], Type, Gs).
+
+
+%% @spec ann_make_tree(As::anns(), Type::ctype(),
+%% Groups::[[cerl()]]) -> cerl()
+%%
+%% @doc Creates a syntax tree with the given annotations, type and
+%% subtrees. See <code>make_tree/2</code> for details.
+%%
+%% @see make_tree/2
+
+-spec ann_make_tree(anns(), ctype(), [[cerl()],...]) -> cerl().
+
+ann_make_tree(As, values, [Es]) -> ann_c_values(As, Es);
+ann_make_tree(As, binary, [Ss]) -> ann_c_binary(As, Ss);
+ann_make_tree(As, bitstr, [[V],[S],[U],[T],[Fs]]) ->
+ ann_c_bitstr(As, V, S, U, T, Fs);
+ann_make_tree(As, cons, [[H], [T]]) -> ann_c_cons(As, H, T);
+ann_make_tree(As, tuple, [Es]) -> ann_c_tuple(As, Es);
+ann_make_tree(As, map, [Es]) -> ann_c_map(As, Es);
+ann_make_tree(As, map, [[A], Es]) -> ann_c_map(As, A, Es);
+ann_make_tree(As, map_pair, [[Op], [K], [V]]) -> ann_c_map_pair(As, Op, K, V);
+ann_make_tree(As, 'let', [Vs, [A], [B]]) -> ann_c_let(As, Vs, A, B);
+ann_make_tree(As, seq, [[A], [B]]) -> ann_c_seq(As, A, B);
+ann_make_tree(As, apply, [[Op], Es]) -> ann_c_apply(As, Op, Es);
+ann_make_tree(As, call, [[M], [N], Es]) -> ann_c_call(As, M, N, Es);
+ann_make_tree(As, primop, [[N], Es]) -> ann_c_primop(As, N, Es);
+ann_make_tree(As, 'case', [[A], Cs]) -> ann_c_case(As, A, Cs);
+ann_make_tree(As, clause, [Ps, [G], [B]]) -> ann_c_clause(As, Ps, G, B);
+ann_make_tree(As, alias, [[V], [P]]) -> ann_c_alias(As, V, P);
+ann_make_tree(As, 'fun', [Vs, [B]]) -> ann_c_fun(As, Vs, B);
+ann_make_tree(As, 'receive', [Cs, [T], [A]]) ->
+ ann_c_receive(As, Cs, T, A);
+ann_make_tree(As, 'try', [[E], Vs, [B], Evs, [H]]) ->
+ ann_c_try(As, E, Vs, B, Evs, H);
+ann_make_tree(As, 'catch', [[B]]) -> ann_c_catch(As, B);
+ann_make_tree(As, letrec, [Es, [B]]) ->
+ ann_c_letrec(As, fold_tuples(Es), B);
+ann_make_tree(As, module, [[N], Xs, Es, Ds]) ->
+ ann_c_module(As, N, Xs, fold_tuples(Es), fold_tuples(Ds)).
+
+
+%% ---------------------------------------------------------------------
+
+%% @spec meta(Tree::cerl()) -> cerl()
+%%
+%% @doc Creates a meta-representation of a syntax tree. The result
+%% represents an Erlang expression "<code><em>MetaTree</em></code>"
+%% which, if evaluated, will yield a new syntax tree representing the
+%% same source code text as <code>Tree</code> (although the actual
+%% data representation may be different). The expression represented
+%% by <code>MetaTree</code> is <em>implementation independent</em>
+%% with regard to the data structures used by the abstract syntax tree
+%% implementation.
+%%
+%% <p>Any node in <code>Tree</code> whose node type is
+%% <code>var</code> (cf. <code>type/1</code>), and whose list of
+%% annotations (cf. <code>get_ann/1</code>) contains the atom
+%% <code>meta_var</code>, will remain unchanged in the resulting tree,
+%% except that exactly one occurrence of <code>meta_var</code> is
+%% removed from its annotation list.</p>
+%%
+%% <p>The main use of the function <code>meta/1</code> is to transform
+%% a data structure <code>Tree</code>, which represents a piece of
+%% program code, into a form that is <em>representation independent
+%% when printed</em>. E.g., suppose <code>Tree</code> represents a
+%% variable named "V". Then (assuming a function <code>print/1</code>
+%% for printing syntax trees), evaluating
+%% <code>print(abstract(Tree))</code> - simply using
+%% <code>abstract/1</code> to map the actual data structure onto a
+%% syntax tree representation - would output a string that might look
+%% something like "<code>{var, ..., 'V'}</code>", which is obviously
+%% dependent on the implementation of the abstract syntax trees. This
+%% could e.g. be useful for caching a syntax tree in a file. However,
+%% in some situations like in a program generator generator (with two
+%% "generator"), it may be unacceptable. Using
+%% <code>print(meta(Tree))</code> instead would output a
+%% <em>representation independent</em> syntax tree generating
+%% expression; in the above case, something like
+%% "<code>cerl:c_var('V')</code>".</p>
+%%
+%% <p>The implementation tries to generate compact code with respect
+%% to literals and lists.</p>
+%%
+%% @see abstract/1
+%% @see type/1
+%% @see get_ann/1
+
+-spec meta(cerl()) -> cerl().
+
+meta(Node) ->
+ %% First of all we check for metavariables:
+ case type(Node) of
+ var ->
+ case lists:member(meta_var, get_ann(Node)) of
+ false ->
+ meta_0(var, Node);
+ true ->
+ %% A meta-variable: remove the first found
+ %% 'meta_var' annotation, but otherwise leave
+ %% the node unchanged.
+ set_ann(Node, lists:delete(meta_var, get_ann(Node)))
+ end;
+ Type ->
+ meta_0(Type, Node)
+ end.
+
+meta_0(Type, Node) ->
+ case get_ann(Node) of
+ [] ->
+ meta_1(Type, Node);
+ As ->
+ meta_call(set_ann, [meta_1(Type, Node), abstract(As)])
+ end.
+
+meta_1(literal, Node) ->
+ %% We handle atomic literals separately, to get a bit
+ %% more compact code. For the rest, we use 'abstract'.
+ case concrete(Node) of
+ V when is_atom(V) ->
+ meta_call(c_atom, [Node]);
+ V when is_integer(V) ->
+ meta_call(c_int, [Node]);
+ V when is_float(V) ->
+ meta_call(c_float, [Node]);
+ [] ->
+ meta_call(c_nil, []);
+ _ ->
+ meta_call(abstract, [Node])
+ end;
+meta_1(var, Node) ->
+ %% A normal variable or function name.
+ meta_call(c_var, [abstract(var_name(Node))]);
+meta_1(values, Node) ->
+ meta_call(c_values,
+ [make_list(meta_list(values_es(Node)))]);
+meta_1(binary, Node) ->
+ meta_call(c_binary,
+ [make_list(meta_list(binary_segments(Node)))]);
+meta_1(bitstr, Node) ->
+ meta_call(c_bitstr,
+ [meta(bitstr_val(Node)),
+ meta(bitstr_size(Node)),
+ meta(bitstr_unit(Node)),
+ meta(bitstr_type(Node)),
+ meta(bitstr_flags(Node))]);
+meta_1(cons, Node) ->
+ %% The list is split up if some sublist has annotatations. If
+ %% 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], Node1} ->
+ meta_call(c_cons, [meta(H), meta(Node1)]);
+ {L, Node1} ->
+ meta_call(make_list,
+ [make_list(meta_list(L)), meta(Node1)])
+ end;
+meta_1(tuple, Node) ->
+ meta_call(c_tuple,
+ [make_list(meta_list(tuple_es(Node)))]);
+meta_1('let', Node) ->
+ meta_call(c_let,
+ [make_list(meta_list(let_vars(Node))),
+ meta(let_arg(Node)), meta(let_body(Node))]);
+meta_1(seq, Node) ->
+ meta_call(c_seq,
+ [meta(seq_arg(Node)), meta(seq_body(Node))]);
+meta_1(apply, Node) ->
+ meta_call(c_apply,
+ [meta(apply_op(Node)),
+ make_list(meta_list(apply_args(Node)))]);
+meta_1(call, Node) ->
+ meta_call(c_call,
+ [meta(call_module(Node)), meta(call_name(Node)),
+ make_list(meta_list(call_args(Node)))]);
+meta_1(primop, Node) ->
+ meta_call(c_primop,
+ [meta(primop_name(Node)),
+ make_list(meta_list(primop_args(Node)))]);
+meta_1('case', Node) ->
+ meta_call(c_case,
+ [meta(case_arg(Node)),
+ make_list(meta_list(case_clauses(Node)))]);
+meta_1(clause, Node) ->
+ meta_call(c_clause,
+ [make_list(meta_list(clause_pats(Node))),
+ meta(clause_guard(Node)),
+ meta(clause_body(Node))]);
+meta_1(alias, Node) ->
+ meta_call(c_alias,
+ [meta(alias_var(Node)), meta(alias_pat(Node))]);
+meta_1('fun', Node) ->
+ meta_call(c_fun,
+ [make_list(meta_list(fun_vars(Node))),
+ meta(fun_body(Node))]);
+meta_1('receive', Node) ->
+ meta_call(c_receive,
+ [make_list(meta_list(receive_clauses(Node))),
+ meta(receive_timeout(Node)),
+ meta(receive_action(Node))]);
+meta_1('try', Node) ->
+ meta_call(c_try,
+ [meta(try_arg(Node)),
+ make_list(meta_list(try_vars(Node))),
+ meta(try_body(Node)),
+ make_list(meta_list(try_evars(Node))),
+ meta(try_handler(Node))]);
+meta_1('catch', Node) ->
+ meta_call(c_catch, [meta(catch_body(Node))]);
+meta_1(letrec, Node) ->
+ meta_call(c_letrec,
+ [make_list([c_tuple([meta(N), meta(F)])
+ || {N, F} <- letrec_defs(Node)]),
+ meta(letrec_body(Node))]);
+meta_1(module, Node) ->
+ meta_call(c_module,
+ [meta(module_name(Node)),
+ make_list(meta_list(module_exports(Node))),
+ make_list([c_tuple([meta(A), meta(V)])
+ || {A, V} <- module_attrs(Node)]),
+ make_list([c_tuple([meta(N), meta(F)])
+ || {N, F} <- module_defs(Node)])]).
+
+meta_call(F, As) ->
+ c_call(c_atom(?MODULE), c_atom(F), As).
+
+meta_list([T | Ts]) ->
+ [meta(T) | meta_list(Ts)];
+meta_list([]) ->
+ [].
+
+split_list(Node) ->
+ split_list(set_ann(Node, []), []).
+
+split_list(Node, L) ->
+ A = get_ann(Node),
+ case type(Node) of
+ cons when A =:= [] ->
+ split_list(cons_tl(Node), [cons_hd(Node) | L]);
+ _ ->
+ {lists:reverse(L), Node}
+ end.
+
+
+%% ---------------------------------------------------------------------
+
+%% General utilities
+
+is_lit_list([#c_literal{} | Es]) ->
+ is_lit_list(Es);
+is_lit_list([_ | _]) ->
+ false;
+is_lit_list([]) ->
+ true.
+
+lit_list_vals([#c_literal{val = V} | Es]) ->
+ [V | lit_list_vals(Es)];
+lit_list_vals([]) ->
+ [].
+
+-spec make_lit_list([litval()]) -> [c_literal()].
+
+make_lit_list([V | Vs]) ->
+ [#c_literal{val = V} | make_lit_list(Vs)];
+make_lit_list([]) ->
+ [].
+
+%% The following tests are the same as done by 'io_lib:char_list' and
+%% 'io_lib:printable_list', respectively, but for a single character.
+
+is_char_value(V) when V >= $\000, V =< $\377 -> true;
+is_char_value(_) -> false.
+
+is_print_char_value(V) when V >= $\040, V =< $\176 -> true;
+is_print_char_value(V) when V >= $\240, V =< $\377 -> true;
+is_print_char_value(V) when V =:= $\b -> true;
+is_print_char_value(V) when V =:= $\d -> true;
+is_print_char_value(V) when V =:= $\e -> true;
+is_print_char_value(V) when V =:= $\f -> true;
+is_print_char_value(V) when V =:= $\n -> true;
+is_print_char_value(V) when V =:= $\r -> true;
+is_print_char_value(V) when V =:= $\s -> true;
+is_print_char_value(V) when V =:= $\t -> true;
+is_print_char_value(V) when V =:= $\v -> true;
+is_print_char_value(V) when V =:= $\" -> true;
+is_print_char_value(V) when V =:= $\' -> true; %' stupid Emacs.
+is_print_char_value(V) when V =:= $\\ -> true;
+is_print_char_value(_) -> false.
+
+is_char_list([V | Vs]) when is_integer(V) ->
+ is_char_value(V) andalso is_char_list(Vs);
+is_char_list([]) ->
+ true;
+is_char_list(_) ->
+ false.
+
+is_print_char_list([V | Vs]) when is_integer(V) ->
+ is_print_char_value(V) andalso is_print_char_list(Vs);
+is_print_char_list([]) ->
+ true;
+is_print_char_list(_) ->
+ false.
+
+unfold_tuples([{X, Y} | Ps]) ->
+ [X, Y | unfold_tuples(Ps)];
+unfold_tuples([]) ->
+ [].
+
+fold_tuples([X, Y | Es]) ->
+ [{X, Y} | fold_tuples(Es)];
+fold_tuples([]) ->
+ [].
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/core_parse.hrl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/core_parse.hrl
new file mode 100644
index 0000000000..5823622f05
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/core_parse.hrl
@@ -0,0 +1,122 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose : Core Erlang syntax trees as records.
+
+%% It would be nice to incorporate some generic functions as well but
+%% this could make including this file difficult.
+
+%% Note: the annotation list is *always* the first record field.
+%% Thus it is possible to define the macros:
+%% -define(get_ann(X), element(2, X)).
+%% -define(set_ann(X, Y), setelement(2, X, Y)).
+
+%% The record definitions appear alphabetically
+
+-record(c_alias, {anno=[] :: cerl:anns(),
+ var :: cerl:c_var(),
+ pat :: cerl:cerl()}).
+
+-record(c_apply, {anno=[] :: cerl:anns(),
+ op :: cerl:c_var(),
+ args :: [cerl:cerl()]}).
+
+-record(c_binary, {anno=[] :: cerl:anns(),
+ segments :: [cerl:c_bitstr()]}).
+
+-record(c_bitstr, {anno=[], val, % val :: Tree,
+ size, % size :: Tree,
+ unit, % unit :: Tree,
+ type, % type :: Tree,
+ flags}). % flags :: Tree
+
+-record(c_call, {anno=[], module, % module :: cerl:cerl(),
+ name, % name :: cerl:cerl(),
+ args}). % args :: [cerl:cerl()]
+
+-record(c_case, {anno=[] :: cerl:anns(),
+ arg :: cerl:cerl(),
+ clauses :: [cerl:cerl()]}).
+
+-record(c_catch, {anno=[] :: cerl:anns(), body :: cerl:cerl()}).
+
+-record(c_clause, {anno=[] :: cerl:anns(),
+ pats, % :: [cerl:cerl()], % pats :: [Tree],
+ guard, % :: cerl:cerl(), % guard :: Tree,
+ body}). % :: cerl:cerl()}). % body :: Tree
+
+-record(c_cons, {anno=[] :: cerl:anns(),
+ hd :: cerl:cerl(),
+ tl :: cerl:cerl()}).
+
+-record(c_fun, {anno=[] :: cerl:anns(),
+ vars :: [cerl:c_var()],
+ body :: cerl:cerl()}).
+
+-record(c_let, {anno=[] :: cerl:anns(),
+ vars :: [cerl:c_var()],
+ arg :: cerl:cerl(),
+ body :: cerl:cerl()}).
+
+-record(c_letrec, {anno=[] :: cerl:anns(),
+ defs :: cerl:defs(),
+ body :: cerl:cerl()}).
+
+-record(c_literal, {anno=[] :: cerl:anns(), val :: cerl:litval()}).
+
+-record(c_map, {anno=[] :: cerl:anns(),
+ arg=#c_literal{val=#{}} :: cerl:c_var() | cerl:c_literal(),
+ es :: [cerl:c_map_pair()],
+ is_pat=false :: boolean()}).
+
+-record(c_map_pair, {anno=[] :: cerl:anns(),
+ op, %:: #c_literal{val::'assoc'} | #c_literal{val::'exact'},
+ key,
+ val}).
+
+-record(c_module, {anno=[] :: cerl:anns(),
+ name :: cerl:c_literal(),
+ exports :: [cerl:c_var()],
+ attrs :: cerl:attrs(),
+ defs :: cerl:defs()}).
+
+-record(c_primop, {anno=[] :: cerl:anns(),
+ name :: cerl:c_literal(),
+ args :: [cerl:cerl()]}).
+
+-record(c_receive, {anno=[]:: cerl:anns(),
+ clauses, % clauses :: [Tree],
+ timeout, % timeout :: Tree,
+ action}). % action :: Tree
+
+-record(c_seq, {anno=[] :: cerl:anns(),
+ arg, % arg :: cerl:cerl(),
+ body}). % body :: cerl:cerl()
+
+-record(c_try, {anno=[], arg, % arg :: cerl:cerl(),
+ vars, % vars :: [cerl:c_var()],
+ body, % body :: cerl:cerl(),
+ evars, % evars :: [cerl:c_var()],
+ handler}). % handler :: cerl:cerl()
+
+-record(c_tuple, {anno=[] :: cerl:anns(), es :: [cerl:cerl()]}).
+
+-record(c_values, {anno=[] :: cerl:anns(), es :: [cerl:cerl()]}).
+
+-record(c_var, {anno=[] :: cerl:anns(), name :: cerl:var_name()}).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl
new file mode 100644
index 0000000000..1139044ec9
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl
@@ -0,0 +1,180 @@
+%%% This is an -*- Erlang -*- file.
+%%%
+%%% %CopyrightBegin%
+%%%
+%%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%%%
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+%%% %CopyrightEnd%
+%%%
+%%%-------------------------------------------------------------------
+%%% File : dialyzer.hrl
+%%% Author : Tobias Lindahl <[email protected]>
+%%% Kostis Sagonas <[email protected]>
+%%% Description : Header file for Dialyzer.
+%%%
+%%% Created : 1 Oct 2004 by Kostis Sagonas <[email protected]>
+%%%-------------------------------------------------------------------
+
+-define(RET_NOTHING_SUSPICIOUS, 0).
+-define(RET_INTERNAL_ERROR, 1).
+-define(RET_DISCREPANCIES, 2).
+
+-type dial_ret() :: ?RET_NOTHING_SUSPICIOUS
+ | ?RET_INTERNAL_ERROR
+ | ?RET_DISCREPANCIES.
+
+%%--------------------------------------------------------------------
+%% Warning classification
+%%--------------------------------------------------------------------
+
+-define(WARN_RETURN_NO_RETURN, warn_return_no_exit).
+-define(WARN_RETURN_ONLY_EXIT, warn_return_only_exit).
+-define(WARN_NOT_CALLED, warn_not_called).
+-define(WARN_NON_PROPER_LIST, warn_non_proper_list).
+-define(WARN_FUN_APP, warn_fun_app).
+-define(WARN_MATCHING, warn_matching).
+-define(WARN_OPAQUE, warn_opaque).
+-define(WARN_FAILING_CALL, warn_failing_call).
+-define(WARN_BIN_CONSTRUCTION, warn_bin_construction).
+-define(WARN_CONTRACT_TYPES, warn_contract_types).
+-define(WARN_CONTRACT_SYNTAX, warn_contract_syntax).
+-define(WARN_CONTRACT_NOT_EQUAL, warn_contract_not_equal).
+-define(WARN_CONTRACT_SUBTYPE, warn_contract_subtype).
+-define(WARN_CONTRACT_SUPERTYPE, warn_contract_supertype).
+-define(WARN_CONTRACT_RANGE, warn_contract_range).
+-define(WARN_CALLGRAPH, warn_callgraph).
+-define(WARN_UNMATCHED_RETURN, warn_umatched_return).
+-define(WARN_RACE_CONDITION, warn_race_condition).
+-define(WARN_BEHAVIOUR, warn_behaviour).
+-define(WARN_UNDEFINED_CALLBACK, warn_undefined_callbacks).
+-define(WARN_UNKNOWN, warn_unknown).
+-define(WARN_MAP_CONSTRUCTION, warn_map_construction).
+
+%%
+%% The following type has double role:
+%% 1. It is the set of warnings that will be collected.
+%% 2. It is also the set of tags for warnings that will be returned.
+%%
+-type dial_warn_tag() :: ?WARN_RETURN_NO_RETURN | ?WARN_RETURN_ONLY_EXIT
+ | ?WARN_NOT_CALLED | ?WARN_NON_PROPER_LIST
+ | ?WARN_MATCHING | ?WARN_OPAQUE | ?WARN_FUN_APP
+ | ?WARN_FAILING_CALL | ?WARN_BIN_CONSTRUCTION
+ | ?WARN_CONTRACT_TYPES | ?WARN_CONTRACT_SYNTAX
+ | ?WARN_CONTRACT_NOT_EQUAL | ?WARN_CONTRACT_SUBTYPE
+ | ?WARN_CONTRACT_SUPERTYPE | ?WARN_CALLGRAPH
+ | ?WARN_UNMATCHED_RETURN | ?WARN_RACE_CONDITION
+ | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE
+ | ?WARN_UNDEFINED_CALLBACK | ?WARN_UNKNOWN
+ | ?WARN_MAP_CONSTRUCTION.
+
+%%
+%% This is the representation of each warning as they will be returned
+%% to dialyzer's callers
+%%
+-type file_line() :: {file:filename(), non_neg_integer()}.
+-type dial_warning() :: {dial_warn_tag(), file_line(), {atom(), [term()]}}.
+
+%%
+%% This is the representation of each warning before suppressions have
+%% been applied
+%%
+-type m_or_mfa() :: module() % warnings not associated with any function
+ | mfa().
+-type warning_info() :: {file:filename(), non_neg_integer(), m_or_mfa()}.
+-type raw_warning() :: {dial_warn_tag(), warning_info(), {atom(), [term()]}}.
+
+%%
+%% This is the representation of dialyzer's internal errors
+%%
+-type dial_error() :: any(). %% XXX: underspecified
+
+%%--------------------------------------------------------------------
+%% Basic types used either in the record definitions below or in other
+%% parts of the application
+%%--------------------------------------------------------------------
+
+-type anal_type() :: 'succ_typings' | 'plt_build'.
+-type anal_type1() :: anal_type() | 'plt_add' | 'plt_check' | 'plt_remove'.
+-type contr_constr() :: {'subtype', erl_types:erl_type(), erl_types:erl_type()}.
+-type contract_pair() :: {erl_types:erl_type(), [contr_constr()]}.
+-type dial_define() :: {atom(), term()}.
+-type dial_option() :: {atom(), term()}.
+-type dial_options() :: [dial_option()].
+-type fopt() :: 'basename' | 'fullpath'.
+-type format() :: 'formatted' | 'raw'.
+-type label() :: non_neg_integer().
+-type dial_warn_tags():: ordsets:ordset(dial_warn_tag()).
+-type rep_mode() :: 'quiet' | 'normal' | 'verbose'.
+-type start_from() :: 'byte_code' | 'src_code'.
+-type mfa_or_funlbl() :: label() | mfa().
+-type solver() :: 'v1' | 'v2'.
+
+%%--------------------------------------------------------------------
+%% Record declarations used by various files
+%%--------------------------------------------------------------------
+
+-type doc_plt() :: 'undefined' | dialyzer_plt:plt().
+
+-record(analysis, {analysis_pid :: pid() | 'undefined',
+ type = succ_typings :: anal_type(),
+ defines = [] :: [dial_define()],
+ doc_plt :: doc_plt(),
+ files = [] :: [file:filename()],
+ include_dirs = [] :: [file:filename()],
+ start_from = byte_code :: start_from(),
+ plt :: dialyzer_plt:plt(),
+ use_contracts = true :: boolean(),
+ race_detection = false :: boolean(),
+ behaviours_chk = false :: boolean(),
+ timing = false :: boolean() | 'debug',
+ timing_server = none :: dialyzer_timing:timing_server(),
+ callgraph_file = "" :: file:filename(),
+ solvers :: [solver()]}).
+
+-record(options, {files = [] :: [file:filename()],
+ files_rec = [] :: [file:filename()],
+ analysis_type = succ_typings :: anal_type1(),
+ timing = false :: boolean() | 'debug',
+ defines = [] :: [dial_define()],
+ from = byte_code :: start_from(),
+ get_warnings = maybe :: boolean() | 'maybe',
+ init_plts = [] :: [file:filename()],
+ include_dirs = [] :: [file:filename()],
+ output_plt = none :: 'none' | file:filename(),
+ legal_warnings = ordsets:new() :: dial_warn_tags(),
+ report_mode = normal :: rep_mode(),
+ erlang_mode = false :: boolean(),
+ use_contracts = true :: boolean(),
+ output_file = none :: 'none' | file:filename(),
+ output_format = formatted :: format(),
+ filename_opt = basename :: fopt(),
+ callgraph_file = "" :: file:filename(),
+ check_plt = true :: boolean(),
+ solvers = [] :: [solver()]}).
+
+-record(contract, {contracts = [] :: [contract_pair()],
+ args = [] :: [erl_types:erl_type()],
+ forms = [] :: [{_, _}]}).
+
+%%--------------------------------------------------------------------
+
+-define(timing(Server, Msg, Var, Expr),
+ begin
+ dialyzer_timing:start_stamp(Server, Msg),
+ Var = Expr,
+ dialyzer_timing:end_stamp(Server),
+ Var
+ end).
+-define(timing(Server, Msg, Expr), ?timing(Server, Msg, _T, Expr)).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_dataflow.erl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_dataflow.erl
new file mode 100644
index 0000000000..9399789464
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_dataflow.erl
@@ -0,0 +1,3802 @@
+%% -*- erlang-indent-level: 2 -*-
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : dialyzer_dataflow.erl
+%%% Author : Tobias Lindahl <[email protected]>
+%%% Description :
+%%%
+%%% Created : 19 Apr 2005 by Tobias Lindahl <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(dialyzer_dataflow).
+
+-export([get_fun_types/5, get_warnings/5, format_args/3]).
+
+%% Data structure interfaces.
+-export([state__add_warning/2, state__cleanup/1,
+ state__duplicate/1, dispose_state/1,
+ state__get_callgraph/1, state__get_races/1,
+ state__get_records/1, state__put_callgraph/2,
+ state__put_races/2, state__records_only/1,
+ state__find_function/2]).
+
+-export_type([state/0]).
+
+-include("dialyzer.hrl").
+
+-import(erl_types,
+ [t_inf/2, t_inf/3, t_inf_lists/2, t_inf_lists/3,
+ t_inf_lists/3, t_is_equal/2, t_is_subtype/2, t_subtract/2,
+ t_sup/1, t_sup/2]).
+
+-import(erl_types,
+ [any_none/1, t_any/0, t_atom/0, t_atom/1, t_atom_vals/1, t_atom_vals/2,
+ t_binary/0, t_boolean/0,
+ t_bitstr/0, t_bitstr/2, t_bitstr_concat/1, t_bitstr_match/2,
+ t_cons/0, t_cons/2, t_cons_hd/2, t_cons_tl/2,
+ t_contains_opaque/2,
+ t_find_opaque_mismatch/3, t_float/0, t_from_range/2, t_from_term/1,
+ t_fun/0, t_fun/2, t_fun_args/1, t_fun_args/2, t_fun_range/1,
+ t_fun_range/2, t_integer/0, t_integers/1,
+ t_is_any/1, t_is_atom/1, t_is_atom/2, t_is_any_atom/3,
+ t_is_boolean/2,
+ t_is_integer/2, t_is_list/1,
+ t_is_nil/2, t_is_none/1, t_is_none_or_unit/1,
+ t_is_number/2, t_is_reference/2, t_is_pid/2, t_is_port/2,
+ t_is_unit/1,
+ t_limit/2, t_list/0, t_list_elements/2,
+ t_maybe_improper_list/0, t_module/0,
+ t_none/0, t_non_neg_integer/0, t_number/0, t_number_vals/2,
+ t_pid/0, t_port/0, t_product/1, t_reference/0,
+ t_to_string/2, t_to_tlist/1,
+ t_tuple/0, t_tuple/1, t_tuple_args/1, t_tuple_args/2,
+ t_tuple_subtypes/2,
+ t_unit/0, t_unopaque/2,
+ t_map/0, t_map/1, t_is_singleton/2
+ ]).
+
+%%-define(DEBUG, true).
+%%-define(DEBUG_PP, true).
+%%-define(DEBUG_TIME, true).
+
+-ifdef(DEBUG).
+-import(erl_types, [t_to_string/1]).
+-define(debug(S_, L_), io:format(S_, L_)).
+-else.
+-define(debug(S_, L_), ok).
+-endif.
+
+%%--------------------------------------------------------------------
+
+-type type() :: erl_types:erl_type().
+-type types() :: erl_types:type_table().
+
+-type curr_fun() :: 'undefined' | 'top' | mfa_or_funlbl().
+
+-define(no_arg, no_arg).
+
+-define(TYPE_LIMIT, 3).
+
+-define(BITS, 128).
+
+%% Types with comment 'race' are due to dialyzer_races.erl.
+-record(state, {callgraph :: dialyzer_callgraph:callgraph()
+ | 'undefined', % race
+ codeserver :: dialyzer_codeserver:codeserver()
+ | 'undefined', % race
+ envs :: env_tab()
+ | 'undefined', % race
+ fun_tab :: fun_tab()
+ | 'undefined', % race
+ fun_homes :: dict:dict(label(), mfa())
+ | 'undefined', % race
+ plt :: dialyzer_plt:plt()
+ | 'undefined', % race
+ opaques :: [type()]
+ | 'undefined', % race
+ races = dialyzer_races:new() :: dialyzer_races:races(),
+ records = dict:new() :: types(),
+ tree_map :: dict:dict(label(), cerl:cerl())
+ | 'undefined', % race
+ warning_mode = false :: boolean(),
+ warnings = [] :: [raw_warning()],
+ work :: {[_], [_], sets:set()}
+ | 'undefined', % race
+ module :: module(),
+ curr_fun :: curr_fun()
+ }).
+
+-record(map, {map = maps:new() :: type_tab(),
+ subst = maps:new() :: subst_tab(),
+ modified = [] :: [Key :: term()],
+ modified_stack = [] :: [{[Key :: term()],reference()}],
+ ref = undefined :: reference() | undefined}).
+
+-type env_tab() :: dict:dict(label(), #map{}).
+-type fun_entry() :: {Args :: [type()], RetType :: type()}.
+-type fun_tab() :: dict:dict('top' | label(),
+ {'not_handled', fun_entry()} | fun_entry()).
+-type key() :: label() | cerl:cerl().
+-type type_tab() :: #{key() => type()}.
+-type subst_tab() :: #{key() => cerl:cerl()}.
+
+%% Exported Types
+
+-opaque state() :: #state{}.
+
+%%--------------------------------------------------------------------
+
+-type fun_types() :: dict:dict(label(), type()).
+
+-spec get_warnings(cerl:c_module(), dialyzer_plt:plt(),
+ dialyzer_callgraph:callgraph(),
+ dialyzer_codeserver:codeserver(),
+ types()) ->
+ {[raw_warning()], fun_types()}.
+
+get_warnings(Tree, Plt, Callgraph, Codeserver, Records) ->
+ State1 = analyze_module(Tree, Plt, Callgraph, Codeserver, Records, true),
+ State2 = state__renew_warnings(state__get_warnings(State1), State1),
+ State3 = state__get_race_warnings(State2),
+ {State3#state.warnings, state__all_fun_types(State3)}.
+
+-spec get_fun_types(cerl:c_module(), dialyzer_plt:plt(),
+ dialyzer_callgraph:callgraph(),
+ dialyzer_codeserver:codeserver(),
+ types()) -> fun_types().
+
+get_fun_types(Tree, Plt, Callgraph, Codeserver, Records) ->
+ State = analyze_module(Tree, Plt, Callgraph, Codeserver, Records, false),
+ state__all_fun_types(State).
+
+%%% ===========================================================================
+%%%
+%%% The analysis.
+%%%
+%%% ===========================================================================
+
+analyze_module(Tree, Plt, Callgraph, Codeserver, Records, GetWarnings) ->
+ debug_pp(Tree, false),
+ Module = cerl:atom_val(cerl:module_name(Tree)),
+ TopFun = cerl:ann_c_fun([{label, top}], [], Tree),
+ State = state__new(Callgraph, Codeserver, TopFun, Plt, Module, Records),
+ State1 = state__race_analysis(not GetWarnings, State),
+ State2 = analyze_loop(State1),
+ case GetWarnings of
+ true ->
+ State3 = state__set_warning_mode(State2),
+ State4 = analyze_loop(State3),
+ dialyzer_races:race(State4);
+ false ->
+ State2
+ end.
+
+analyze_loop(State) ->
+ case state__get_work(State) of
+ none -> state__set_curr_fun(undefined, State);
+ {Fun, NewState0} ->
+ NewState1 = state__set_curr_fun(get_label(Fun), NewState0),
+ {ArgTypes, IsCalled} = state__get_args_and_status(Fun, NewState1),
+ case not IsCalled of
+ true ->
+ ?debug("Not handling (not called) ~w: ~s\n",
+ [NewState1#state.curr_fun,
+ t_to_string(t_product(ArgTypes))]),
+ analyze_loop(NewState1);
+ false ->
+ case state__fun_env(Fun, NewState1) of
+ none ->
+ ?debug("Not handling (no env) ~w: ~s\n",
+ [NewState1#state.curr_fun,
+ t_to_string(t_product(ArgTypes))]),
+ analyze_loop(NewState1);
+ Map ->
+ ?debug("Handling fun ~p: ~s\n",
+ [NewState1#state.curr_fun,
+ t_to_string(state__fun_type(Fun, NewState1))]),
+ Vars = cerl:fun_vars(Fun),
+ Map1 = enter_type_lists(Vars, ArgTypes, Map),
+ Body = cerl:fun_body(Fun),
+ FunLabel = get_label(Fun),
+ IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
+ NewState3 =
+ case IsRaceAnalysisEnabled of
+ true ->
+ NewState2 = state__renew_curr_fun(
+ state__lookup_name(FunLabel, NewState1), FunLabel,
+ NewState1),
+ state__renew_race_list([], 0, NewState2);
+ false -> NewState1
+ end,
+ {NewState4, _Map2, BodyType} =
+ traverse(Body, Map1, NewState3),
+ ?debug("Done analyzing: ~w:~s\n",
+ [NewState1#state.curr_fun,
+ t_to_string(t_fun(ArgTypes, BodyType))]),
+ NewState5 =
+ case IsRaceAnalysisEnabled of
+ true -> renew_race_code(NewState4);
+ false -> NewState4
+ end,
+ NewState6 =
+ state__update_fun_entry(Fun, ArgTypes, BodyType, NewState5),
+ ?debug("done adding stuff for ~w\n",
+ [state__lookup_name(get_label(Fun), State)]),
+ analyze_loop(NewState6)
+ end
+ end
+ end.
+
+traverse(Tree, Map, State) ->
+ ?debug("Handling ~p\n", [cerl:type(Tree)]),
+ %% debug_pp_map(Map),
+ case cerl:type(Tree) of
+ alias ->
+ %% This only happens when checking for illegal record patterns
+ %% so the handling is a bit rudimentary.
+ traverse(cerl:alias_pat(Tree), Map, State);
+ apply ->
+ handle_apply(Tree, Map, State);
+ binary ->
+ Segs = cerl:binary_segments(Tree),
+ {State1, Map1, SegTypes} = traverse_list(Segs, Map, State),
+ {State1, Map1, t_bitstr_concat(SegTypes)};
+ bitstr ->
+ handle_bitstr(Tree, Map, State);
+ call ->
+ handle_call(Tree, Map, State);
+ 'case' ->
+ handle_case(Tree, Map, State);
+ 'catch' ->
+ {State1, _Map1, _} = traverse(cerl:catch_body(Tree), Map, State),
+ {State1, Map, t_any()};
+ cons ->
+ handle_cons(Tree, Map, State);
+ 'fun' ->
+ Type = state__fun_type(Tree, State),
+ case state__warning_mode(State) of
+ true -> {State, Map, Type};
+ false ->
+ State2 = state__add_work(get_label(Tree), State),
+ State3 = state__update_fun_env(Tree, Map, State2),
+ {State3, Map, Type}
+ end;
+ 'let' ->
+ handle_let(Tree, Map, State);
+ letrec ->
+ Defs = cerl:letrec_defs(Tree),
+ Body = cerl:letrec_body(Tree),
+ %% By not including the variables in scope we can assure that we
+ %% will get the current function type when using the variables.
+ FoldFun = fun({Var, Fun}, {AccState, AccMap}) ->
+ {NewAccState, NewAccMap0, FunType} =
+ traverse(Fun, AccMap, AccState),
+ NewAccMap = enter_type(Var, FunType, NewAccMap0),
+ {NewAccState, NewAccMap}
+ end,
+ {State1, Map1} = lists:foldl(FoldFun, {State, Map}, Defs),
+ traverse(Body, Map1, State1);
+ literal ->
+ Type = literal_type(Tree),
+ {State, Map, Type};
+ module ->
+ handle_module(Tree, Map, State);
+ primop ->
+ Type =
+ case cerl:atom_val(cerl:primop_name(Tree)) of
+ match_fail -> t_none();
+ raise -> t_none();
+ bs_init_writable -> t_from_term(<<>>);
+ Other -> erlang:error({'Unsupported primop', Other})
+ end,
+ {State, Map, Type};
+ 'receive' ->
+ handle_receive(Tree, Map, State);
+ seq ->
+ Arg = cerl:seq_arg(Tree),
+ Body = cerl:seq_body(Tree),
+ {State1, Map1, ArgType} = SMA = traverse(Arg, Map, State),
+ case t_is_none_or_unit(ArgType) of
+ true ->
+ SMA;
+ false ->
+ State2 =
+ case
+ t_is_any(ArgType)
+ orelse t_is_simple(ArgType, State)
+ orelse is_call_to_send(Arg)
+ orelse is_lc_simple_list(Arg, ArgType, State)
+ of
+ true -> % do not warn in these cases
+ State1;
+ false ->
+ state__add_warning(State1, ?WARN_UNMATCHED_RETURN, Arg,
+ {unmatched_return,
+ [format_type(ArgType, State1)]})
+ end,
+ traverse(Body, Map1, State2)
+ end;
+ 'try' ->
+ handle_try(Tree, Map, State);
+ tuple ->
+ handle_tuple(Tree, Map, State);
+ map ->
+ handle_map(Tree, Map, State);
+ values ->
+ Elements = cerl:values_es(Tree),
+ {State1, Map1, EsType} = traverse_list(Elements, Map, State),
+ Type = t_product(EsType),
+ {State1, Map1, Type};
+ var ->
+ ?debug("Looking up unknown variable: ~p\n", [Tree]),
+ case state__lookup_type_for_letrec(Tree, State) of
+ error ->
+ LType = lookup_type(Tree, Map),
+ {State, Map, LType};
+ {ok, Type} -> {State, Map, Type}
+ end;
+ Other ->
+ erlang:error({'Unsupported type', Other})
+ end.
+
+traverse_list(Trees, Map, State) ->
+ traverse_list(Trees, Map, State, []).
+
+traverse_list([Tree|Tail], Map, State, Acc) ->
+ {State1, Map1, Type} = traverse(Tree, Map, State),
+ traverse_list(Tail, Map1, State1, [Type|Acc]);
+traverse_list([], Map, State, Acc) ->
+ {State, Map, lists:reverse(Acc)}.
+
+%%________________________________________
+%%
+%% Special instructions
+%%
+
+handle_apply(Tree, Map, State) ->
+ Args = cerl:apply_args(Tree),
+ Op = cerl:apply_op(Tree),
+ {State0, Map1, ArgTypes} = traverse_list(Args, Map, State),
+ {State1, Map2, OpType} = traverse(Op, Map1, State0),
+ case any_none(ArgTypes) of
+ true ->
+ {State1, Map2, t_none()};
+ false ->
+ FunList =
+ case state__lookup_call_site(Tree, State) of
+ error -> [external]; %% so that we go directly in the fallback
+ {ok, List} -> List
+ end,
+ 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
+ true ->
+ Msg = {fun_app_no_fun,
+ [format_cerl(Op), format_type(OpType, State2), Arity]},
+ State3 = state__add_warning(State2, ?WARN_FAILING_CALL,
+ Tree, Msg),
+ {State3, Map2, t_none()};
+ false ->
+ NewArgs = t_inf_lists(ArgTypes,
+ t_fun_args(OpType1, 'universe')),
+ case any_none(NewArgs) of
+ true ->
+ Msg = {fun_app_args,
+ [format_args(Args, ArgTypes, State),
+ format_type(OpType, State)]},
+ State3 = state__add_warning(State2, ?WARN_FAILING_CALL,
+ Tree, Msg),
+ {State3, enter_type(Op, OpType1, Map2), t_none()};
+ false ->
+ Map3 = enter_type_lists(Args, NewArgs, Map2),
+ Range0 = t_fun_range(OpType1, 'universe'),
+ Range =
+ case t_is_unit(Range0) of
+ true -> t_none();
+ false -> Range0
+ end,
+ {State2, enter_type(Op, OpType1, Map3), Range}
+ end
+ end;
+ Normal -> Normal
+ end
+ end.
+
+handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State) ->
+ None = t_none(),
+ %% Call-site analysis may be inaccurate and consider more funs than those that
+ %% are actually possible. If all of them are incorrect, then warnings can be
+ %% emitted. If at least one fun is ok, however, then no warning is emitted,
+ %% just in case the bad ones are not really possible. The last argument is
+ %% used for this, with the following encoding:
+ %% Initial value: {none, []}
+ %% First fun checked: {one, <List of warns>}
+ %% More funs checked: {many, <List of warns>}
+ %% A '{one, []}' can only become '{many, []}'.
+ %% If at any point an fun does not add warnings, then the list is also
+ %% replaced with an empty list.
+ handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State,
+ [None || _ <- ArgTypes], None, false, {none, []}).
+
+handle_apply_or_call([{local, external}|Left], Args, ArgTypes, Map, Tree, State,
+ _AccArgTypes, _AccRet, _HadExternal, Warns) ->
+ {HowMany, _} = Warns,
+ NewHowMany =
+ case HowMany of
+ none -> one;
+ _ -> many
+ end,
+ NewWarns = {NewHowMany, []},
+ handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, State,
+ ArgTypes, t_any(), true, NewWarns);
+handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
+ Args, ArgTypes, Map, Tree,
+ #state{opaques = Opaques} = State,
+ AccArgTypes, AccRet, HadExternal, Warns) ->
+ Any = t_any(),
+ AnyArgs = [Any || _ <- Args],
+ GenSig = {AnyArgs, fun(_) -> t_any() end},
+ {CArgs, CRange} =
+ case Contr of
+ {value, #contract{args = As} = C} ->
+ {As, fun(FunArgs) ->
+ dialyzer_contracts:get_contract_return(C, FunArgs)
+ end};
+ none -> GenSig
+ end,
+ {BifArgs, BifRange} =
+ case TypeOfApply of
+ remote ->
+ {M, F, A} = Fun,
+ case erl_bif_types:is_known(M, F, A) of
+ true ->
+ BArgs = erl_bif_types:arg_types(M, F, A),
+ BRange =
+ fun(FunArgs) ->
+ erl_bif_types:type(M, F, A, FunArgs, Opaques)
+ end,
+ {BArgs, BRange};
+ false ->
+ GenSig
+ end;
+ local -> GenSig
+ end,
+ {SigArgs, SigRange} =
+ case Sig of
+ {value, {SR, SA}} -> {SA, SR};
+ none -> {AnyArgs, t_any()}
+ end,
+
+ ?debug("--------------------------------------------------------\n", []),
+ ?debug("Fun: ~p\n", [state__lookup_name(Fun, State)]),
+ ?debug("Module ~p\n", [State#state.module]),
+ ?debug("CArgs ~s\n", [erl_types:t_to_string(t_product(CArgs))]),
+ ?debug("ArgTypes ~s\n", [erl_types:t_to_string(t_product(ArgTypes))]),
+ ?debug("BifArgs ~p\n", [erl_types:t_to_string(t_product(BifArgs))]),
+
+ NewArgsSig = t_inf_lists(SigArgs, ArgTypes, Opaques),
+ ?debug("SigArgs ~s\n", [erl_types:t_to_string(t_product(SigArgs))]),
+ ?debug("NewArgsSig: ~s\n", [erl_types:t_to_string(t_product(NewArgsSig))]),
+ NewArgsContract = t_inf_lists(CArgs, ArgTypes, Opaques),
+ ?debug("NewArgsContract: ~s\n",
+ [erl_types:t_to_string(t_product(NewArgsContract))]),
+ NewArgsBif = t_inf_lists(BifArgs, ArgTypes, Opaques),
+ ?debug("NewArgsBif: ~s\n", [erl_types:t_to_string(t_product(NewArgsBif))]),
+ NewArgTypes0 = t_inf_lists(NewArgsSig, NewArgsContract),
+ NewArgTypes = t_inf_lists(NewArgTypes0, NewArgsBif, Opaques),
+ ?debug("NewArgTypes ~s\n", [erl_types:t_to_string(t_product(NewArgTypes))]),
+ ?debug("\n", []),
+
+ BifRet = BifRange(NewArgTypes),
+ ContrRet = CRange(NewArgTypes),
+ RetWithoutContr = t_inf(SigRange, BifRet),
+ RetWithoutLocal = t_inf(ContrRet, RetWithoutContr),
+
+ ?debug("RetWithoutContr: ~s\n",[erl_types:t_to_string(RetWithoutContr)]),
+ ?debug("RetWithoutLocal: ~s\n", [erl_types:t_to_string(RetWithoutLocal)]),
+ ?debug("BifRet: ~s\n", [erl_types:t_to_string(BifRange(NewArgTypes))]),
+ ?debug("SigRange: ~s\n", [erl_types:t_to_string(SigRange)]),
+ ?debug("ContrRet: ~s\n", [erl_types:t_to_string(ContrRet)]),
+ ?debug("LocalRet: ~s\n", [erl_types:t_to_string(LocalRet)]),
+
+ State1 =
+ case is_race_analysis_enabled(State) of
+ true ->
+ Ann = cerl:get_ann(Tree),
+ File = get_file(Ann),
+ Line = abs(get_line(Ann)),
+ dialyzer_races:store_race_call(Fun, ArgTypes, Args,
+ {File, Line}, State);
+ false -> State
+ end,
+ FailedConj = any_none([RetWithoutLocal|NewArgTypes]),
+ IsFailBif = t_is_none(BifRange(BifArgs)),
+ IsFailSig = t_is_none(SigRange),
+ ?debug("FailedConj: ~p~n", [FailedConj]),
+ ?debug("IsFailBif: ~p~n", [IsFailBif]),
+ ?debug("IsFailSig: ~p~n", [IsFailSig]),
+ State2 =
+ case FailedConj andalso not (IsFailBif orelse IsFailSig) of
+ true ->
+ case t_is_none(RetWithoutLocal) andalso
+ not t_is_none(RetWithoutContr) andalso
+ not any_none(NewArgTypes) of
+ true ->
+ {value, C1} = Contr,
+ Contract = dialyzer_contracts:contract_to_string(C1),
+ {M1, F1, A1} = state__lookup_name(Fun, State),
+ ArgStrings = format_args(Args, ArgTypes, State),
+ CRet = erl_types:t_to_string(RetWithoutContr),
+ %% This Msg will be post_processed by dialyzer_succ_typings
+ Msg =
+ {contract_range, [Contract, M1, F1, A1, ArgStrings, CRet]},
+ state__add_warning(State1, ?WARN_CONTRACT_RANGE, Tree, Msg);
+ false ->
+ FailedSig = any_none(NewArgsSig),
+ FailedContract =
+ any_none([CRange(NewArgsContract)|NewArgsContract]),
+ FailedBif = any_none([BifRange(NewArgsBif)|NewArgsBif]),
+ InfSig = t_inf(t_fun(SigArgs, SigRange),
+ t_fun(BifArgs, BifRange(BifArgs))),
+ FailReason =
+ apply_fail_reason(FailedSig, FailedBif, FailedContract),
+ Msg = get_apply_fail_msg(Fun, Args, ArgTypes, NewArgTypes, InfSig,
+ Contr, CArgs, State1, FailReason, Opaques),
+ WarnType = case Msg of
+ {call, _} -> ?WARN_FAILING_CALL;
+ {apply, _} -> ?WARN_FAILING_CALL;
+ {call_with_opaque, _} -> ?WARN_OPAQUE;
+ {call_without_opaque, _} -> ?WARN_OPAQUE;
+ {opaque_type_test, _} -> ?WARN_OPAQUE
+ end,
+ Frc = {erlang, is_record, 3} =:= state__lookup_name(Fun, State),
+ state__add_warning(State1, WarnType, Tree, Msg, Frc)
+ end;
+ false -> State1
+ end,
+ State3 =
+ case TypeOfApply of
+ local ->
+ case state__is_escaping(Fun, State2) of
+ true -> State2;
+ false ->
+ ForwardArgs = [t_limit(X, ?TYPE_LIMIT) || X <- ArgTypes],
+ forward_args(Fun, ForwardArgs, State2)
+ end;
+ remote ->
+ add_bif_warnings(Fun, NewArgTypes, Tree, State2)
+ end,
+ NewAccArgTypes =
+ case FailedConj of
+ true -> AccArgTypes;
+ false -> [t_sup(X, Y) || {X, Y} <- lists:zip(NewArgTypes, AccArgTypes)]
+ end,
+ TotalRet =
+ case t_is_none(LocalRet) andalso t_is_unit(RetWithoutLocal) of
+ true -> RetWithoutLocal;
+ false -> t_inf(RetWithoutLocal, LocalRet)
+ end,
+ NewAccRet = t_sup(AccRet, TotalRet),
+ ?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]),
+ {NewWarnings, State4} = state__remove_added_warnings(State, State3),
+ {HowMany, OldWarnings} = Warns,
+ NewWarns =
+ case HowMany of
+ none -> {one, NewWarnings};
+ _ ->
+ case OldWarnings =:= [] of
+ true -> {many, []};
+ false ->
+ case NewWarnings =:= [] of
+ true -> {many, []};
+ false -> {many, NewWarnings ++ OldWarnings}
+ end
+ end
+ end,
+ handle_apply_or_call(Left, Args, ArgTypes, Map, Tree,
+ State4, NewAccArgTypes, NewAccRet, HadExternal, NewWarns);
+handle_apply_or_call([], Args, _ArgTypes, Map, _Tree, State,
+ AccArgTypes, AccRet, HadExternal, {_, Warnings}) ->
+ State1 = state__add_warnings(Warnings, State),
+ case HadExternal of
+ false ->
+ NewMap = enter_type_lists(Args, AccArgTypes, Map),
+ {State1, NewMap, AccRet};
+ true ->
+ {had_external, State1}
+ end.
+
+apply_fail_reason(FailedSig, FailedBif, FailedContract) ->
+ if
+ (FailedSig orelse FailedBif) andalso (not FailedContract) -> only_sig;
+ FailedContract andalso (not (FailedSig orelse FailedBif)) -> only_contract;
+ true -> both
+ end.
+
+get_apply_fail_msg(Fun, Args, ArgTypes, NewArgTypes,
+ Sig, Contract, ContrArgs, State, FailReason, Opaques) ->
+ ArgStrings = format_args(Args, ArgTypes, State),
+ ContractInfo =
+ case Contract of
+ {value, #contract{} = C} ->
+ {dialyzer_contracts:is_overloaded(C),
+ dialyzer_contracts:contract_to_string(C)};
+ none -> {false, none}
+ end,
+ EnumArgTypes = lists:zip(lists:seq(1, length(NewArgTypes)), NewArgTypes),
+ ArgNs = [Arg || {Arg, Type} <- EnumArgTypes, t_is_none(Type)],
+ case state__lookup_name(Fun, State) of
+ {M, F, A} ->
+ case is_opaque_type_test_problem(Fun, Args, NewArgTypes, State) of
+ {yes, Arg, ArgType} ->
+ {opaque_type_test, [atom_to_list(F), ArgStrings,
+ format_arg(Arg), format_type(ArgType, State)]};
+ no ->
+ SigArgs = t_fun_args(Sig),
+ BadOpaque =
+ opaque_problems([SigArgs, ContrArgs], ArgTypes, Opaques, ArgNs),
+ %% In fact *both* 'call_with_opaque' and
+ %% 'call_without_opaque' are possible.
+ case lists:keyfind(decl, 1, BadOpaque) of
+ {decl, BadArgs} ->
+ %% a structured term is used where an opaque is expected
+ ExpectedTriples =
+ case FailReason of
+ only_sig -> expected_arg_triples(BadArgs, SigArgs, State);
+ _ -> expected_arg_triples(BadArgs, ContrArgs, State)
+ end,
+ {call_without_opaque, [M, F, ArgStrings, ExpectedTriples]};
+ false ->
+ case lists:keyfind(use, 1, BadOpaque) of
+ {use, BadArgs} ->
+ %% an opaque term is used where a structured term is expected
+ ExpectedArgs =
+ case FailReason of
+ only_sig -> SigArgs;
+ _ -> ContrArgs
+ end,
+ {call_with_opaque, [M, F, ArgStrings, BadArgs, ExpectedArgs]};
+ false ->
+ case
+ erl_bif_types:opaque_args(M, F, A, ArgTypes, Opaques)
+ of
+ [] -> %% there is a structured term clash in some argument
+ {call, [M, F, ArgStrings,
+ ArgNs, FailReason,
+ format_sig_args(Sig, State),
+ format_type(t_fun_range(Sig), State),
+ ContractInfo]};
+ Ns ->
+ {call_with_opaque, [M, F, ArgStrings, Ns, ContrArgs]}
+ end
+ end
+ end
+ end;
+ Label when is_integer(Label) ->
+ {apply, [ArgStrings,
+ ArgNs, FailReason,
+ format_sig_args(Sig, State),
+ format_type(t_fun_range(Sig), State),
+ ContractInfo]}
+ end.
+
+%% -> [{ElementI, [ArgN]}] where [ArgN] is a non-empty list of
+%% arguments containing unknown opaque types and Element is 1 or 2.
+opaque_problems(ContractOrSigList, ArgTypes, Opaques, ArgNs) ->
+ ArgElementList = find_unknown(ContractOrSigList, ArgTypes, Opaques, ArgNs),
+ F = fun(1) -> decl; (2) -> use end,
+ [{F(ElementI), lists:usort([ArgN || {ArgN, EI} <- ArgElementList,
+ EI =:= ElementI])} ||
+ ElementI <- lists:usort([EI || {_, EI} <- ArgElementList])].
+
+%% -> [{ArgN, ElementI}] where ElementI = 1 means there is an unknown
+%% opaque type in argument ArgN of the the contract/signature,
+%% and ElementI = 2 means that there is an unknown opaque type in
+%% argument ArgN of the the (current) argument types.
+find_unknown(ContractOrSigList, ArgTypes, Opaques, NoneArgNs) ->
+ ArgNs = lists:seq(1, length(ArgTypes)),
+ [{ArgN, ElementI} ||
+ ContractOrSig <- ContractOrSigList,
+ {E1, E2, ArgN} <- lists:zip3(ContractOrSig, ArgTypes, ArgNs),
+ lists:member(ArgN, NoneArgNs),
+ ElementI <- erl_types:t_find_unknown_opaque(E1, E2, Opaques)].
+
+is_opaque_type_test_problem(Fun, Args, ArgTypes, State) ->
+ case Fun of
+ {erlang, FN, 1} when FN =:= is_atom; FN =:= is_boolean;
+ FN =:= is_binary; FN =:= is_bitstring;
+ FN =:= is_float; FN =:= is_function;
+ FN =:= is_integer; FN =:= is_list;
+ FN =:= is_number; FN =:= is_pid; FN =:= is_port;
+ FN =:= is_reference; FN =:= is_tuple;
+ FN =:= is_map ->
+ type_test_opaque_arg(Args, ArgTypes, State#state.opaques);
+ {erlang, FN, 2} when FN =:= is_function ->
+ type_test_opaque_arg(Args, ArgTypes, State#state.opaques);
+ _ -> no
+ end.
+
+type_test_opaque_arg([], [], _Opaques) ->
+ no;
+type_test_opaque_arg([Arg|Args], [ArgType|ArgTypes], Opaques) ->
+ case erl_types:t_has_opaque_subtype(ArgType, Opaques) of
+ true -> {yes, Arg, ArgType};
+ false -> type_test_opaque_arg(Args, ArgTypes, Opaques)
+ end.
+
+expected_arg_triples(ArgNs, ArgTypes, State) ->
+ [begin
+ Arg = lists:nth(N, ArgTypes),
+ {N, Arg, format_type(Arg, State)}
+ end || N <- ArgNs].
+
+add_bif_warnings({erlang, Op, 2}, [T1, T2] = Ts, Tree, State)
+ when Op =:= '=:='; Op =:= '==' ->
+ Opaques = State#state.opaques,
+ Inf = t_inf(T1, T2, Opaques),
+ case
+ t_is_none(Inf) andalso (not any_none(Ts))
+ andalso (not is_int_float_eq_comp(T1, Op, T2, Opaques))
+ of
+ true ->
+ %% Give priority to opaque warning (as usual).
+ case erl_types:t_find_unknown_opaque(T1, T2, Opaques) of
+ [] ->
+ Args = comp_format_args([], T1, Op, T2, State),
+ state__add_warning(State, ?WARN_MATCHING, Tree, {exact_eq, Args});
+ Ns ->
+ Args = comp_format_args(Ns, T1, Op, T2, State),
+ state__add_warning(State, ?WARN_OPAQUE, Tree, {opaque_eq, Args})
+ end;
+ false ->
+ State
+ end;
+add_bif_warnings({erlang, Op, 2}, [T1, T2] = Ts, Tree, State)
+ when Op =:= '=/='; Op =:= '/=' ->
+ Opaques = State#state.opaques,
+ case
+ (not any_none(Ts))
+ andalso (not is_int_float_eq_comp(T1, Op, T2, Opaques))
+ of
+ true ->
+ case erl_types:t_find_unknown_opaque(T1, T2, Opaques) of
+ [] -> State;
+ Ns ->
+ Args = comp_format_args(Ns, T1, Op, T2, State),
+ state__add_warning(State, ?WARN_OPAQUE, Tree, {opaque_neq, Args})
+ end;
+ false ->
+ State
+ end;
+add_bif_warnings(_, _, _, State) ->
+ State.
+
+is_int_float_eq_comp(T1, Op, T2, Opaques) ->
+ (Op =:= '==' orelse Op =:= '/=') andalso
+ ((erl_types:t_is_float(T1, Opaques)
+ andalso t_is_integer(T2, Opaques)) orelse
+ (t_is_integer(T1, Opaques)
+ andalso erl_types:t_is_float(T2, Opaques))).
+
+comp_format_args([1|_], T1, Op, T2, State) ->
+ [format_type(T2, State), Op, format_type(T1, State)];
+comp_format_args(_, T1, Op, T2, State) ->
+ [format_type(T1, State), Op, format_type(T2, State)].
+
+%%----------------------------------------
+
+handle_bitstr(Tree, Map, State) ->
+ %% Construction of binaries.
+ Size = cerl:bitstr_size(Tree),
+ Val = cerl:bitstr_val(Tree),
+ BitstrType = cerl:concrete(cerl:bitstr_type(Tree)),
+ {State1, Map1, SizeType0} = traverse(Size, Map, State),
+ {State2, Map2, ValType0} = traverse(Val, Map1, State1),
+ case cerl:bitstr_bitsize(Tree) of
+ BitSz when BitSz =:= all orelse BitSz =:= utf ->
+ ValType =
+ case BitSz of
+ all ->
+ true = (BitstrType =:= binary),
+ t_inf(ValType0, t_bitstr());
+ utf ->
+ true = lists:member(BitstrType, [utf8, utf16, utf32]),
+ t_inf(ValType0, t_integer())
+ end,
+ Map3 = enter_type(Val, ValType, Map2),
+ case t_is_none(ValType) of
+ true ->
+ Msg = {bin_construction, ["value",
+ format_cerl(Val), format_cerl(Tree),
+ format_type(ValType0, State2)]},
+ State3 = state__add_warning(State2, ?WARN_BIN_CONSTRUCTION, Val, Msg),
+ {State3, Map3, t_none()};
+ false ->
+ {State2, Map3, t_bitstr()}
+ end;
+ BitSz when is_integer(BitSz) orelse BitSz =:= any ->
+ SizeType = t_inf(SizeType0, t_non_neg_integer()),
+ ValType =
+ case BitstrType of
+ binary -> t_inf(ValType0, t_bitstr());
+ float -> t_inf(ValType0, t_number());
+ integer -> t_inf(ValType0, t_integer())
+ end,
+ case any_none([SizeType, ValType]) of
+ true ->
+ {Msg, Offending} =
+ case t_is_none(SizeType) of
+ true ->
+ {{bin_construction,
+ ["size", format_cerl(Size), format_cerl(Tree),
+ format_type(SizeType0, State2)]},
+ Size};
+ false ->
+ {{bin_construction,
+ ["value", format_cerl(Val), format_cerl(Tree),
+ format_type(ValType0, State2)]},
+ Val}
+ end,
+ State3 = state__add_warning(State2, ?WARN_BIN_CONSTRUCTION,
+ Offending, Msg),
+ {State3, Map2, t_none()};
+ false ->
+ UnitVal = cerl:concrete(cerl:bitstr_unit(Tree)),
+ Opaques = State2#state.opaques,
+ NumberVals = t_number_vals(SizeType, Opaques),
+ {State3, Type} =
+ case t_contains_opaque(SizeType, Opaques) of
+ true ->
+ Msg = {opaque_size, [format_type(SizeType, State2),
+ format_cerl(Size)]},
+ {state__add_warning(State2, ?WARN_OPAQUE, Size, Msg),
+ t_none()};
+ false ->
+ case NumberVals of
+ [OneSize] -> {State2, t_bitstr(0, OneSize * UnitVal)};
+ unknown -> {State2, t_bitstr()};
+ _ ->
+ MinSize = erl_types:number_min(SizeType, Opaques),
+ {State2, t_bitstr(UnitVal, UnitVal * MinSize)}
+ end
+ end,
+ Map3 = enter_type_lists([Val, Size, Tree],
+ [ValType, SizeType, Type], Map2),
+ {State3, Map3, Type}
+ end
+ end.
+
+%%----------------------------------------
+
+handle_call(Tree, Map, State) ->
+ M = cerl:call_module(Tree),
+ F = cerl:call_name(Tree),
+ Args = cerl:call_args(Tree),
+ MFAList = [M, F|Args],
+ {State1, Map1, [MType0, FType0|As]} = traverse_list(MFAList, Map, State),
+ Opaques = State#state.opaques,
+ MType = t_inf(t_module(), MType0, Opaques),
+ FType = t_inf(t_atom(), FType0, Opaques),
+ Map2 = enter_type_lists([M, F], [MType, FType], Map1),
+ MOpaque = t_is_none(MType) andalso (not t_is_none(MType0)),
+ FOpaque = t_is_none(FType) andalso (not t_is_none(FType0)),
+ case any_none([MType, FType|As]) of
+ true ->
+ State2 =
+ if
+ MOpaque -> % This is a problem we just detected; not a known one
+ MS = format_cerl(M),
+ case t_is_none(t_inf(t_module(), MType0)) of
+ true ->
+ Msg = {app_call, [MS, format_cerl(F),
+ format_args(Args, As, State1),
+ MS, format_type(t_module(), State1),
+ format_type(MType0, State1)]},
+ state__add_warning(State1, ?WARN_FAILING_CALL, Tree, Msg);
+ false ->
+ Msg = {opaque_call, [MS, format_cerl(F),
+ format_args(Args, As, State1),
+ MS, format_type(MType0, State1)]},
+ state__add_warning(State1, ?WARN_FAILING_CALL, Tree, Msg)
+ end;
+ FOpaque ->
+ FS = format_cerl(F),
+ case t_is_none(t_inf(t_atom(), FType0)) of
+ true ->
+ Msg = {app_call, [format_cerl(M), FS,
+ format_args(Args, As, State1),
+ FS, format_type(t_atom(), State1),
+ format_type(FType0, State1)]},
+ state__add_warning(State1, ?WARN_FAILING_CALL, Tree, Msg);
+ false ->
+ Msg = {opaque_call, [format_cerl(M), FS,
+ format_args(Args, As, State1),
+ FS, format_type(FType0, State1)]},
+ state__add_warning(State1, ?WARN_FAILING_CALL, Tree, Msg)
+ end;
+ true -> State1
+ end,
+ {State2, Map2, t_none()};
+ false ->
+ case t_is_atom(MType) of
+ true ->
+ %% XXX: Consider doing this for all combinations of MF
+ case {t_atom_vals(MType), t_atom_vals(FType)} of
+ {[MAtom], [FAtom]} ->
+ FunInfo = [{remote, state__fun_info({MAtom, FAtom, length(Args)},
+ State1)}],
+ handle_apply_or_call(FunInfo, Args, As, Map2, Tree, State1);
+ {_MAtoms, _FAtoms} ->
+ {State1, Map2, t_any()}
+ end;
+ false ->
+ {State1, Map2, t_any()}
+ end
+ end.
+
+%%----------------------------------------
+
+handle_case(Tree, Map, State) ->
+ Arg = cerl:case_arg(Tree),
+ Clauses = filter_match_fail(cerl:case_clauses(Tree)),
+ {State1, Map1, ArgType} = SMA = traverse(Arg, Map, State),
+ case t_is_none_or_unit(ArgType) of
+ true -> SMA;
+ false ->
+ State2 =
+ case is_race_analysis_enabled(State) of
+ true ->
+ {RaceList, RaceListSize} = get_race_list_and_size(State1),
+ state__renew_race_list([beg_case|RaceList],
+ RaceListSize + 1, State1);
+ false -> State1
+ end,
+ Map2 = join_maps_begin(Map1),
+ {MapList, State3, Type} =
+ handle_clauses(Clauses, Arg, ArgType, ArgType, State2,
+ [], Map2, [], []),
+ Map3 = join_maps_end(MapList, Map2),
+ debug_pp_map(Map3),
+ {State3, Map3, Type}
+ end.
+
+%%----------------------------------------
+
+handle_cons(Tree, Map, State) ->
+ Hd = cerl:cons_hd(Tree),
+ Tl = cerl:cons_tl(Tree),
+ {State1, Map1, HdType} = traverse(Hd, Map, State),
+ {State2, Map2, TlType} = traverse(Tl, Map1, State1),
+ State3 =
+ case t_is_none(t_inf(TlType, t_list(), State2#state.opaques)) of
+ true ->
+ Msg = {improper_list_constr, [format_type(TlType, State2)]},
+ state__add_warning(State2, ?WARN_NON_PROPER_LIST, Tree, Msg);
+ false ->
+ State2
+ end,
+ Type = t_cons(HdType, TlType),
+ {State3, Map2, Type}.
+
+%%----------------------------------------
+
+handle_let(Tree, Map, State) ->
+ IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
+ Arg = cerl:let_arg(Tree),
+ Vars = cerl:let_vars(Tree),
+ {Map0, State0} =
+ case cerl:is_c_var(Arg) of
+ true ->
+ [Var] = Vars,
+ {enter_subst(Var, Arg, Map),
+ case IsRaceAnalysisEnabled of
+ true ->
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
+ state__renew_race_list(
+ [dialyzer_races:let_tag_new(Var, Arg)|RaceList],
+ RaceListSize + 1, State);
+ false -> State
+ end};
+ false -> {Map, State}
+ end,
+ Body = cerl:let_body(Tree),
+ {State1, Map1, ArgTypes} = SMA = traverse(Arg, Map0, State0),
+ State2 =
+ case IsRaceAnalysisEnabled andalso cerl:is_c_call(Arg) of
+ true ->
+ Mod = cerl:call_module(Arg),
+ Name = cerl:call_name(Arg),
+ case cerl:is_literal(Mod) andalso
+ cerl:concrete(Mod) =:= ets andalso
+ cerl:is_literal(Name) andalso
+ cerl:concrete(Name) =:= new of
+ true -> renew_race_public_tables(Vars, State1);
+ false -> State1
+ end;
+ false -> State1
+ end,
+ case t_is_none_or_unit(ArgTypes) of
+ true -> SMA;
+ false ->
+ Map2 = enter_type_lists(Vars, t_to_tlist(ArgTypes), Map1),
+ traverse(Body, Map2, State2)
+ end.
+
+%%----------------------------------------
+
+handle_module(Tree, Map, State) ->
+ %% By not including the variables in scope we can assure that we
+ %% will get the current function type when using the variables.
+ Defs = cerl:module_defs(Tree),
+ PartFun = fun({_Var, Fun}) ->
+ state__is_escaping(get_label(Fun), State)
+ end,
+ {Defs1, Defs2} = lists:partition(PartFun, Defs),
+ Letrec = cerl:c_letrec(Defs1, cerl:c_int(42)),
+ {State1, Map1, _FunTypes} = traverse(Letrec, Map, State),
+ %% Also add environments for the other top-level functions.
+ VarTypes = [{Var, state__fun_type(Fun, State1)} || {Var, Fun} <- Defs],
+ EnvMap = enter_type_list(VarTypes, Map),
+ FoldFun = fun({_Var, Fun}, AccState) ->
+ state__update_fun_env(Fun, EnvMap, AccState)
+ end,
+ State2 = lists:foldl(FoldFun, State1, Defs2),
+ {State2, Map1, t_any()}.
+
+%%----------------------------------------
+
+handle_receive(Tree, Map, State) ->
+ Clauses = filter_match_fail(cerl:receive_clauses(Tree)),
+ Timeout = cerl:receive_timeout(Tree),
+ State1 =
+ case is_race_analysis_enabled(State) of
+ true ->
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
+ state__renew_race_list([beg_case|RaceList],
+ RaceListSize + 1, State);
+ false -> State
+ end,
+ {MapList, State2, ReceiveType} =
+ handle_clauses(Clauses, ?no_arg, t_any(), t_any(), State1, [], Map,
+ [], []),
+ Map1 = join_maps(MapList, Map),
+ {State3, Map2, TimeoutType} = traverse(Timeout, Map1, State2),
+ Opaques = State3#state.opaques,
+ case (t_is_atom(TimeoutType, Opaques) andalso
+ (t_atom_vals(TimeoutType, Opaques) =:= ['infinity'])) of
+ true ->
+ {State3, Map2, ReceiveType};
+ false ->
+ Action = cerl:receive_action(Tree),
+ {State4, Map3, ActionType} = traverse(Action, Map, State3),
+ Map4 = join_maps([Map3, Map1], Map),
+ Type = t_sup(ReceiveType, ActionType),
+ {State4, Map4, Type}
+ end.
+
+%%----------------------------------------
+
+handle_try(Tree, Map, State) ->
+ Arg = cerl:try_arg(Tree),
+ EVars = cerl:try_evars(Tree),
+ Vars = cerl:try_vars(Tree),
+ Body = cerl:try_body(Tree),
+ Handler = cerl:try_handler(Tree),
+ {State1, Map1, ArgType} = traverse(Arg, Map, State),
+ Map2 = mark_as_fresh(Vars, Map1),
+ {SuccState, SuccMap, SuccType} =
+ case bind_pat_vars(Vars, t_to_tlist(ArgType), [], Map2, State1) of
+ {error, _, _, _, _} ->
+ {State1, map__new(), t_none()};
+ {SuccMap1, VarTypes} ->
+ %% Try to bind the argument. Will only succeed if
+ %% it is a simple structured term.
+ SuccMap2 =
+ case bind_pat_vars_reverse([Arg], [t_product(VarTypes)], [],
+ SuccMap1, State1) of
+ {error, _, _, _, _} -> SuccMap1;
+ {SM, _} -> SM
+ end,
+ traverse(Body, SuccMap2, State1)
+ end,
+ ExcMap1 = mark_as_fresh(EVars, Map),
+ {State2, ExcMap2, HandlerType} = traverse(Handler, ExcMap1, SuccState),
+ TryType = t_sup(SuccType, HandlerType),
+ {State2, join_maps([ExcMap2, SuccMap], Map1), TryType}.
+
+%%----------------------------------------
+
+handle_map(Tree,Map,State) ->
+ Pairs = cerl:map_es(Tree),
+ Arg = cerl:map_arg(Tree),
+ {State1, Map1, ArgType} = traverse(Arg, Map, State),
+ ArgType1 = t_inf(t_map(), ArgType),
+ case t_is_none_or_unit(ArgType1) of
+ true ->
+ {State1, Map1, ArgType1};
+ false ->
+ {State2, Map2, TypePairs, ExactKeys} =
+ traverse_map_pairs(Pairs, Map1, State1, t_none(), [], []),
+ InsertPair = fun({KV,assoc,_},Acc) -> erl_types:t_map_put(KV,Acc);
+ ({KV,exact,KVTree},Acc) ->
+ case t_is_none(T=erl_types:t_map_update(KV,Acc)) of
+ true -> throw({none, Acc, KV, KVTree});
+ false -> T
+ end
+ end,
+ try lists:foldl(InsertPair, ArgType1, TypePairs)
+ of ResT ->
+ BindT = t_map([{K, t_any()} || K <- ExactKeys]),
+ case bind_pat_vars_reverse([Arg], [BindT], [], Map2, State2) of
+ {error, _, _, _, _} -> {State2, Map2, ResT};
+ {Map3, _} -> {State2, Map3, ResT}
+ end
+ catch {none, MapType, {K,_}, KVTree} ->
+ Msg2 = {map_update, [format_type(MapType, State2),
+ format_type(K, State2)]},
+ {state__add_warning(State2, ?WARN_MAP_CONSTRUCTION, KVTree, Msg2),
+ Map2, t_none()}
+ end
+ end.
+
+traverse_map_pairs([], Map, State, _ShadowKeys, PairAcc, KeyAcc) ->
+ {State, Map, lists:reverse(PairAcc), KeyAcc};
+traverse_map_pairs([Pair|Pairs], Map, State, ShadowKeys, PairAcc, KeyAcc) ->
+ Key = cerl:map_pair_key(Pair),
+ Val = cerl:map_pair_val(Pair),
+ Op = cerl:map_pair_op(Pair),
+ {State1, Map1, [K,V]} = traverse_list([Key,Val],Map,State),
+ KeyAcc1 =
+ case cerl:is_literal(Op) andalso cerl:concrete(Op) =:= exact andalso
+ t_is_singleton(K, State#state.opaques) andalso
+ t_is_none(t_inf(ShadowKeys, K)) of
+ true -> [K|KeyAcc];
+ false -> KeyAcc
+ end,
+ traverse_map_pairs(Pairs, Map1, State1, t_sup(K, ShadowKeys),
+ [{{K,V},cerl:concrete(Op),Pair}|PairAcc], KeyAcc1).
+
+%%----------------------------------------
+
+handle_tuple(Tree, Map, State) ->
+ Elements = cerl:tuple_es(Tree),
+ {State1, Map1, EsType} = traverse_list(Elements, Map, State),
+ TupleType = t_tuple(EsType),
+ case t_is_none(TupleType) of
+ true ->
+ {State1, Map1, t_none()};
+ false ->
+ %% Let's find out if this is a record
+ case Elements of
+ [Tag|Left] ->
+ case cerl:is_c_atom(Tag) andalso is_literal_record(Tree) of
+ true ->
+ TagVal = cerl:atom_val(Tag),
+ case state__lookup_record(TagVal, length(Left), State1) of
+ error -> {State1, Map1, TupleType};
+ {ok, RecType} ->
+ InfTupleType = t_inf(RecType, TupleType),
+ case t_is_none(InfTupleType) of
+ true ->
+ RecC = format_type(TupleType, State1),
+ FieldDiffs = format_field_diffs(TupleType, State1),
+ Msg = {record_constr, [RecC, FieldDiffs]},
+ State2 = state__add_warning(State1, ?WARN_MATCHING,
+ Tree, Msg),
+ {State2, Map1, t_none()};
+ false ->
+ case bind_pat_vars(Elements, t_tuple_args(RecType),
+ [], Map1, State1) of
+ {error, bind, ErrorPat, ErrorType, _} ->
+ Msg = {record_constr,
+ [TagVal, format_patterns(ErrorPat),
+ format_type(ErrorType, State1)]},
+ State2 = state__add_warning(State1, ?WARN_MATCHING,
+ Tree, Msg),
+ {State2, Map1, t_none()};
+ {error, opaque, ErrorPat, ErrorType, OpaqueType} ->
+ Msg = {opaque_match,
+ [format_patterns(ErrorPat),
+ format_type(ErrorType, State1),
+ format_type(OpaqueType, State1)]},
+ State2 = state__add_warning(State1, ?WARN_OPAQUE,
+ Tree, Msg),
+ {State2, Map1, t_none()};
+ {Map2, ETypes} ->
+ {State1, Map2, t_tuple(ETypes)}
+ end
+ end
+ end;
+ false ->
+ {State1, Map1, t_tuple(EsType)}
+ end;
+ [] ->
+ {State1, Map1, t_tuple([])}
+ end
+ end.
+
+%%----------------------------------------
+%% Clauses
+%%
+handle_clauses([C|Left], Arg, ArgType, OrigArgType, State, CaseTypes, MapIn,
+ Acc, ClauseAcc) ->
+ IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
+ State1 =
+ case IsRaceAnalysisEnabled of
+ true ->
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
+ state__renew_race_list(
+ [dialyzer_races:beg_clause_new(Arg, cerl:clause_pats(C),
+ cerl:clause_guard(C))|
+ RaceList], RaceListSize + 1,
+ State);
+ false -> State
+ end,
+ {State2, ClauseMap, BodyType, NewArgType} =
+ do_clause(C, Arg, ArgType, OrigArgType, MapIn, State1),
+ {NewClauseAcc, State3} =
+ case IsRaceAnalysisEnabled of
+ true ->
+ {RaceList1, RaceListSize1} = get_race_list_and_size(State2),
+ EndClause = dialyzer_races:end_clause_new(Arg, cerl:clause_pats(C),
+ cerl:clause_guard(C)),
+ {[EndClause|ClauseAcc],
+ state__renew_race_list([EndClause|RaceList1],
+ RaceListSize1 + 1, State2)};
+ false -> {ClauseAcc, State2}
+ end,
+ {NewCaseTypes, NewAcc} =
+ case t_is_none(BodyType) of
+ true -> {CaseTypes, Acc};
+ false -> {[BodyType|CaseTypes], [ClauseMap|Acc]}
+ end,
+ handle_clauses(Left, Arg, NewArgType, OrigArgType, State3,
+ NewCaseTypes, MapIn, NewAcc, NewClauseAcc);
+handle_clauses([], _Arg, _ArgType, _OrigArgType, State, CaseTypes, _MapIn, Acc,
+ ClauseAcc) ->
+ State1 =
+ case is_race_analysis_enabled(State) of
+ true ->
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
+ state__renew_race_list(
+ [dialyzer_races:end_case_new(ClauseAcc)|RaceList],
+ RaceListSize + 1, State);
+ false -> State
+ end,
+ {lists:reverse(Acc), State1, t_sup(CaseTypes)}.
+
+do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
+ Pats = cerl:clause_pats(C),
+ Guard = cerl:clause_guard(C),
+ Body = cerl:clause_body(C),
+ State1 =
+ case is_race_analysis_enabled(State) of
+ true ->
+ state__renew_fun_args(Pats, State);
+ false -> State
+ end,
+ Map0 = mark_as_fresh(Pats, Map),
+ Map1 = if Arg =:= ?no_arg -> Map0;
+ true -> bind_subst(Arg, Pats, Map0)
+ end,
+ BindRes =
+ case t_is_none(ArgType0) of
+ true ->
+ {error, bind, Pats, ArgType0, ArgType0};
+ false ->
+ ArgTypes =
+ case t_is_any(ArgType0) of
+ true -> [ArgType0 || _ <- Pats];
+ false -> t_to_tlist(ArgType0)
+ end,
+ bind_pat_vars(Pats, ArgTypes, [], Map1, State1)
+ end,
+ case BindRes of
+ {error, ErrorType, NewPats, Type, OpaqueTerm} ->
+ ?debug("Failed binding pattern: ~s\nto ~s\n",
+ [cerl_prettypr:format(C), format_type(ArgType0, State1)]),
+ case state__warning_mode(State1) of
+ false ->
+ {State1, Map, t_none(), ArgType0};
+ true ->
+ {Msg, Force} =
+ case t_is_none(ArgType0) of
+ true ->
+ PatString = format_patterns(Pats),
+ PatTypes = [PatString, format_type(OrigArgType, State1)],
+ %% See if this is covered by an earlier clause or if it
+ %% simply cannot match
+ OrigArgTypes =
+ case t_is_any(OrigArgType) of
+ true -> Any = t_any(), [Any || _ <- Pats];
+ false -> t_to_tlist(OrigArgType)
+ end,
+ Tag =
+ case bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1) of
+ {error, bind, _, _, _} -> pattern_match;
+ {error, record, _, _, _} -> record_match;
+ {error, opaque, _, _, _} -> opaque_match;
+ {_, _} -> pattern_match_cov
+ end,
+ {{Tag, PatTypes}, false};
+ false ->
+ %% Try to find out if this is a default clause in a list
+ %% comprehension and supress this. A real Hack(tm)
+ Force0 =
+ case is_compiler_generated(cerl:get_ann(C)) of
+ true ->
+ case Pats of
+ [Pat] ->
+ case cerl:is_c_cons(Pat) of
+ true ->
+ not (cerl:is_c_var(cerl:cons_hd(Pat)) andalso
+ cerl:is_c_var(cerl:cons_tl(Pat)) andalso
+ cerl:is_literal(Guard) andalso
+ (cerl:concrete(Guard) =:= true));
+ false ->
+ true
+ end;
+ [Pat0, Pat1] -> % binary comprehension
+ case cerl:is_c_cons(Pat0) of
+ true ->
+ not (cerl:is_c_var(cerl:cons_hd(Pat0)) andalso
+ cerl:is_c_var(cerl:cons_tl(Pat0)) andalso
+ cerl:is_c_var(Pat1) andalso
+ cerl:is_literal(Guard) andalso
+ (cerl:concrete(Guard) =:= true));
+ false ->
+ true
+ end;
+ _ -> true
+ end;
+ false ->
+ true
+ end,
+ PatString =
+ case ErrorType of
+ bind -> format_patterns(Pats);
+ record -> format_patterns(NewPats);
+ opaque -> format_patterns(NewPats)
+ end,
+ PatTypes = case ErrorType of
+ bind -> [PatString, format_type(ArgType0, State1)];
+ record -> [PatString, format_type(Type, State1)];
+ opaque -> [PatString, format_type(Type, State1),
+ format_type(OpaqueTerm, State1)]
+ end,
+ FailedTag = case ErrorType of
+ bind -> pattern_match;
+ record -> record_match;
+ opaque -> opaque_match
+ end,
+ {{FailedTag, PatTypes}, Force0}
+ end,
+ WarnType = case Msg of
+ {opaque_match, _} -> ?WARN_OPAQUE;
+ {pattern_match, _} -> ?WARN_MATCHING;
+ {record_match, _} -> ?WARN_MATCHING;
+ {pattern_match_cov, _} -> ?WARN_MATCHING
+ end,
+ {state__add_warning(State1, WarnType, C, Msg, Force),
+ Map, t_none(), ArgType0}
+ end;
+ {Map2, PatTypes} ->
+ Map3 =
+ case Arg =:= ?no_arg of
+ true -> Map2;
+ false ->
+ %% Try to bind the argument. Will only succeed if
+ %% it is a simple structured term.
+ case bind_pat_vars_reverse([Arg], [t_product(PatTypes)],
+ [], Map2, State1) of
+ {error, _, _, _, _} -> Map2;
+ {NewMap, _} -> NewMap
+ end
+ end,
+ NewArgType =
+ case Arg =:= ?no_arg of
+ true -> ArgType0;
+ false ->
+ GenType = dialyzer_typesig:get_safe_underapprox(Pats, Guard),
+ t_subtract(t_product(t_to_tlist(ArgType0)), GenType)
+ end,
+ case bind_guard(Guard, Map3, State1) of
+ {error, Reason} ->
+ ?debug("Failed guard: ~s\n",
+ [cerl_prettypr:format(C, [{hook, cerl_typean:pp_hook()}])]),
+ PatString = format_patterns(Pats),
+ DefaultMsg =
+ case Pats =:= [] of
+ true -> {guard_fail, []};
+ false ->
+ {guard_fail_pat, [PatString, format_type(ArgType0, State1)]}
+ end,
+ State2 =
+ case Reason of
+ none -> state__add_warning(State1, ?WARN_MATCHING, C, DefaultMsg);
+ {FailGuard, Msg} ->
+ case is_compiler_generated(cerl:get_ann(FailGuard)) of
+ false ->
+ WarnType = case Msg of
+ {guard_fail, _} -> ?WARN_MATCHING;
+ {neg_guard_fail, _} -> ?WARN_MATCHING;
+ {opaque_guard, _} -> ?WARN_OPAQUE
+ end,
+ state__add_warning(State1, WarnType, FailGuard, Msg);
+ true ->
+ state__add_warning(State1, ?WARN_MATCHING, C, Msg)
+ end
+ end,
+ {State2, Map, t_none(), NewArgType};
+ Map4 ->
+ {RetState, RetMap, BodyType} = traverse(Body, Map4, State1),
+ {RetState, RetMap, BodyType, NewArgType}
+ end
+ end.
+
+bind_subst(Arg, Pats, Map) ->
+ case cerl:type(Arg) of
+ values ->
+ bind_subst_list(cerl:values_es(Arg), Pats, Map);
+ var ->
+ [Pat] = Pats,
+ enter_subst(Arg, Pat, Map);
+ _ ->
+ Map
+ end.
+
+bind_subst_list([Arg|ArgLeft], [Pat|PatLeft], Map) ->
+ NewMap =
+ case {cerl:type(Arg), cerl:type(Pat)} of
+ {var, var} -> enter_subst(Arg, Pat, Map);
+ {var, alias} -> enter_subst(Arg, cerl:alias_pat(Pat), Map);
+ {literal, literal} -> Map;
+ {T, T} -> bind_subst_list(lists:flatten(cerl:subtrees(Arg)),
+ lists:flatten(cerl:subtrees(Pat)),
+ Map);
+ _ -> Map
+ end,
+ bind_subst_list(ArgLeft, PatLeft, NewMap);
+bind_subst_list([], [], Map) ->
+ Map.
+
+%%----------------------------------------
+%% Patterns
+%%
+
+bind_pat_vars(Pats, Types, Acc, Map, State) ->
+ try
+ bind_pat_vars(Pats, Types, Acc, Map, State, false)
+ catch
+ throw:Error ->
+ %% Error = {error, bind | opaque | record, ErrorPats, ErrorType}
+ Error
+ end.
+
+bind_pat_vars_reverse(Pats, Types, Acc, Map, State) ->
+ try
+ bind_pat_vars(Pats, Types, Acc, Map, State, true)
+ catch
+ throw:Error ->
+ %% Error = {error, bind | opaque | record, ErrorPats, ErrorType}
+ Error
+ end.
+
+bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) ->
+ ?debug("Binding pat: ~w to ~s\n", [cerl:type(Pat), format_type(Type, State)]
+),
+ Opaques = State#state.opaques,
+ {NewMap, TypeOut} =
+ case cerl:type(Pat) of
+ alias ->
+ %% Map patterns are more allowing than the type of their literal. We
+ %% must unfold AliasPat if it is a literal.
+ AliasPat = dialyzer_utils:refold_pattern(cerl:alias_pat(Pat)),
+ Var = cerl:alias_var(Pat),
+ Map1 = enter_subst(Var, AliasPat, Map),
+ {Map2, [PatType]} = bind_pat_vars([AliasPat], [Type], [],
+ Map1, State, Rev),
+ {enter_type(Var, PatType, Map2), PatType};
+ binary ->
+ %% Cannot bind the binary if we are in reverse match since
+ %% binary patterns and binary construction are not symmetric.
+ case Rev of
+ true -> {Map, t_bitstr()};
+ false ->
+ BinType = t_inf(t_bitstr(), Type, Opaques),
+ case t_is_none(BinType) of
+ true ->
+ case t_find_opaque_mismatch(t_bitstr(), Type, Opaques) of
+ {ok, T1, T2} ->
+ bind_error([Pat], T1, T2, opaque);
+ error ->
+ bind_error([Pat], Type, t_none(), bind)
+ end;
+ false ->
+ Segs = cerl:binary_segments(Pat),
+ {Map1, SegTypes} = bind_bin_segs(Segs, BinType, Map, State),
+ {Map1, t_bitstr_concat(SegTypes)}
+ end
+ end;
+ cons ->
+ Cons = t_inf(Type, t_cons(), Opaques),
+ case t_is_none(Cons) of
+ true ->
+ bind_opaque_pats(t_cons(), Type, Pat, State);
+ false ->
+ {Map1, [HdType, TlType]} =
+ bind_pat_vars([cerl:cons_hd(Pat), cerl:cons_tl(Pat)],
+ [t_cons_hd(Cons, Opaques),
+ t_cons_tl(Cons, Opaques)],
+ [], Map, State, Rev),
+ {Map1, t_cons(HdType, TlType)}
+ end;
+ literal ->
+ Pat0 = dialyzer_utils:refold_pattern(Pat),
+ case cerl:is_literal(Pat0) of
+ true ->
+ Literal = literal_type(Pat),
+ case t_is_none(t_inf(Literal, Type, Opaques)) of
+ true ->
+ bind_opaque_pats(Literal, Type, Pat, State);
+ false -> {Map, Literal}
+ end;
+ false ->
+ %% Retry with the unfolded pattern
+ {Map1, [PatType]}
+ = bind_pat_vars([Pat0], [Type], [], Map, State, Rev),
+ {Map1, PatType}
+ end;
+ map ->
+ MapT = t_inf(Type, t_map(), Opaques),
+ case t_is_none(MapT) of
+ true ->
+ bind_opaque_pats(t_map(), Type, Pat, State);
+ false ->
+ case Rev of
+ %% TODO: Reverse matching (propagating a matched subset back to a value)
+ true -> {Map, MapT};
+ false ->
+ FoldFun =
+ fun(Pair, {MapAcc, ListAcc}) ->
+ %% Only exact (:=) can appear in patterns
+ exact = cerl:concrete(cerl:map_pair_op(Pair)),
+ Key = cerl:map_pair_key(Pair),
+ KeyType =
+ case cerl:type(Key) of
+ var ->
+ case state__lookup_type_for_letrec(Key, State) of
+ error -> lookup_type(Key, MapAcc);
+ {ok, RecType} -> RecType
+ end;
+ literal ->
+ literal_type(Key)
+ end,
+ Bind = erl_types:t_map_get(KeyType, MapT),
+ {MapAcc1, [ValType]} =
+ bind_pat_vars([cerl:map_pair_val(Pair)],
+ [Bind], [], MapAcc, State, Rev),
+ case t_is_singleton(KeyType, Opaques) of
+ true -> {MapAcc1, [{KeyType, ValType}|ListAcc]};
+ false -> {MapAcc1, ListAcc}
+ end
+ end,
+ {Map1, Pairs} = lists:foldl(FoldFun, {Map, []}, cerl:map_es(Pat)),
+ {Map1, t_inf(MapT, t_map(Pairs))}
+ end
+ end;
+ tuple ->
+ Es = cerl:tuple_es(Pat),
+ {TypedRecord, Prototype} =
+ case Es of
+ [] -> {false, t_tuple([])};
+ [Tag|Left] ->
+ case cerl:is_c_atom(Tag) andalso is_literal_record(Pat) of
+ true ->
+ TagAtom = cerl:atom_val(Tag),
+ case state__lookup_record(TagAtom, length(Left), State) of
+ error -> {false, t_tuple(length(Es))};
+ {ok, Record} ->
+ [_Head|AnyTail] = [t_any() || _ <- Es],
+ UntypedRecord = t_tuple([t_atom(TagAtom)|AnyTail]),
+ {not t_is_equal(Record, UntypedRecord), Record}
+ end;
+ false -> {false, t_tuple(length(Es))}
+ end
+ end,
+ Tuple = t_inf(Prototype, Type, Opaques),
+ case t_is_none(Tuple) of
+ true ->
+ bind_opaque_pats(Prototype, Type, Pat, State);
+ false ->
+ SubTuples = t_tuple_subtypes(Tuple, Opaques),
+ %% Need to call the top function to get the try-catch wrapper
+ MapJ = join_maps_begin(Map),
+ Results =
+ case Rev of
+ true ->
+ [bind_pat_vars_reverse(Es, t_tuple_args(SubTuple, Opaques),
+ [], MapJ, State)
+ || SubTuple <- SubTuples];
+ false ->
+ [bind_pat_vars(Es, t_tuple_args(SubTuple, Opaques), [],
+ MapJ, State)
+ || SubTuple <- SubTuples]
+ end,
+ case lists:keyfind(opaque, 2, Results) of
+ {error, opaque, _PatList, _Type, Opaque} ->
+ bind_error([Pat], Tuple, Opaque, opaque);
+ false ->
+ case [M || {M, _} <- Results, M =/= error] of
+ [] ->
+ case TypedRecord of
+ true -> bind_error([Pat], Tuple, Prototype, record);
+ false -> bind_error([Pat], Tuple, t_none(), bind)
+ end;
+ Maps ->
+ Map1 = join_maps_end(Maps, MapJ),
+ TupleType = t_sup([t_tuple(EsTypes)
+ || {M, EsTypes} <- Results, M =/= error]),
+ {Map1, TupleType}
+ end
+ end
+ end;
+ values ->
+ Es = cerl:values_es(Pat),
+ {Map1, EsTypes} =
+ bind_pat_vars(Es, t_to_tlist(Type), [], Map, State, Rev),
+ {Map1, t_product(EsTypes)};
+ var ->
+ VarType1 =
+ case state__lookup_type_for_letrec(Pat, State) of
+ error -> lookup_type(Pat, Map);
+ {ok, RecType} -> RecType
+ end,
+ %% Must do inf when binding args to pats. Vars in pats are fresh.
+ VarType2 = t_inf(VarType1, Type, Opaques),
+ case t_is_none(VarType2) of
+ true ->
+ case t_find_opaque_mismatch(VarType1, Type, Opaques) of
+ {ok, T1, T2} ->
+ bind_error([Pat], T1, T2, opaque);
+ error ->
+ bind_error([Pat], Type, t_none(), bind)
+ end;
+ false ->
+ Map1 = enter_type(Pat, VarType2, Map),
+ {Map1, VarType2}
+ end;
+ _Other ->
+ %% Catch all is needed when binding args to pats
+ ?debug("Failed match for ~p\n", [_Other]),
+ bind_error([Pat], Type, t_none(), bind)
+ end,
+ bind_pat_vars(PatLeft, TypeLeft, [TypeOut|Acc], NewMap, State, Rev);
+bind_pat_vars([], [], Acc, Map, _State, _Rev) ->
+ {Map, lists:reverse(Acc)}.
+
+bind_bin_segs(BinSegs, BinType, Map, State) ->
+ bind_bin_segs(BinSegs, BinType, [], Map, State).
+
+bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) ->
+ Val = cerl:bitstr_val(Seg),
+ SegType = cerl:concrete(cerl:bitstr_type(Seg)),
+ UnitVal = cerl:concrete(cerl:bitstr_unit(Seg)),
+ case cerl:bitstr_bitsize(Seg) of
+ all ->
+ binary = SegType, [] = Segs, %% just an assert
+ T = t_inf(t_bitstr(UnitVal, 0), BinType),
+ {Map1, [Type]} = bind_pat_vars([Val], [T], [], Map, State, false),
+ Type1 = remove_local_opaque_types(Type, State#state.opaques),
+ bind_bin_segs(Segs, t_bitstr(0, 0), [Type1|Acc], Map1, State);
+ utf -> % XXX: possibly can be strengthened
+ true = lists:member(SegType, [utf8, utf16, utf32]),
+ {Map1, [_]} = bind_pat_vars([Val], [t_integer()], [], Map, State, false),
+ Type = t_binary(),
+ bind_bin_segs(Segs, BinType, [Type|Acc], Map1, State);
+ BitSz when is_integer(BitSz) orelse BitSz =:= any ->
+ Size = cerl:bitstr_size(Seg),
+ {Map1, [SizeType]} =
+ bind_pat_vars([Size], [t_non_neg_integer()], [], Map, State, false),
+ Opaques = State#state.opaques,
+ NumberVals = t_number_vals(SizeType, Opaques),
+ case t_contains_opaque(SizeType, Opaques) of
+ true -> bind_error([Seg], SizeType, t_none(), opaque);
+ false -> ok
+ end,
+ Type =
+ case NumberVals of
+ [OneSize] -> t_bitstr(0, UnitVal * OneSize);
+ _ -> % 'unknown' too
+ MinSize = erl_types:number_min(SizeType, Opaques),
+ t_bitstr(UnitVal, UnitVal * MinSize)
+ end,
+ ValConstr =
+ case SegType of
+ binary -> Type; %% The same constraints as for the whole bitstr
+ float -> t_float();
+ integer ->
+ case NumberVals of
+ unknown -> t_integer();
+ List ->
+ SizeVal = lists:max(List),
+ Flags = cerl:concrete(cerl:bitstr_flags(Seg)),
+ N = SizeVal * UnitVal,
+ case N >= ?BITS of
+ true ->
+ case lists:member(signed, Flags) of
+ true -> t_from_range(neg_inf, pos_inf);
+ false -> t_from_range(0, pos_inf)
+ end;
+ false ->
+ case lists:member(signed, Flags) of
+ true -> t_from_range(-(1 bsl (N - 1)), 1 bsl (N - 1) - 1);
+ false -> t_from_range(0, 1 bsl N - 1)
+ end
+ end
+ end
+ end,
+ {Map2, [_]} = bind_pat_vars([Val], [ValConstr], [], Map1, State, false),
+ NewBinType = t_bitstr_match(Type, BinType),
+ case t_is_none(NewBinType) of
+ true -> bind_error([Seg], BinType, t_none(), bind);
+ false -> bind_bin_segs(Segs, NewBinType, [Type|Acc], Map2, State)
+ end
+ end;
+bind_bin_segs([], _BinType, Acc, Map, _State) ->
+ {Map, lists:reverse(Acc)}.
+
+bind_error(Pats, Type, OpaqueType, Error0) ->
+ Error = case {Error0, Pats} of
+ {bind, [Pat]} ->
+ case is_literal_record(Pat) of
+ true -> record;
+ false -> Error0
+ end;
+ _ -> Error0
+ end,
+ throw({error, Error, Pats, Type, OpaqueType}).
+
+-spec bind_opaque_pats(type(), type(), cerl:c_literal(), state()) ->
+ no_return().
+
+bind_opaque_pats(GenType, Type, Pat, State) ->
+ case t_find_opaque_mismatch(GenType, Type, State#state.opaques) of
+ {ok, T1, T2} ->
+ bind_error([Pat], T1, T2, opaque);
+ error ->
+ bind_error([Pat], Type, t_none(), bind)
+ end.
+
+%%----------------------------------------
+%% Guards
+%%
+
+bind_guard(Guard, Map, State) ->
+ try bind_guard(Guard, Map, maps:new(), pos, State) of
+ {Map1, _Type} -> Map1
+ catch
+ throw:{fail, Warning} -> {error, Warning};
+ throw:{fatal_fail, Warning} -> {error, Warning}
+ end.
+
+bind_guard(Guard, Map, Env, Eval, State) ->
+ ?debug("Handling ~w guard: ~s\n",
+ [Eval, cerl_prettypr:format(Guard, [{noann, true}])]),
+ case cerl:type(Guard) of
+ binary ->
+ {Map, t_binary()};
+ 'case' ->
+ Arg = cerl:case_arg(Guard),
+ Clauses = cerl:case_clauses(Guard),
+ bind_guard_case_clauses(Arg, Clauses, Map, Env, Eval, State);
+ cons ->
+ Hd = cerl:cons_hd(Guard),
+ Tl = cerl:cons_tl(Guard),
+ {Map1, HdType} = bind_guard(Hd, Map, Env, dont_know, State),
+ {Map2, TlType} = bind_guard(Tl, Map1, Env, dont_know, State),
+ {Map2, t_cons(HdType, TlType)};
+ literal ->
+ {Map, literal_type(Guard)};
+ 'try' ->
+ Arg = cerl:try_arg(Guard),
+ [Var] = cerl:try_vars(Guard),
+ EVars = cerl:try_evars(Guard),
+ %%?debug("Storing: ~w\n", [Var]),
+ Map1 = join_maps_begin(Map),
+ Map2 = mark_as_fresh(EVars, Map1),
+ %% Visit handler first so we know if it should be ignored
+ {{HandlerMap, HandlerType}, HandlerE} =
+ try {bind_guard(cerl:try_handler(Guard), Map2, Env, Eval, State), none}
+ catch throw:HE ->
+ {{Map2, t_none()}, HE}
+ end,
+ BodyEnv = maps:put(get_label(Var), Arg, Env),
+ Wanted = case Eval of pos -> t_atom(true); neg -> t_atom(false);
+ dont_know -> t_any() end,
+ case t_is_none(t_inf(HandlerType, Wanted)) of
+ %% Handler won't save us; pretend it does not exist
+ true -> bind_guard(cerl:try_body(Guard), Map, BodyEnv, Eval, State);
+ false ->
+ {{BodyMap, BodyType}, BodyE} =
+ try {bind_guard(cerl:try_body(Guard), Map1, BodyEnv,
+ Eval, State), none}
+ catch throw:BE ->
+ {{Map1, t_none()}, BE}
+ end,
+ Map3 = join_maps_end([BodyMap, HandlerMap], Map1),
+ case t_is_none(Sup = t_sup(BodyType, HandlerType)) of
+ true ->
+ %% Pick a reason. N.B. We assume that the handler is always
+ %% compiler-generated if the body is; that way, we won't need to
+ %% check.
+ Fatality = case {BodyE, HandlerE} of
+ {{fatal_fail, _}, _} -> fatal_fail;
+ {_, {fatal_fail, _}} -> fatal_fail;
+ _ -> fail
+ end,
+ throw({Fatality,
+ case {BodyE, HandlerE} of
+ {{_, Rsn}, _} when Rsn =/= none -> Rsn;
+ {_, {_,Rsn}} -> Rsn;
+ _ -> none
+ end});
+ false -> {Map3, Sup}
+ end
+ end;
+ tuple ->
+ Es0 = cerl:tuple_es(Guard),
+ {Map1, Es} = bind_guard_list(Es0, Map, Env, dont_know, State),
+ {Map1, t_tuple(Es)};
+ map ->
+ case Eval of
+ dont_know -> handle_guard_map(Guard, Map, Env, State);
+ _PosOrNeg -> {Map, t_none()} %% Map exprs do not produce bools
+ end;
+ 'let' ->
+ Arg = cerl:let_arg(Guard),
+ [Var] = cerl:let_vars(Guard),
+ %%?debug("Storing: ~w\n", [Var]),
+ NewEnv = maps:put(get_label(Var), Arg, Env),
+ bind_guard(cerl:let_body(Guard), Map, NewEnv, Eval, State);
+ values ->
+ Es = cerl:values_es(Guard),
+ List = [bind_guard(V, Map, Env, dont_know, State) || V <- Es],
+ Type = t_product([T || {_, T} <- List]),
+ {Map, Type};
+ var ->
+ ?debug("Looking for var(~w)...", [cerl_trees:get_label(Guard)]),
+ case maps:find(get_label(Guard), Env) of
+ error ->
+ ?debug("Did not find it\n", []),
+ Type = lookup_type(Guard, Map),
+ Constr =
+ case Eval of
+ pos -> t_atom(true);
+ neg -> t_atom(false);
+ dont_know -> Type
+ end,
+ Inf = t_inf(Constr, Type),
+ {enter_type(Guard, Inf, Map), Inf};
+ {ok, Tree} ->
+ ?debug("Found it\n", []),
+ {Map1, Type} = bind_guard(Tree, Map, Env, Eval, State),
+ {enter_type(Guard, Type, Map1), Type}
+ end;
+ call ->
+ handle_guard_call(Guard, Map, Env, Eval, State)
+ end.
+
+handle_guard_call(Guard, Map, Env, Eval, State) ->
+ MFA = {cerl:atom_val(cerl:call_module(Guard)),
+ cerl:atom_val(cerl:call_name(Guard)),
+ cerl:call_arity(Guard)},
+ case MFA of
+ {erlang, F, 1} when F =:= is_atom; F =:= is_boolean;
+ F =:= is_binary; F =:= is_bitstring;
+ F =:= is_float; F =:= is_function;
+ F =:= is_integer; F =:= is_list; F =:= is_map;
+ F =:= is_number; F =:= is_pid; F =:= is_port;
+ F =:= is_reference; F =:= is_tuple ->
+ handle_guard_type_test(Guard, F, Map, Env, Eval, State);
+ {erlang, is_function, 2} ->
+ handle_guard_is_function(Guard, Map, Env, Eval, State);
+ MFA when (MFA =:= {erlang, internal_is_record, 3}) or
+ (MFA =:= {erlang, is_record, 3}) ->
+ handle_guard_is_record(Guard, Map, Env, Eval, State);
+ {erlang, '=:=', 2} ->
+ handle_guard_eqeq(Guard, Map, Env, Eval, State);
+ {erlang, '==', 2} ->
+ handle_guard_eq(Guard, Map, Env, Eval, State);
+ {erlang, 'and', 2} ->
+ handle_guard_and(Guard, Map, Env, Eval, State);
+ {erlang, 'or', 2} ->
+ handle_guard_or(Guard, Map, Env, Eval, State);
+ {erlang, 'not', 1} ->
+ handle_guard_not(Guard, Map, Env, Eval, State);
+ {erlang, Comp, 2} when Comp =:= '<'; Comp =:= '=<';
+ Comp =:= '>'; Comp =:= '>=' ->
+ handle_guard_comp(Guard, Comp, Map, Env, Eval, State);
+ _ ->
+ handle_guard_gen_fun(MFA, Guard, Map, Env, Eval, State)
+ end.
+
+handle_guard_gen_fun({M, F, A}, Guard, Map, Env, Eval, State) ->
+ Args = cerl:call_args(Guard),
+ {Map1, As} = bind_guard_list(Args, Map, Env, dont_know, State),
+ Opaques = State#state.opaques,
+ BifRet = erl_bif_types:type(M, F, A, As, Opaques),
+ case t_is_none(BifRet) of
+ true ->
+ %% Is this an error-bif?
+ case t_is_none(erl_bif_types:type(M, F, A)) of
+ true -> signal_guard_fail(Eval, Guard, As, State);
+ false -> signal_guard_fatal_fail(Eval, Guard, As, State)
+ end;
+ false ->
+ BifArgs = bif_args(M, F, A),
+ Map2 = enter_type_lists(Args, t_inf_lists(BifArgs, As, Opaques), Map1),
+ Ret =
+ case Eval of
+ pos -> t_inf(t_atom(true), BifRet);
+ neg -> t_inf(t_atom(false), BifRet);
+ dont_know -> BifRet
+ end,
+ case t_is_none(Ret) of
+ true ->
+ case Eval =:= pos of
+ true -> signal_guard_fail(Eval, Guard, As, State);
+ false -> throw({fail, none})
+ end;
+ false -> {Map2, Ret}
+ end
+ end.
+
+handle_guard_type_test(Guard, F, Map, Env, Eval, State) ->
+ [Arg] = cerl:call_args(Guard),
+ {Map1, ArgType} = bind_guard(Arg, Map, Env, dont_know, State),
+ case bind_type_test(Eval, F, ArgType, State) of
+ error ->
+ ?debug("Type test: ~w failed\n", [F]),
+ signal_guard_fail(Eval, Guard, [ArgType], State);
+ {ok, NewArgType, Ret} ->
+ ?debug("Type test: ~w succeeded, NewType: ~s, Ret: ~s\n",
+ [F, t_to_string(NewArgType), t_to_string(Ret)]),
+ {enter_type(Arg, NewArgType, Map1), Ret}
+ end.
+
+bind_type_test(Eval, TypeTest, ArgType, State) ->
+ Type = case TypeTest of
+ is_atom -> t_atom();
+ is_boolean -> t_boolean();
+ is_binary -> t_binary();
+ is_bitstring -> t_bitstr();
+ is_float -> t_float();
+ is_function -> t_fun();
+ is_integer -> t_integer();
+ is_list -> t_maybe_improper_list();
+ is_map -> t_map();
+ is_number -> t_number();
+ is_pid -> t_pid();
+ is_port -> t_port();
+ is_reference -> t_reference();
+ is_tuple -> t_tuple()
+ end,
+ case Eval of
+ pos ->
+ Inf = t_inf(Type, ArgType, State#state.opaques),
+ case t_is_none(Inf) of
+ true -> error;
+ false -> {ok, Inf, t_atom(true)}
+ end;
+ neg ->
+ Sub = t_subtract(ArgType, Type),
+ case t_is_none(Sub) of
+ true -> error;
+ false -> {ok, Sub, t_atom(false)}
+ end;
+ dont_know ->
+ {ok, ArgType, t_boolean()}
+ end.
+
+handle_guard_comp(Guard, Comp, Map, Env, Eval, State) ->
+ Args = cerl:call_args(Guard),
+ [Arg1, Arg2] = Args,
+ {Map1, ArgTypes} = bind_guard_list(Args, Map, Env, dont_know, State),
+ Opaques = State#state.opaques,
+ [Type1, Type2] = ArgTypes,
+ IsInt1 = t_is_integer(Type1, Opaques),
+ IsInt2 = t_is_integer(Type2, Opaques),
+ case {type(Arg1), type(Arg2)} of
+ {{literal, Lit1}, {literal, Lit2}} ->
+ case erlang:Comp(cerl:concrete(Lit1), cerl:concrete(Lit2)) of
+ true when Eval =:= pos -> {Map, t_atom(true)};
+ true when Eval =:= dont_know -> {Map, t_atom(true)};
+ true when Eval =:= neg -> {Map, t_atom(true)};
+ false when Eval =:= pos ->
+ signal_guard_fail(Eval, Guard, ArgTypes, State);
+ false when Eval =:= dont_know -> {Map, t_atom(false)};
+ false when Eval =:= neg -> {Map, t_atom(false)}
+ end;
+ {{literal, Lit1}, var} when IsInt1 andalso IsInt2 andalso (Eval =:= pos) ->
+ case bind_comp_literal_var(Lit1, Arg2, Type2, Comp, Map1, Opaques) of
+ error -> signal_guard_fail(Eval, Guard, ArgTypes, State);
+ {ok, NewMap} -> {NewMap, t_atom(true)}
+ end;
+ {var, {literal, Lit2}} when IsInt1 andalso IsInt2 andalso (Eval =:= pos) ->
+ case bind_comp_literal_var(Lit2, Arg1, Type1, invert_comp(Comp),
+ Map1, Opaques) of
+ error -> signal_guard_fail(Eval, Guard, ArgTypes, State);
+ {ok, NewMap} -> {NewMap, t_atom(true)}
+ end;
+ {_, _} ->
+ handle_guard_gen_fun({erlang, Comp, 2}, Guard, Map, Env, Eval, State)
+ end.
+
+invert_comp('=<') -> '>=';
+invert_comp('<') -> '>';
+invert_comp('>=') -> '=<';
+invert_comp('>') -> '<'.
+
+bind_comp_literal_var(Lit, Var, VarType, CompOp, Map, Opaques) ->
+ LitVal = cerl:concrete(Lit),
+ NewVarType =
+ case t_number_vals(VarType, Opaques) of
+ unknown ->
+ Range =
+ case CompOp of
+ '=<' -> t_from_range(LitVal, pos_inf);
+ '<' -> t_from_range(LitVal + 1, pos_inf);
+ '>=' -> t_from_range(neg_inf, LitVal);
+ '>' -> t_from_range(neg_inf, LitVal - 1)
+ end,
+ t_inf(Range, VarType, Opaques);
+ NumberVals ->
+ NewNumberVals = [X || X <- NumberVals, erlang:CompOp(LitVal, X)],
+ t_integers(NewNumberVals)
+ end,
+ case t_is_none(NewVarType) of
+ true -> error;
+ false -> {ok, enter_type(Var, NewVarType, Map)}
+ end.
+
+handle_guard_is_function(Guard, Map, Env, Eval, State) ->
+ Args = cerl:call_args(Guard),
+ {Map1, ArgTypes0} = bind_guard_list(Args, Map, Env, dont_know, State),
+ [FunType0, ArityType0] = ArgTypes0,
+ Opaques = State#state.opaques,
+ ArityType = t_inf(ArityType0, t_integer(), Opaques),
+ case t_is_none(ArityType) of
+ true -> signal_guard_fail(Eval, Guard, ArgTypes0, State);
+ false ->
+ FunTypeConstr =
+ case t_number_vals(ArityType, State#state.opaques) of
+ unknown -> t_fun();
+ Vals ->
+ t_sup([t_fun(lists:duplicate(X, t_any()), t_any()) || X <- Vals])
+ end,
+ FunType = t_inf(FunType0, FunTypeConstr, Opaques),
+ case t_is_none(FunType) of
+ true ->
+ case Eval of
+ pos -> signal_guard_fail(Eval, Guard, ArgTypes0, State);
+ neg -> {Map1, t_atom(false)};
+ dont_know -> {Map1, t_atom(false)}
+ end;
+ false ->
+ case Eval of
+ pos -> {enter_type_lists(Args, [FunType, ArityType], Map1),
+ t_atom(true)};
+ neg -> {Map1, t_atom(false)};
+ dont_know -> {Map1, t_boolean()}
+ end
+ end
+ end.
+
+handle_guard_is_record(Guard, Map, Env, Eval, State) ->
+ Args = cerl:call_args(Guard),
+ [Rec, Tag0, Arity0] = Args,
+ Tag = cerl:atom_val(Tag0),
+ Arity = cerl:int_val(Arity0),
+ {Map1, RecType} = bind_guard(Rec, Map, Env, dont_know, State),
+ ArityMin1 = Arity - 1,
+ Opaques = State#state.opaques,
+ Tuple = t_tuple([t_atom(Tag)|lists:duplicate(ArityMin1, t_any())]),
+ case t_is_none(t_inf(Tuple, RecType, Opaques)) of
+ true ->
+ case erl_types:t_has_opaque_subtype(RecType, Opaques) of
+ true ->
+ signal_guard_fail(Eval, Guard,
+ [RecType, t_from_term(Tag),
+ t_from_term(Arity)],
+ State);
+ false ->
+ case Eval of
+ pos -> signal_guard_fail(Eval, Guard,
+ [RecType, t_from_term(Tag),
+ t_from_term(Arity)],
+ State);
+ neg -> {Map1, t_atom(false)};
+ dont_know -> {Map1, t_atom(false)}
+ end
+ end;
+ false ->
+ TupleType =
+ case state__lookup_record(Tag, ArityMin1, State) of
+ error -> Tuple;
+ {ok, Prototype} -> Prototype
+ end,
+ Type = t_inf(TupleType, RecType, State#state.opaques),
+ case t_is_none(Type) of
+ true ->
+ %% No special handling of opaque errors.
+ FArgs = "record " ++ format_type(RecType, State),
+ Msg = {record_matching, [FArgs, Tag]},
+ throw({fail, {Guard, Msg}});
+ false ->
+ case Eval of
+ pos -> {enter_type(Rec, Type, Map1), t_atom(true)};
+ neg -> {Map1, t_atom(false)};
+ dont_know -> {Map1, t_boolean()}
+ end
+ end
+ end.
+
+handle_guard_eq(Guard, Map, Env, Eval, State) ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ case {type(Arg1), type(Arg2)} of
+ {{literal, Lit1}, {literal, Lit2}} ->
+ case cerl:concrete(Lit1) =:= cerl:concrete(Lit2) of
+ true ->
+ if
+ Eval =:= pos -> {Map, t_atom(true)};
+ Eval =:= neg ->
+ ArgTypes = [t_from_term(cerl:concrete(Lit1)),
+ t_from_term(cerl:concrete(Lit2))],
+ signal_guard_fail(Eval, Guard, ArgTypes, State);
+ Eval =:= dont_know -> {Map, t_atom(true)}
+ end;
+ false ->
+ if
+ Eval =:= neg -> {Map, t_atom(false)};
+ Eval =:= dont_know -> {Map, t_atom(false)};
+ Eval =:= pos ->
+ ArgTypes = [t_from_term(cerl:concrete(Lit1)),
+ t_from_term(cerl:concrete(Lit2))],
+ signal_guard_fail(Eval, Guard, ArgTypes, State)
+ end
+ end;
+ {{literal, Lit1}, _} when Eval =:= pos ->
+ case cerl:concrete(Lit1) of
+ Atom when is_atom(Atom) ->
+ bind_eqeq_guard_lit_other(Guard, Lit1, Arg2, Map, Env, State);
+ [] ->
+ bind_eqeq_guard_lit_other(Guard, Lit1, Arg2, Map, Env, State);
+ _ ->
+ bind_eq_guard(Guard, Lit1, Arg2, Map, Env, Eval, State)
+ end;
+ {_, {literal, Lit2}} when Eval =:= pos ->
+ case cerl:concrete(Lit2) of
+ Atom when is_atom(Atom) ->
+ bind_eqeq_guard_lit_other(Guard, Lit2, Arg1, Map, Env, State);
+ [] ->
+ bind_eqeq_guard_lit_other(Guard, Lit2, Arg1, Map, Env, State);
+ _ ->
+ bind_eq_guard(Guard, Arg1, Lit2, Map, Env, Eval, State)
+ end;
+ {_, _} ->
+ bind_eq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State)
+ end.
+
+bind_eq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) ->
+ {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State),
+ {Map2, Type2} = bind_guard(Arg2, Map1, Env, dont_know, State),
+ Opaques = State#state.opaques,
+ case
+ t_is_nil(Type1, Opaques) orelse t_is_nil(Type2, Opaques)
+ orelse t_is_atom(Type1, Opaques) orelse t_is_atom(Type2, Opaques)
+ of
+ true -> bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State);
+ false ->
+ %% XXX. Is this test OK?
+ OpArgs = erl_types:t_find_unknown_opaque(Type1, Type2, Opaques),
+ case OpArgs =:= [] of
+ true ->
+ case Eval of
+ pos -> {Map2, t_atom(true)};
+ neg -> {Map2, t_atom(false)};
+ dont_know -> {Map2, t_boolean()}
+ end;
+ false ->
+ signal_guard_fail(Eval, Guard, [Type1, Type2], State)
+ end
+ end.
+
+handle_guard_eqeq(Guard, Map, Env, Eval, State) ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ case {type(Arg1), type(Arg2)} of
+ {{literal, Lit1}, {literal, Lit2}} ->
+
+ case cerl:concrete(Lit1) =:= cerl:concrete(Lit2) of
+ true ->
+ if Eval =:= neg ->
+ ArgTypes = [t_from_term(cerl:concrete(Lit1)),
+ t_from_term(cerl:concrete(Lit2))],
+ signal_guard_fail(Eval, Guard, ArgTypes, State);
+ Eval =:= pos -> {Map, t_atom(true)};
+ Eval =:= dont_know -> {Map, t_atom(true)}
+ end;
+ false ->
+ if Eval =:= neg -> {Map, t_atom(false)};
+ Eval =:= dont_know -> {Map, t_atom(false)};
+ Eval =:= pos ->
+ ArgTypes = [t_from_term(cerl:concrete(Lit1)),
+ t_from_term(cerl:concrete(Lit2))],
+ signal_guard_fail(Eval, Guard, ArgTypes, State)
+ end
+ end;
+ {{literal, Lit1}, _} when Eval =:= pos ->
+ bind_eqeq_guard_lit_other(Guard, Lit1, Arg2, Map, Env, State);
+ {_, {literal, Lit2}} when Eval =:= pos ->
+ bind_eqeq_guard_lit_other(Guard, Lit2, Arg1, Map, Env, State);
+ {_, _} ->
+ bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State)
+ end.
+
+bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) ->
+ {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State),
+ {Map2, Type2} = bind_guard(Arg2, Map1, Env, dont_know, State),
+ ?debug("Types are:~s =:= ~s\n", [t_to_string(Type1),
+ t_to_string(Type2)]),
+ Opaques = State#state.opaques,
+ Inf = t_inf(Type1, Type2, Opaques),
+ case t_is_none(Inf) of
+ true ->
+ OpArgs = erl_types:t_find_unknown_opaque(Type1, Type2, Opaques),
+ case OpArgs =:= [] of
+ true ->
+ case Eval of
+ neg -> {Map2, t_atom(false)};
+ dont_know -> {Map2, t_atom(false)};
+ pos -> signal_guard_fail(Eval, Guard, [Type1, Type2], State)
+ end;
+ false ->
+ signal_guard_fail(Eval, Guard, [Type1, Type2], State)
+ end;
+ false ->
+ case Eval of
+ pos ->
+ case {cerl:type(Arg1), cerl:type(Arg2)} of
+ {var, var} ->
+ Map3 = enter_subst(Arg1, Arg2, Map2),
+ Map4 = enter_type(Arg2, Inf, Map3),
+ {Map4, t_atom(true)};
+ {var, _} ->
+ Map3 = enter_type(Arg1, Inf, Map2),
+ {Map3, t_atom(true)};
+ {_, var} ->
+ Map3 = enter_type(Arg2, Inf, Map2),
+ {Map3, t_atom(true)};
+ {_, _} ->
+ {Map2, t_atom(true)}
+ end;
+ neg ->
+ {Map2, t_atom(false)};
+ dont_know ->
+ {Map2, t_boolean()}
+ end
+ end.
+
+bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State) ->
+ Eval = dont_know,
+ Opaques = State#state.opaques,
+ case cerl:concrete(Arg1) of
+ true ->
+ {_, Type} = MT = bind_guard(Arg2, Map, Env, pos, State),
+ case t_is_any_atom(true, Type, Opaques) of
+ true -> MT;
+ false ->
+ {_, Type0} = bind_guard(Arg2, Map, Env, Eval, State),
+ signal_guard_fail(Eval, Guard, [Type0, t_atom(true)], State)
+ end;
+ false ->
+ {Map1, Type} = bind_guard(Arg2, Map, Env, neg, State),
+ case t_is_any_atom(false, Type, Opaques) of
+ true -> {Map1, t_atom(true)};
+ false ->
+ {_, Type0} = bind_guard(Arg2, Map, Env, Eval, State),
+ signal_guard_fail(Eval, Guard, [Type0, t_atom(false)], State)
+ end;
+ Term ->
+ LitType = t_from_term(Term),
+ {Map1, Type} = bind_guard(Arg2, Map, Env, Eval, State),
+ case t_is_subtype(LitType, Type) of
+ false -> signal_guard_fail(Eval, Guard, [Type, LitType], State);
+ true ->
+ case cerl:is_c_var(Arg2) of
+ true -> {enter_type(Arg2, LitType, Map1), t_atom(true)};
+ false -> {Map1, t_atom(true)}
+ end
+ end
+ end.
+
+handle_guard_and(Guard, Map, Env, Eval, State) ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ Opaques = State#state.opaques,
+ case Eval of
+ pos ->
+ {Map1, Type1} = bind_guard(Arg1, Map, Env, Eval, State),
+ case t_is_any_atom(true, Type1, Opaques) of
+ false -> signal_guard_fail(Eval, Guard, [Type1, t_any()], State);
+ true ->
+ {Map2, Type2} = bind_guard(Arg2, Map1, Env, Eval, State),
+ case t_is_any_atom(true, Type2, Opaques) of
+ false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State);
+ true -> {Map2, t_atom(true)}
+ end
+ end;
+ neg ->
+ MapJ = join_maps_begin(Map),
+ {Map1, Type1} =
+ try bind_guard(Arg1, MapJ, Env, neg, State)
+ catch throw:{fail, _} -> bind_guard(Arg2, MapJ, Env, pos, State)
+ end,
+ {Map2, Type2} =
+ try bind_guard(Arg2, MapJ, Env, neg, State)
+ catch throw:{fail, _} -> bind_guard(Arg1, MapJ, Env, pos, State)
+ end,
+ case
+ t_is_any_atom(false, Type1, Opaques)
+ orelse t_is_any_atom(false, Type2, Opaques)
+ of
+ true -> {join_maps_end([Map1, Map2], MapJ), t_atom(false)};
+ false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State)
+ end;
+ dont_know ->
+ MapJ = join_maps_begin(Map),
+ {Map1, Type1} = bind_guard(Arg1, MapJ, Env, dont_know, State),
+ {Map2, Type2} = bind_guard(Arg2, MapJ, Env, dont_know, State),
+ Bool1 = t_inf(Type1, t_boolean()),
+ Bool2 = t_inf(Type2, t_boolean()),
+ case t_is_none(Bool1) orelse t_is_none(Bool2) of
+ true -> throw({fatal_fail, none});
+ false ->
+ NewMap = join_maps_end([Map1, Map2], MapJ),
+ NewType =
+ case {t_atom_vals(Bool1, Opaques), t_atom_vals(Bool2, Opaques)} of
+ {['true'] , ['true'] } -> t_atom(true);
+ {['false'], _ } -> t_atom(false);
+ {_ , ['false']} -> t_atom(false);
+ {unknown , _ } ->
+ signal_guard_fail(Eval, Guard, [Type1, Type2], State);
+ {_ , unknown } ->
+ signal_guard_fail(Eval, Guard, [Type1, Type2], State);
+ {_ , _ } -> t_boolean()
+
+ end,
+ {NewMap, NewType}
+ end
+ end.
+
+handle_guard_or(Guard, Map, Env, Eval, State) ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ Opaques = State#state.opaques,
+ case Eval of
+ pos ->
+ MapJ = join_maps_begin(Map),
+ {Map1, Bool1} =
+ try bind_guard(Arg1, MapJ, Env, pos, State)
+ catch
+ throw:{fail,_} -> bind_guard(Arg1, MapJ, Env, dont_know, State)
+ end,
+ {Map2, Bool2} =
+ try bind_guard(Arg2, MapJ, Env, pos, State)
+ catch
+ throw:{fail,_} -> bind_guard(Arg2, MapJ, Env, dont_know, State)
+ end,
+ case
+ ((t_is_any_atom(true, Bool1, Opaques)
+ andalso t_is_boolean(Bool2, Opaques))
+ orelse
+ (t_is_any_atom(true, Bool2, Opaques)
+ andalso t_is_boolean(Bool1, Opaques)))
+ of
+ true -> {join_maps_end([Map1, Map2], MapJ), t_atom(true)};
+ false -> signal_guard_fail(Eval, Guard, [Bool1, Bool2], State)
+ end;
+ neg ->
+ {Map1, Type1} = bind_guard(Arg1, Map, Env, neg, State),
+ case t_is_any_atom(false, Type1, Opaques) of
+ false -> signal_guard_fail(Eval, Guard, [Type1, t_any()], State);
+ true ->
+ {Map2, Type2} = bind_guard(Arg2, Map1, Env, neg, State),
+ case t_is_any_atom(false, Type2, Opaques) of
+ false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State);
+ true -> {Map2, t_atom(false)}
+ end
+ end;
+ dont_know ->
+ MapJ = join_maps_begin(Map),
+ {Map1, Type1} = bind_guard(Arg1, MapJ, Env, dont_know, State),
+ {Map2, Type2} = bind_guard(Arg2, MapJ, Env, dont_know, State),
+ Bool1 = t_inf(Type1, t_boolean()),
+ Bool2 = t_inf(Type2, t_boolean()),
+ case t_is_none(Bool1) orelse t_is_none(Bool2) of
+ true -> throw({fatal_fail, none});
+ false ->
+ NewMap = join_maps_end([Map1, Map2], MapJ),
+ NewType =
+ case {t_atom_vals(Bool1, Opaques), t_atom_vals(Bool2, Opaques)} of
+ {['false'], ['false']} -> t_atom(false);
+ {['true'] , _ } -> t_atom(true);
+ {_ , ['true'] } -> t_atom(true);
+ {unknown , _ } ->
+ signal_guard_fail(Eval, Guard, [Type1, Type2], State);
+ {_ , unknown } ->
+ signal_guard_fail(Eval, Guard, [Type1, Type2], State);
+ {_ , _ } -> t_boolean()
+ end,
+ {NewMap, NewType}
+ end
+ end.
+
+handle_guard_not(Guard, Map, Env, Eval, State) ->
+ [Arg] = cerl:call_args(Guard),
+ Opaques = State#state.opaques,
+ case Eval of
+ neg ->
+ {Map1, Type} = bind_guard(Arg, Map, Env, pos, State),
+ case t_is_any_atom(true, Type, Opaques) of
+ true -> {Map1, t_atom(false)};
+ false ->
+ {_, Type0} = bind_guard(Arg, Map, Env, Eval, State),
+ signal_guard_fail(Eval, Guard, [Type0], State)
+ end;
+ pos ->
+ {Map1, Type} = bind_guard(Arg, Map, Env, neg, State),
+ case t_is_any_atom(false, Type, Opaques) of
+ true -> {Map1, t_atom(true)};
+ false ->
+ {_, Type0} = bind_guard(Arg, Map, Env, Eval, State),
+ signal_guard_fail(Eval, Guard, [Type0], State)
+ end;
+ dont_know ->
+ {Map1, Type} = bind_guard(Arg, Map, Env, dont_know, State),
+ Bool = t_inf(Type, t_boolean()),
+ case t_is_none(Bool) of
+ true -> throw({fatal_fail, none});
+ false ->
+ case t_atom_vals(Bool, Opaques) of
+ ['true'] -> {Map1, t_atom(false)};
+ ['false'] -> {Map1, t_atom(true)};
+ [_, _] -> {Map1, Bool};
+ unknown -> signal_guard_fail(Eval, Guard, [Type], State)
+ end
+ end
+ end.
+
+bind_guard_list(Guards, Map, Env, Eval, State) ->
+ bind_guard_list(Guards, Map, Env, Eval, State, []).
+
+bind_guard_list([G|Gs], Map, Env, Eval, State, Acc) ->
+ {Map1, T} = bind_guard(G, Map, Env, Eval, State),
+ bind_guard_list(Gs, Map1, Env, Eval, State, [T|Acc]);
+bind_guard_list([], Map, _Env, _Eval, _State, Acc) ->
+ {Map, lists:reverse(Acc)}.
+
+handle_guard_map(Guard, Map, Env, State) ->
+ Pairs = cerl:map_es(Guard),
+ Arg = cerl:map_arg(Guard),
+ {Map1, ArgType0} = bind_guard(Arg, Map, Env, dont_know, State),
+ ArgType1 = t_inf(t_map(), ArgType0),
+ case t_is_none_or_unit(ArgType1) of
+ true -> {Map1, t_none()};
+ false ->
+ {Map2, TypePairs} = bind_guard_map_pairs(Pairs, Map1, Env, State, []),
+ {Map2, lists:foldl(fun({KV,assoc},Acc) -> erl_types:t_map_put(KV,Acc);
+ ({KV,exact},Acc) -> erl_types:t_map_update(KV,Acc)
+ end, ArgType1, TypePairs)}
+ end.
+
+bind_guard_map_pairs([], Map, _Env, _State, PairAcc) ->
+ {Map, lists:reverse(PairAcc)};
+bind_guard_map_pairs([Pair|Pairs], Map, Env, State, PairAcc) ->
+ Key = cerl:map_pair_key(Pair),
+ Val = cerl:map_pair_val(Pair),
+ Op = cerl:map_pair_op(Pair),
+ {Map1, [K,V]} = bind_guard_list([Key,Val],Map,Env,dont_know,State),
+ bind_guard_map_pairs(Pairs, Map1, Env, State,
+ [{{K,V},cerl:concrete(Op)}|PairAcc]).
+
+-type eval() :: 'pos' | 'neg' | 'dont_know'.
+
+-spec signal_guard_fail(eval(), cerl:c_call(), [type()],
+ state()) -> no_return().
+
+signal_guard_fail(Eval, Guard, ArgTypes, State) ->
+ signal_guard_failure(Eval, Guard, ArgTypes, fail, State).
+
+-spec signal_guard_fatal_fail(eval(), cerl:c_call(), [erl_types:erl_type()],
+ state()) -> no_return().
+
+signal_guard_fatal_fail(Eval, Guard, ArgTypes, State) ->
+ signal_guard_failure(Eval, Guard, ArgTypes, fatal_fail, State).
+
+signal_guard_failure(Eval, Guard, ArgTypes, Tag, State) ->
+ Args = cerl:call_args(Guard),
+ F = cerl:atom_val(cerl:call_name(Guard)),
+ {M, F, A} = MFA = {cerl:atom_val(cerl:call_module(Guard)), F, length(Args)},
+ Opaques = State#state.opaques,
+ {Kind, XInfo} =
+ case erl_bif_types:opaque_args(M, F, A, ArgTypes, Opaques) of
+ [] ->
+ {case Eval of
+ neg -> neg_guard_fail;
+ pos -> guard_fail;
+ dont_know -> guard_fail
+ end,
+ []};
+ Ns -> {opaque_guard, [Ns]}
+ end,
+ FArgs =
+ case is_infix_op(MFA) of
+ true ->
+ [ArgType1, ArgType2] = ArgTypes,
+ [Arg1, Arg2] = Args,
+ [format_args_1([Arg1], [ArgType1], State),
+ atom_to_list(F),
+ format_args_1([Arg2], [ArgType2], State)] ++ XInfo;
+ false ->
+ [F, format_args(Args, ArgTypes, State)]
+ end,
+ Msg = {Kind, FArgs},
+ throw({Tag, {Guard, Msg}}).
+
+is_infix_op({erlang, '=:=', 2}) -> true;
+is_infix_op({erlang, '==', 2}) -> true;
+is_infix_op({erlang, '=/=', 2}) -> true;
+is_infix_op({erlang, '=/', 2}) -> true;
+is_infix_op({erlang, '<', 2}) -> true;
+is_infix_op({erlang, '=<', 2}) -> true;
+is_infix_op({erlang, '>', 2}) -> true;
+is_infix_op({erlang, '>=', 2}) -> true;
+is_infix_op({M, F, A}) when is_atom(M), is_atom(F),
+ is_integer(A), 0 =< A, A =< 255 -> false.
+
+bif_args(M, F, A) ->
+ case erl_bif_types:arg_types(M, F, A) of
+ unknown -> lists:duplicate(A, t_any());
+ List -> List
+ end.
+
+bind_guard_case_clauses(Arg, Clauses, Map0, Env, Eval, State) ->
+ Clauses1 = filter_fail_clauses(Clauses),
+ Map = join_maps_begin(Map0),
+ {GenMap, GenArgType} = bind_guard(Arg, Map, Env, dont_know, State),
+ bind_guard_case_clauses(GenArgType, GenMap, Arg, Clauses1, Map, Env, Eval,
+ t_none(), [], State).
+
+filter_fail_clauses([Clause|Left]) ->
+ case (cerl:clause_pats(Clause) =:= []) of
+ true ->
+ Body = cerl:clause_body(Clause),
+ case cerl:is_literal(Body) andalso (cerl:concrete(Body) =:= fail) orelse
+ cerl:is_c_primop(Body) andalso
+ (cerl:atom_val(cerl:primop_name(Body)) =:= match_fail) of
+ true -> filter_fail_clauses(Left);
+ false -> [Clause|filter_fail_clauses(Left)]
+ end;
+ false ->
+ [Clause|filter_fail_clauses(Left)]
+ end;
+filter_fail_clauses([]) ->
+ [].
+
+bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
+ Map, Env, Eval, AccType, AccMaps, State) ->
+ Pats = cerl:clause_pats(Clause),
+ {NewMap0, ArgType} =
+ case Pats of
+ [Pat] ->
+ case cerl:is_literal(Pat) of
+ true ->
+ try
+ case cerl:concrete(Pat) of
+ true -> bind_guard(ArgExpr, Map, Env, pos, State);
+ false -> bind_guard(ArgExpr, Map, Env, neg, State);
+ _ -> {GenMap, GenArgType}
+ end
+ catch
+ throw:{fail, _} -> {none, GenArgType}
+ end;
+ false ->
+ {GenMap, GenArgType}
+ end;
+ _ -> {GenMap, GenArgType}
+ end,
+ NewMap1 =
+ case Pats =:= [] of
+ true -> NewMap0;
+ false ->
+ case t_is_none(ArgType) of
+ true -> none;
+ false ->
+ ArgTypes = case t_is_any(ArgType) of
+ true -> Any = t_any(), [Any || _ <- Pats];
+ false -> t_to_tlist(ArgType)
+ end,
+ case bind_pat_vars(Pats, ArgTypes, [], NewMap0, State) of
+ {error, _, _, _, _} -> none;
+ {PatMap, _PatTypes} -> PatMap
+ end
+ end
+ end,
+ Guard = cerl:clause_guard(Clause),
+ GenPatType = dialyzer_typesig:get_safe_underapprox(Pats, Guard),
+ NewGenArgType = t_subtract(GenArgType, GenPatType),
+ case (NewMap1 =:= none) orelse t_is_none(GenArgType) of
+ true ->
+ bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env,
+ Eval, AccType, AccMaps, State);
+ false ->
+ {NewAccType, NewAccMaps} =
+ try
+ {NewMap2, GuardType} = bind_guard(Guard, NewMap1, Env, pos, State),
+ case t_is_none(t_inf(t_atom(true), GuardType)) of
+ true -> throw({fail, none});
+ false -> ok
+ end,
+ {NewMap3, CType} = bind_guard(cerl:clause_body(Clause), NewMap2,
+ Env, Eval, State),
+ Opaques = State#state.opaques,
+ case Eval of
+ pos ->
+ case t_is_any_atom(true, CType, Opaques) of
+ true -> ok;
+ false -> throw({fail, none})
+ end;
+ neg ->
+ case t_is_any_atom(false, CType, Opaques) of
+ true -> ok;
+ false -> throw({fail, none})
+ end;
+ dont_know ->
+ ok
+ end,
+ {t_sup(AccType, CType), [NewMap3|AccMaps]}
+ catch
+ throw:{fail, _What} -> {AccType, AccMaps}
+ end,
+ bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env,
+ Eval, NewAccType, NewAccMaps, State)
+ end;
+bind_guard_case_clauses(_GenArgType, _GenMap, _ArgExpr, [], Map, _Env, _Eval,
+ AccType, AccMaps, _State) ->
+ case t_is_none(AccType) of
+ true -> throw({fail, none});
+ false -> {join_maps_end(AccMaps, Map), AccType}
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Maps and types.
+%%%
+%%% ===========================================================================
+
+map__new() ->
+ #map{}.
+
+%% join_maps_begin pushes 'modified' to the stack; join_maps pops
+%% 'modified' from the stack.
+
+join_maps_begin(#map{modified = M, modified_stack = S, ref = Ref} = Map) ->
+ Map#map{ref = make_ref(), modified = [], modified_stack = [{M,Ref} | S]}.
+
+join_maps_end(Maps, MapOut) ->
+ #map{ref = Ref, modified_stack = [{M1,R1} | S]} = MapOut,
+ true = lists:all(fun(M) -> M#map.ref =:= Ref end, Maps), % sanity
+ Keys0 = lists:usort(lists:append([M#map.modified || M <- Maps])),
+ #map{map = Map, subst = Subst} = MapOut,
+ Keys = [Key ||
+ Key <- Keys0,
+ maps:is_key(Key, Map) orelse maps:is_key(Key, Subst)],
+ Out = case Maps of
+ [] -> join_maps(Maps, MapOut);
+ _ -> join_maps(Keys, Maps, MapOut)
+ end,
+ debug_join_check(Maps, MapOut, Out),
+ Out#map{ref = R1,
+ modified = Out#map.modified ++ M1, % duplicates possible
+ modified_stack = S}.
+
+join_maps(Maps, MapOut) ->
+ #map{map = Map, subst = Subst} = MapOut,
+ Keys = ordsets:from_list(maps:keys(Map) ++ maps:keys(Subst)),
+ join_maps(Keys, Maps, MapOut).
+
+join_maps(Keys, Maps, MapOut) ->
+ KTs = join_maps_collect(Keys, Maps, MapOut),
+ lists:foldl(fun({K, T}, M) -> enter_type(K, T, M) end, MapOut, KTs).
+
+join_maps_collect([Key|Left], Maps, MapOut) ->
+ Type = join_maps_one_key(Maps, Key, t_none()),
+ case t_is_equal(lookup_type(Key, MapOut), Type) of
+ true -> join_maps_collect(Left, Maps, MapOut);
+ false -> [{Key, Type} | join_maps_collect(Left, Maps, MapOut)]
+ end;
+join_maps_collect([], _Maps, _MapOut) ->
+ [].
+
+join_maps_one_key([Map|Left], Key, AccType) ->
+ case t_is_any(AccType) of
+ true ->
+ %% We can stop here
+ AccType;
+ false ->
+ join_maps_one_key(Left, Key, t_sup(lookup_type(Key, Map), AccType))
+ end;
+join_maps_one_key([], _Key, AccType) ->
+ AccType.
+
+-ifdef(DEBUG).
+debug_join_check(Maps, MapOut, Out) ->
+ #map{map = Map, subst = Subst} = Out,
+ #map{map = Map2, subst = Subst2} = join_maps(Maps, MapOut),
+ F = fun(D) -> lists:keysort(1, maps:to_list(D)) end,
+ [throw({bug, join_maps}) ||
+ F(Map) =/= F(Map2) orelse F(Subst) =/= F(Subst2)].
+-else.
+debug_join_check(_Maps, _MapOut, _Out) -> ok.
+-endif.
+
+enter_type_lists([Key|KeyTail], [Val|ValTail], Map) ->
+ Map1 = enter_type(Key, Val, Map),
+ enter_type_lists(KeyTail, ValTail, Map1);
+enter_type_lists([], [], Map) ->
+ Map.
+
+enter_type_list([{Key, Val}|Left], Map) ->
+ Map1 = enter_type(Key, Val, Map),
+ enter_type_list(Left, Map1);
+enter_type_list([], Map) ->
+ Map.
+
+enter_type(Key, Val, MS) ->
+ case cerl:is_literal(Key) of
+ true -> MS;
+ false ->
+ case cerl:is_c_values(Key) of
+ true ->
+ Keys = cerl:values_es(Key),
+ case t_is_any(Val) orelse t_is_none(Val) of
+ true ->
+ enter_type_lists(Keys, [Val || _ <- Keys], MS);
+ false ->
+ enter_type_lists(Keys, t_to_tlist(Val), MS)
+ end;
+ false ->
+ #map{map = Map, subst = Subst} = MS,
+ KeyLabel = get_label(Key),
+ case maps:find(KeyLabel, Subst) of
+ {ok, NewKey} ->
+ ?debug("Binding ~p to ~p\n", [KeyLabel, NewKey]),
+ enter_type(NewKey, Val, MS);
+ error ->
+ ?debug("Entering ~p :: ~s\n", [KeyLabel, t_to_string(Val)]),
+ case maps:find(KeyLabel, Map) of
+ {ok, Value} ->
+ case erl_types:t_is_equal(Val, Value) of
+ true -> MS;
+ false -> store_map(KeyLabel, Val, MS)
+ end;
+ error -> store_map(KeyLabel, Val, MS)
+ end
+ end
+ end
+ end.
+
+store_map(Key, Val, #map{map = Map, ref = undefined} = MapRec) ->
+ MapRec#map{map = maps:put(Key, Val, Map)};
+store_map(Key, Val, #map{map = Map, modified = Mod} = MapRec) ->
+ MapRec#map{map = maps:put(Key, Val, Map), modified = [Key | Mod]}.
+
+enter_subst(Key, Val0, #map{subst = Subst} = MS) ->
+ KeyLabel = get_label(Key),
+ Val = dialyzer_utils:refold_pattern(Val0),
+ case cerl:is_literal(Val) of
+ true ->
+ store_map(KeyLabel, literal_type(Val), MS);
+ false ->
+ case cerl:is_c_var(Val) of
+ false -> MS;
+ true ->
+ ValLabel = get_label(Val),
+ case maps:find(ValLabel, Subst) of
+ {ok, NewVal} ->
+ enter_subst(Key, NewVal, MS);
+ error ->
+ if KeyLabel =:= ValLabel -> MS;
+ true ->
+ ?debug("Subst: storing ~p = ~p\n", [KeyLabel, ValLabel]),
+ store_subst(KeyLabel, ValLabel, MS)
+ end
+ end
+ end
+ end.
+
+store_subst(Key, Val, #map{subst = S, ref = undefined} = Map) ->
+ Map#map{subst = maps:put(Key, Val, S)};
+store_subst(Key, Val, #map{subst = S, modified = Mod} = Map) ->
+ Map#map{subst = maps:put(Key, Val, S), modified = [Key | Mod]}.
+
+lookup_type(Key, #map{map = Map, subst = Subst}) ->
+ lookup(Key, Map, Subst, t_none()).
+
+lookup(Key, Map, Subst, AnyNone) ->
+ case cerl:is_literal(Key) of
+ true -> literal_type(Key);
+ false ->
+ Label = get_label(Key),
+ case maps:find(Label, Subst) of
+ {ok, NewKey} -> lookup(NewKey, Map, Subst, AnyNone);
+ error ->
+ case maps:find(Label, Map) of
+ {ok, Val} -> Val;
+ error -> AnyNone
+ end
+ end
+ end.
+
+lookup_fun_sig(Fun, Callgraph, Plt) ->
+ MFAorLabel =
+ case dialyzer_callgraph:lookup_name(Fun, Callgraph) of
+ error -> Fun;
+ {ok, MFA} -> MFA
+ end,
+ dialyzer_plt:lookup(Plt, MFAorLabel).
+
+literal_type(Lit) ->
+ t_from_term(cerl:concrete(Lit)).
+
+mark_as_fresh([Tree|Left], Map) ->
+ SubTrees1 = lists:append(cerl:subtrees(Tree)),
+ {SubTrees2, Map1} =
+ case cerl:type(Tree) of
+ bitstr ->
+ %% The Size field is not fresh.
+ {SubTrees1 -- [cerl:bitstr_size(Tree)], Map};
+ map_pair ->
+ %% The keys are not fresh
+ {SubTrees1 -- [cerl:map_pair_key(Tree)], Map};
+ var ->
+ {SubTrees1, enter_type(Tree, t_any(), Map)};
+ _ ->
+ {SubTrees1, Map}
+ end,
+ mark_as_fresh(SubTrees2 ++ Left, Map1);
+mark_as_fresh([], Map) ->
+ Map.
+
+-ifdef(DEBUG).
+debug_pp_map(#map{map = Map}=MapRec) ->
+ Keys = maps:keys(Map),
+ io:format("Map:\n", []),
+ lists:foreach(fun (Key) ->
+ io:format("\t~w :: ~s\n",
+ [Key, t_to_string(lookup_type(Key, MapRec))])
+ end, Keys),
+ ok.
+-else.
+debug_pp_map(_Map) -> ok.
+-endif.
+
+%%% ===========================================================================
+%%%
+%%% Utilities
+%%%
+%%% ===========================================================================
+
+get_label(L) when is_integer(L) ->
+ L;
+get_label(T) ->
+ cerl_trees:get_label(T).
+
+t_is_simple(ArgType, State) ->
+ Opaques = State#state.opaques,
+ t_is_atom(ArgType, Opaques) orelse t_is_number(ArgType, Opaques)
+ orelse t_is_port(ArgType, Opaques)
+ orelse t_is_pid(ArgType, Opaques) orelse t_is_reference(ArgType, Opaques)
+ orelse t_is_nil(ArgType, Opaques).
+
+remove_local_opaque_types(Type, Opaques) ->
+ t_unopaque(Type, Opaques).
+
+%% t_is_structured(ArgType) ->
+%% case t_is_nil(ArgType) of
+%% true -> false;
+%% false ->
+%% SType = t_inf(t_sup([t_list(), t_tuple(), t_binary()]), ArgType),
+%% t_is_equal(ArgType, SType)
+%% end.
+
+is_call_to_send(Tree) ->
+ case cerl:is_c_call(Tree) of
+ false -> false;
+ true ->
+ Mod = cerl:call_module(Tree),
+ Name = cerl:call_name(Tree),
+ Arity = cerl:call_arity(Tree),
+ cerl:is_c_atom(Mod)
+ andalso cerl:is_c_atom(Name)
+ andalso is_send(cerl:atom_val(Name))
+ andalso (cerl:atom_val(Mod) =:= erlang)
+ andalso (Arity =:= 2)
+ end.
+
+is_send('!') -> true;
+is_send(send) -> true;
+is_send(_) -> false.
+
+is_lc_simple_list(Tree, TreeType, State) ->
+ Opaques = State#state.opaques,
+ Ann = cerl:get_ann(Tree),
+ lists:member(list_comprehension, Ann)
+ andalso t_is_list(TreeType)
+ andalso t_is_simple(t_list_elements(TreeType, Opaques), State).
+
+filter_match_fail([Clause] = Cls) ->
+ Body = cerl:clause_body(Clause),
+ case cerl:type(Body) of
+ primop ->
+ case cerl:atom_val(cerl:primop_name(Body)) of
+ match_fail -> [];
+ raise -> [];
+ _ -> Cls
+ end;
+ _ -> Cls
+ end;
+filter_match_fail([H|T]) ->
+ [H|filter_match_fail(T)];
+filter_match_fail([]) ->
+ %% This can actually happen, for example in
+ %% receive after 1 -> ok end
+ [].
+
+%%% ===========================================================================
+%%%
+%%% The State.
+%%%
+%%% ===========================================================================
+
+state__new(Callgraph, Codeserver, Tree, Plt, Module, Records) ->
+ Opaques = erl_types:t_opaque_from_records(Records),
+ {TreeMap, FunHomes} = build_tree_map(Tree, Callgraph),
+ Funs = dict:fetch_keys(TreeMap),
+ FunTab = init_fun_tab(Funs, dict:new(), TreeMap, Callgraph, Plt),
+ ExportedFuns =
+ [Fun || Fun <- Funs--[top], dialyzer_callgraph:is_escaping(Fun, Callgraph)],
+ Work = init_work(ExportedFuns),
+ Env = lists:foldl(fun(Fun, Env) -> dict:store(Fun, map__new(), Env) end,
+ dict:new(), Funs),
+ #state{callgraph = Callgraph, codeserver = Codeserver,
+ envs = Env, fun_tab = FunTab, fun_homes = FunHomes, opaques = Opaques,
+ plt = Plt, races = dialyzer_races:new(), records = Records,
+ warning_mode = false, warnings = [], work = Work, tree_map = TreeMap,
+ module = Module}.
+
+state__warning_mode(#state{warning_mode = WM}) ->
+ WM.
+
+state__set_warning_mode(#state{tree_map = TreeMap, fun_tab = FunTab,
+ races = Races} = State) ->
+ ?debug("==========\nStarting warning pass\n==========\n", []),
+ Funs = dict:fetch_keys(TreeMap),
+ State#state{work = init_work([top|Funs--[top]]),
+ fun_tab = FunTab, warning_mode = true,
+ races = dialyzer_races:put_race_analysis(true, Races)}.
+
+state__race_analysis(Analysis, #state{races = Races} = State) ->
+ State#state{races = dialyzer_races:put_race_analysis(Analysis, Races)}.
+
+state__renew_curr_fun(CurrFun, CurrFunLabel,
+ #state{races = Races} = State) ->
+ State#state{races = dialyzer_races:put_curr_fun(CurrFun, CurrFunLabel,
+ Races)}.
+
+state__renew_fun_args(Args, #state{races = Races} = State) ->
+ case state__warning_mode(State) of
+ true -> State;
+ false ->
+ State#state{races = dialyzer_races:put_fun_args(Args, Races)}
+ end.
+
+state__renew_race_list(RaceList, RaceListSize,
+ #state{races = Races} = State) ->
+ State#state{races = dialyzer_races:put_race_list(RaceList, RaceListSize,
+ Races)}.
+
+state__renew_warnings(Warnings, State) ->
+ State#state{warnings = Warnings}.
+
+-spec state__add_warning(raw_warning(), state()) -> state().
+
+state__add_warning(Warn, #state{warnings = Warnings} = State) ->
+ State#state{warnings = [Warn|Warnings]}.
+
+state__add_warning(State, Tag, Tree, Msg) ->
+ state__add_warning(State, Tag, Tree, Msg, false).
+
+state__add_warning(#state{warning_mode = false} = State, _, _, _, _) ->
+ State;
+state__add_warning(#state{warnings = Warnings, warning_mode = true} = State,
+ Tag, Tree, Msg, Force) ->
+ Ann = cerl:get_ann(Tree),
+ case Force of
+ true ->
+ WarningInfo = {get_file(Ann),
+ abs(get_line(Ann)),
+ State#state.curr_fun},
+ Warn = {Tag, WarningInfo, Msg},
+ ?debug("MSG ~s\n", [dialyzer:format_warning(Warn)]),
+ State#state{warnings = [Warn|Warnings]};
+ false ->
+ case is_compiler_generated(Ann) of
+ true -> State;
+ false ->
+ WarningInfo = {get_file(Ann), get_line(Ann), State#state.curr_fun},
+ Warn = {Tag, WarningInfo, Msg},
+ case Tag of
+ ?WARN_CONTRACT_RANGE -> ok;
+ _ -> ?debug("MSG ~s\n", [dialyzer:format_warning(Warn)])
+ end,
+ State#state{warnings = [Warn|Warnings]}
+ end
+ end.
+
+state__remove_added_warnings(OldState, NewState) ->
+ #state{warnings = OldWarnings} = OldState,
+ #state{warnings = NewWarnings} = NewState,
+ {NewWarnings -- OldWarnings, NewState#state{warnings = OldWarnings}}.
+
+state__add_warnings(Warns, #state{warnings = Warnings} = State) ->
+ State#state{warnings = Warns ++ Warnings}.
+
+-spec state__set_curr_fun(curr_fun(), state()) -> state().
+
+state__set_curr_fun(undefined, State) ->
+ State#state{curr_fun = undefined};
+state__set_curr_fun(FunLbl, State) ->
+ State#state{curr_fun = find_function(FunLbl, State)}.
+
+-spec state__find_function(mfa_or_funlbl(), state()) -> mfa_or_funlbl().
+
+state__find_function(FunLbl, State) ->
+ find_function(FunLbl, State).
+
+state__get_race_warnings(#state{races = Races} = State) ->
+ {Races1, State1} = dialyzer_races:get_race_warnings(Races, State),
+ State1#state{races = Races1}.
+
+state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
+ callgraph = Callgraph, plt = Plt} = State) ->
+ FoldFun =
+ fun({top, _}, AccState) -> AccState;
+ ({FunLbl, Fun}, AccState) ->
+ AccState1 = state__set_curr_fun(FunLbl, AccState),
+ {NotCalled, Ret} =
+ case dict:fetch(get_label(Fun), FunTab) of
+ {not_handled, {_Args0, Ret0}} -> {true, Ret0};
+ {_Args0, Ret0} -> {false, Ret0}
+ end,
+ case NotCalled of
+ true ->
+ case dialyzer_callgraph:lookup_name(FunLbl, Callgraph) of
+ error -> AccState1;
+ {ok, {_M, F, A}} ->
+ Msg = {unused_fun, [F, A]},
+ state__add_warning(AccState1, ?WARN_NOT_CALLED, Fun, Msg)
+ end;
+ false ->
+ {Name, Contract} =
+ case dialyzer_callgraph:lookup_name(FunLbl, Callgraph) of
+ error -> {[], none};
+ {ok, {_M, F, A} = MFA} ->
+ {[F, A], dialyzer_plt:lookup_contract(Plt, MFA)}
+ end,
+ case t_is_none(Ret) of
+ true ->
+ %% Check if the function has a contract that allows this.
+ Warn =
+ case Contract of
+ none -> not parent_allows_this(FunLbl, AccState1);
+ {value, C} ->
+ GenRet = dialyzer_contracts:get_contract_return(C),
+ not t_is_unit(GenRet)
+ end,
+ case Warn of
+ true ->
+ case classify_returns(Fun) of
+ no_match ->
+ Msg = {no_return, [no_match|Name]},
+ state__add_warning(AccState1, ?WARN_RETURN_NO_RETURN,
+ Fun, Msg);
+ only_explicit ->
+ Msg = {no_return, [only_explicit|Name]},
+ state__add_warning(AccState1, ?WARN_RETURN_ONLY_EXIT,
+ Fun, Msg);
+ only_normal ->
+ Msg = {no_return, [only_normal|Name]},
+ state__add_warning(AccState1, ?WARN_RETURN_NO_RETURN,
+ Fun, Msg);
+ both ->
+ Msg = {no_return, [both|Name]},
+ state__add_warning(AccState1, ?WARN_RETURN_NO_RETURN,
+ Fun, Msg)
+ end;
+ false ->
+ AccState
+ end;
+ false ->
+ AccState
+ end
+ end
+ end,
+ #state{warnings = Warn} = lists:foldl(FoldFun, State, dict:to_list(TreeMap)),
+ Warn.
+
+state__is_escaping(Fun, #state{callgraph = Callgraph}) ->
+ dialyzer_callgraph:is_escaping(Fun, Callgraph).
+
+state__lookup_type_for_letrec(Var, #state{callgraph = Callgraph} = State) ->
+ Label = get_label(Var),
+ case dialyzer_callgraph:lookup_letrec(Label, Callgraph) of
+ error -> error;
+ {ok, FunLabel} ->
+ {ok, state__fun_type(FunLabel, State)}
+ end.
+
+state__lookup_name({_, _, _} = MFA, #state{}) ->
+ MFA;
+state__lookup_name(top, #state{}) ->
+ top;
+state__lookup_name(Fun, #state{callgraph = Callgraph}) ->
+ case dialyzer_callgraph:lookup_name(Fun, Callgraph) of
+ {ok, MFA} -> MFA;
+ error -> Fun
+ end.
+
+state__lookup_record(Tag, Arity, #state{records = Records}) ->
+ case erl_types:lookup_record(Tag, Arity, Records) of
+ {ok, Fields} ->
+ RecType =
+ t_tuple([t_atom(Tag)|
+ [FieldType || {_FieldName, _Abstr, FieldType} <- Fields]]),
+ {ok, RecType};
+ error ->
+ error
+ end.
+
+state__get_args_and_status(Tree, #state{fun_tab = FunTab}) ->
+ Fun = get_label(Tree),
+ case dict:find(Fun, FunTab) of
+ {ok, {not_handled, {ArgTypes, _}}} -> {ArgTypes, false};
+ {ok, {ArgTypes, _}} -> {ArgTypes, true}
+ end.
+
+build_tree_map(Tree, Callgraph) ->
+ Fun =
+ fun(T, {Dict, Homes, FunLbls} = Acc) ->
+ case cerl:is_c_fun(T) of
+ true ->
+ FunLbl = get_label(T),
+ Dict1 = dict:store(FunLbl, T, Dict),
+ case catch dialyzer_callgraph:lookup_name(FunLbl, Callgraph) of
+ {ok, MFA} ->
+ F2 =
+ fun(Lbl, Dict0) ->
+ dict:store(Lbl, MFA, Dict0)
+ end,
+ Homes1 = lists:foldl(F2, Homes, [FunLbl|FunLbls]),
+ {Dict1, Homes1, []};
+ _ ->
+ {Dict1, Homes, [FunLbl|FunLbls]}
+ end;
+ false ->
+ Acc
+ end
+ end,
+ Dict0 = dict:new(),
+ {Dict, Homes, _} = cerl_trees:fold(Fun, {Dict0, Dict0, []}, Tree),
+ {Dict, Homes}.
+
+init_fun_tab([top|Left], Dict, TreeMap, Callgraph, Plt) ->
+ NewDict = dict:store(top, {[], t_none()}, Dict),
+ init_fun_tab(Left, NewDict, TreeMap, Callgraph, Plt);
+init_fun_tab([Fun|Left], Dict, TreeMap, Callgraph, Plt) ->
+ Arity = cerl:fun_arity(dict:fetch(Fun, TreeMap)),
+ FunEntry =
+ case dialyzer_callgraph:is_escaping(Fun, Callgraph) of
+ true ->
+ Args = lists:duplicate(Arity, t_any()),
+ case lookup_fun_sig(Fun, Callgraph, Plt) of
+ none -> {Args, t_unit()};
+ {value, {RetType, _}} ->
+ case t_is_none(RetType) of
+ true -> {Args, t_none()};
+ false -> {Args, t_unit()}
+ end
+ end;
+ false -> {not_handled, {lists:duplicate(Arity, t_none()), t_unit()}}
+ end,
+ NewDict = dict:store(Fun, FunEntry, Dict),
+ init_fun_tab(Left, NewDict, TreeMap, Callgraph, Plt);
+init_fun_tab([], Dict, _TreeMap, _Callgraph, _Plt) ->
+ ?debug("DICT:~p\n",[dict:to_list(Dict)]),
+ Dict.
+
+state__update_fun_env(Tree, Map, #state{envs = Envs} = State) ->
+ NewEnvs = dict:store(get_label(Tree), Map, Envs),
+ State#state{envs = NewEnvs}.
+
+state__fun_env(Tree, #state{envs = Envs}) ->
+ Fun = get_label(Tree),
+ case dict:find(Fun, Envs) of
+ error -> none;
+ {ok, Map} -> Map
+ end.
+
+state__clean_not_called(#state{fun_tab = FunTab} = State) ->
+ NewFunTab =
+ dict:map(fun(top, Entry) -> Entry;
+ (_Fun, {not_handled, {Args, _}}) -> {Args, t_none()};
+ (_Fun, Entry) -> Entry
+ end, FunTab),
+ State#state{fun_tab = NewFunTab}.
+
+state__all_fun_types(State) ->
+ #state{fun_tab = FunTab} = state__clean_not_called(State),
+ Tab1 = dict:erase(top, FunTab),
+ dict:map(fun(_Fun, {Args, Ret}) -> t_fun(Args, Ret)end, Tab1).
+
+state__fun_type(Fun, #state{fun_tab = FunTab}) ->
+ Label =
+ if is_integer(Fun) -> Fun;
+ true -> get_label(Fun)
+ end,
+ Entry = dict:find(Label, FunTab),
+ ?debug("FunType ~p:~p\n",[Label, Entry]),
+ case Entry of
+ {ok, {not_handled, {A, R}}} ->
+ t_fun(A, R);
+ {ok, {A, R}} ->
+ t_fun(A, R)
+ end.
+
+state__update_fun_entry(Tree, ArgTypes, Out0,
+ #state{fun_tab=FunTab, callgraph=CG, plt=Plt} = State)->
+ Fun = get_label(Tree),
+ Out1 =
+ if Fun =:= top -> Out0;
+ true ->
+ case lookup_fun_sig(Fun, CG, Plt) of
+ {value, {SigRet, _}} -> t_inf(SigRet, Out0);
+ none -> Out0
+ end
+ end,
+ Out = t_limit(Out1, ?TYPE_LIMIT),
+ {ok, {OldArgTypes, OldOut}} = dict:find(Fun, FunTab),
+ SameArgs = lists:all(fun({A, B}) -> erl_types:t_is_equal(A, B)
+ end, lists:zip(OldArgTypes, ArgTypes)),
+ SameOut = t_is_equal(OldOut, Out),
+ if
+ SameArgs, SameOut ->
+ ?debug("Fixpoint for ~w: ~s\n",
+ [state__lookup_name(Fun, State),
+ t_to_string(t_fun(ArgTypes, Out))]),
+ State;
+ true ->
+ %% Can only happen in self-recursive functions.
+ NewEntry = {OldArgTypes, Out},
+ ?debug("New Entry for ~w: ~s\n",
+ [state__lookup_name(Fun, State),
+ t_to_string(t_fun(OldArgTypes, Out))]),
+ NewFunTab = dict:store(Fun, NewEntry, FunTab),
+ State1 = State#state{fun_tab = NewFunTab},
+ state__add_work_from_fun(Tree, State1)
+ end.
+
+state__add_work_from_fun(_Tree, #state{warning_mode = true} = State) ->
+ State;
+state__add_work_from_fun(Tree, #state{callgraph = Callgraph,
+ tree_map = TreeMap} = State) ->
+ case get_label(Tree) of
+ top -> State;
+ Label when is_integer(Label) ->
+ case dialyzer_callgraph:in_neighbours(Label, Callgraph) of
+ none -> State;
+ MFAList ->
+ LabelList = [dialyzer_callgraph:lookup_label(MFA, Callgraph)
+ || MFA <- MFAList],
+ %% Must filter the result for results in this module.
+ FilteredList = [L || {ok, L} <- LabelList, dict:is_key(L, TreeMap)],
+ ?debug("~w: Will try to add:~w\n",
+ [state__lookup_name(Label, State), MFAList]),
+ lists:foldl(fun(L, AccState) ->
+ state__add_work(L, AccState)
+ end, State, FilteredList)
+ end
+ end.
+
+state__add_work(external, State) ->
+ State;
+state__add_work(top, State) ->
+ State;
+state__add_work(Fun, #state{work = Work} = State) ->
+ NewWork = add_work(Fun, Work),
+ State#state{work = NewWork}.
+
+state__get_work(#state{work = Work, tree_map = TreeMap} = State) ->
+ case get_work(Work) of
+ none -> none;
+ {Fun, NewWork} ->
+ {dict:fetch(Fun, TreeMap), State#state{work = NewWork}}
+ end.
+
+state__lookup_call_site(Tree, #state{callgraph = Callgraph}) ->
+ Label = get_label(Tree),
+ dialyzer_callgraph:lookup_call_site(Label, Callgraph).
+
+state__fun_info(external, #state{}) ->
+ external;
+state__fun_info({_, _, _} = MFA, #state{plt = PLT}) ->
+ {MFA,
+ dialyzer_plt:lookup(PLT, MFA),
+ dialyzer_plt:lookup_contract(PLT, MFA),
+ t_any()};
+state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) ->
+ {Sig, Contract} =
+ case dialyzer_callgraph:lookup_name(Fun, CG) of
+ error ->
+ {dialyzer_plt:lookup(PLT, Fun), none};
+ {ok, MFA} ->
+ {dialyzer_plt:lookup(PLT, MFA), dialyzer_plt:lookup_contract(PLT, MFA)}
+ end,
+ LocalRet =
+ case dict:fetch(Fun, FunTab) of
+ {not_handled, {_Args, Ret}} -> Ret;
+ {_Args, Ret} -> Ret
+ end,
+ ?debug("LocalRet: ~s\n", [t_to_string(LocalRet)]),
+ {Fun, Sig, Contract, LocalRet}.
+
+forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) ->
+ {OldArgTypes, OldOut, Fixpoint} =
+ case dict:find(Fun, FunTab) of
+ {ok, {not_handled, {OldArgTypes0, OldOut0}}} ->
+ {OldArgTypes0, OldOut0, false};
+ {ok, {OldArgTypes0, OldOut0}} ->
+ {OldArgTypes0, OldOut0,
+ t_is_subtype(t_product(ArgTypes), t_product(OldArgTypes0))}
+ end,
+ case Fixpoint of
+ true -> State;
+ false ->
+ NewArgTypes = [t_sup(X, Y) ||
+ {X, Y} <- lists:zip(ArgTypes, OldArgTypes)],
+ NewWork = add_work(Fun, Work),
+ ?debug("~w: forwarding args ~s\n",
+ [state__lookup_name(Fun, State),
+ t_to_string(t_product(NewArgTypes))]),
+ NewFunTab = dict:store(Fun, {NewArgTypes, OldOut}, FunTab),
+ State#state{work = NewWork, fun_tab = NewFunTab}
+ end.
+
+-spec state__cleanup(state()) -> state().
+
+state__cleanup(#state{callgraph = Callgraph,
+ races = Races,
+ records = Records}) ->
+ #state{callgraph = dialyzer_callgraph:cleanup(Callgraph),
+ races = dialyzer_races:cleanup(Races),
+ records = Records}.
+
+-spec state__duplicate(state()) -> state().
+
+state__duplicate(#state{callgraph = Callgraph} = State) ->
+ State#state{callgraph = dialyzer_callgraph:duplicate(Callgraph)}.
+
+-spec dispose_state(state()) -> ok.
+
+dispose_state(#state{callgraph = Callgraph}) ->
+ dialyzer_callgraph:dispose_race_server(Callgraph).
+
+-spec state__get_callgraph(state()) -> dialyzer_callgraph:callgraph().
+
+state__get_callgraph(#state{callgraph = Callgraph}) ->
+ Callgraph.
+
+-spec state__get_races(state()) -> dialyzer_races:races().
+
+state__get_races(#state{races = Races}) ->
+ Races.
+
+-spec state__get_records(state()) -> types().
+
+state__get_records(#state{records = Records}) ->
+ Records.
+
+-spec state__put_callgraph(dialyzer_callgraph:callgraph(), state()) ->
+ state().
+
+state__put_callgraph(Callgraph, State) ->
+ State#state{callgraph = Callgraph}.
+
+-spec state__put_races(dialyzer_races:races(), state()) -> state().
+
+state__put_races(Races, State) ->
+ State#state{races = Races}.
+
+-spec state__records_only(state()) -> state().
+
+state__records_only(#state{records = Records}) ->
+ #state{records = Records}.
+
+%%% ===========================================================================
+%%%
+%%% Races
+%%%
+%%% ===========================================================================
+
+is_race_analysis_enabled(#state{races = Races, callgraph = Callgraph}) ->
+ RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
+ RaceAnalysis = dialyzer_races:get_race_analysis(Races),
+ RaceDetection andalso RaceAnalysis.
+
+get_race_list_and_size(#state{races = Races}) ->
+ dialyzer_races:get_race_list_and_size(Races).
+
+renew_race_code(#state{races = Races, callgraph = Callgraph,
+ warning_mode = WarningMode} = State) ->
+ case WarningMode of
+ true -> State;
+ false ->
+ NewCallgraph = dialyzer_callgraph:renew_race_code(Races, Callgraph),
+ State#state{callgraph = NewCallgraph}
+ end.
+
+renew_race_public_tables([Var], #state{races = Races, callgraph = Callgraph,
+ warning_mode = WarningMode} = State) ->
+ case WarningMode of
+ true -> State;
+ false ->
+ Table = dialyzer_races:get_new_table(Races),
+ case Table of
+ no_t -> State;
+ _Other ->
+ VarLabel = get_label(Var),
+ NewCallgraph =
+ dialyzer_callgraph:renew_race_public_tables(VarLabel, Callgraph),
+ State#state{callgraph = NewCallgraph}
+ end
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Worklist
+%%%
+%%% ===========================================================================
+
+init_work(List) ->
+ {List, [], sets:from_list(List)}.
+
+get_work({[], [], _Set}) ->
+ none;
+get_work({[H|T], Rev, Set}) ->
+ {H, {T, Rev, sets:del_element(H, Set)}};
+get_work({[], Rev, Set}) ->
+ get_work({lists:reverse(Rev), [], Set}).
+
+add_work(New, {List, Rev, Set} = Work) ->
+ case sets:is_element(New, Set) of
+ true -> Work;
+ false -> {List, [New|Rev], sets:add_element(New, Set)}
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Utilities.
+%%%
+%%% ===========================================================================
+
+get_line([Line|_]) when is_integer(Line) -> Line;
+get_line([_|Tail]) -> get_line(Tail);
+get_line([]) -> -1.
+
+get_file([]) -> [];
+get_file([{file, File}|_]) -> File;
+get_file([_|Tail]) -> get_file(Tail).
+
+is_compiler_generated(Ann) ->
+ lists:member(compiler_generated, Ann) orelse (get_line(Ann) < 1).
+
+is_literal_record(Tree) ->
+ Ann = cerl:get_ann(Tree),
+ lists:member(record, Ann).
+
+-spec format_args([cerl:cerl()], [type()], state()) ->
+ nonempty_string().
+
+format_args([], [], _State) ->
+ "()";
+format_args(ArgList0, TypeList, State) ->
+ ArgList = fold_literals(ArgList0),
+ "(" ++ format_args_1(ArgList, TypeList, State) ++ ")".
+
+format_args_1([Arg], [Type], State) ->
+ format_arg(Arg) ++ format_type(Type, State);
+format_args_1([Arg|Args], [Type|Types], State) ->
+ String =
+ case cerl:is_literal(Arg) of
+ true -> format_cerl(Arg);
+ false -> format_arg(Arg) ++ format_type(Type, State)
+ end,
+ String ++ "," ++ format_args_1(Args, Types, State).
+
+format_arg(Arg) ->
+ Default = "",
+ case cerl:is_c_var(Arg) of
+ true ->
+ case cerl:var_name(Arg) of
+ Atom when is_atom(Atom) ->
+ case atom_to_list(Atom) of
+ "cor"++_ -> Default;
+ "rec"++_ -> Default;
+ Name -> Name ++ "::"
+ end;
+ _What -> Default
+ end;
+ false ->
+ Default
+ end.
+
+-spec format_type(type(), state()) -> string().
+
+format_type(Type, #state{records = R}) ->
+ t_to_string(Type, R).
+
+-spec format_field_diffs(type(), state()) -> string().
+
+format_field_diffs(RecConstruction, #state{records = R}) ->
+ erl_types:record_field_diffs_to_string(RecConstruction, R).
+
+-spec format_sig_args(type(), state()) -> string().
+
+format_sig_args(Type, #state{opaques = Opaques} = State) ->
+ SigArgs = t_fun_args(Type, Opaques),
+ case SigArgs of
+ [] -> "()";
+ [SArg|SArgs] ->
+ lists:flatten("(" ++ format_type(SArg, State)
+ ++ ["," ++ format_type(T, State) || T <- SArgs] ++ ")")
+ end.
+
+format_cerl(Tree) ->
+ cerl_prettypr:format(cerl:set_ann(Tree, []),
+ [{hook, dialyzer_utils:pp_hook()},
+ {noann, true},
+ {paper, 100000}, %% These guys strip
+ {ribbon, 100000} %% newlines.
+ ]).
+
+format_patterns(Pats0) ->
+ Pats = fold_literals(Pats0),
+ NewPats = map_pats(cerl:c_values(Pats)),
+ String = format_cerl(NewPats),
+ case Pats of
+ [PosVar] ->
+ case cerl:is_c_var(PosVar) andalso (cerl:var_name(PosVar) =/= '') of
+ true -> "variable "++String;
+ false -> "pattern "++String
+ end;
+ _ ->
+ "pattern "++String
+ end.
+
+map_pats(Pats) ->
+ Fun = fun(Tree) ->
+ case cerl:is_c_var(Tree) of
+ true ->
+ case cerl:var_name(Tree) of
+ Atom when is_atom(Atom) ->
+ case atom_to_list(Atom) of
+ "cor"++_ -> cerl:c_var('');
+ "rec"++_ -> cerl:c_var('');
+ _ -> cerl:set_ann(Tree, [])
+ end;
+ _What -> cerl:c_var('')
+ end;
+ false ->
+ cerl:set_ann(Tree, [])
+ end
+ end,
+ cerl_trees:map(Fun, Pats).
+
+fold_literals(TreeList) ->
+ [cerl:fold_literal(Tree) || Tree <- TreeList].
+
+type(Tree) ->
+ Folded = cerl:fold_literal(Tree),
+ case cerl:type(Folded) of
+ literal -> {literal, Folded};
+ Type -> Type
+ end.
+
+is_literal(Tree) ->
+ Folded = cerl:fold_literal(Tree),
+ case cerl:is_literal(Folded) of
+ true -> {yes, Folded};
+ false -> no
+ end.
+
+parent_allows_this(FunLbl, #state{callgraph = Callgraph, plt = Plt} =State) ->
+ case state__is_escaping(FunLbl, State) of
+ false -> false; % if it isn't escaping it can't be a return value
+ true ->
+ case state__lookup_name(FunLbl, State) of
+ {_M, _F, _A} -> false; % if it has a name it is not a fun
+ _ ->
+ case dialyzer_callgraph:in_neighbours(FunLbl, Callgraph) of
+ [Parent] ->
+ case state__lookup_name(Parent, State) of
+ {_M, _F, _A} = PMFA ->
+ case dialyzer_plt:lookup_contract(Plt, PMFA) of
+ none -> false;
+ {value, C} ->
+ GenRet = dialyzer_contracts:get_contract_return(C),
+ case erl_types:t_is_fun(GenRet) of
+ false -> false; % element of structure? far-fetched...
+ true -> t_is_unit(t_fun_range(GenRet))
+ end
+ end;
+ _ -> false % parent should have a name to have a contract
+ end;
+ _ -> false % called in other funs? far-fetched...
+ end
+ end
+ end.
+
+find_function({_, _, _} = MFA, _State) ->
+ MFA;
+find_function(top, _State) ->
+ top;
+find_function(FunLbl, #state{fun_homes = Homes}) ->
+ dict:fetch(FunLbl, Homes).
+
+classify_returns(Tree) ->
+ case find_terminals(cerl:fun_body(Tree)) of
+ {false, false} -> no_match;
+ {true, false} -> only_explicit;
+ {false, true} -> only_normal;
+ {true, true} -> both
+ end.
+
+find_terminals(Tree) ->
+ case cerl:type(Tree) of
+ apply -> {false, true};
+ binary -> {false, true};
+ bitstr -> {false, true};
+ call ->
+ M0 = cerl:call_module(Tree),
+ F0 = cerl:call_name(Tree),
+ A = length(cerl:call_args(Tree)),
+ case {is_literal(M0), is_literal(F0)} of
+ {{yes, LitM}, {yes, LitF}} ->
+ M = cerl:concrete(LitM),
+ F = cerl:concrete(LitF),
+ case (erl_bif_types:is_known(M, F, A)
+ andalso t_is_none(erl_bif_types:type(M, F, A))) of
+ true -> {true, false};
+ false -> {false, true}
+ end;
+ _ ->
+ %% We cannot make assumptions. Say that both are true.
+ {true, true}
+ end;
+ 'case' -> find_terminals_list(cerl:case_clauses(Tree));
+ 'catch' -> find_terminals(cerl:catch_body(Tree));
+ clause -> find_terminals(cerl:clause_body(Tree));
+ cons -> {false, true};
+ 'fun' -> {false, true};
+ 'let' -> find_terminals(cerl:let_body(Tree));
+ letrec -> find_terminals(cerl:letrec_body(Tree));
+ literal -> {false, true};
+ map -> {false, true};
+ primop -> {false, false}; %% match_fail, etc. are not explicit exits.
+ 'receive' ->
+ Timeout = cerl:receive_timeout(Tree),
+ Clauses = cerl:receive_clauses(Tree),
+ case (cerl:is_literal(Timeout) andalso
+ (cerl:concrete(Timeout) =:= infinity)) of
+ true ->
+ if Clauses =:= [] -> {false, true}; %% A never ending receive.
+ true -> find_terminals_list(Clauses)
+ end;
+ false -> find_terminals_list([cerl:receive_action(Tree)|Clauses])
+ end;
+ seq -> find_terminals(cerl:seq_body(Tree));
+ 'try' ->
+ find_terminals_list([cerl:try_handler(Tree), cerl:try_body(Tree)]);
+ tuple -> {false, true};
+ values -> {false, true};
+ var -> {false, true}
+ end.
+
+find_terminals_list(List) ->
+ find_terminals_list(List, false, false).
+
+find_terminals_list([Tree|Left], Explicit1, Normal1) ->
+ {Explicit2, Normal2} = find_terminals(Tree),
+ case {Explicit1 or Explicit2, Normal1 or Normal2} of
+ {true, true} = Ans -> Ans;
+ {NewExplicit, NewNormal} ->
+ find_terminals_list(Left, NewExplicit, NewNormal)
+ end;
+find_terminals_list([], Explicit, Normal) ->
+ {Explicit, Normal}.
+
+%%----------------------------------------------------------------------------
+
+-ifdef(DEBUG_PP).
+debug_pp(Tree, true) ->
+ io:put_chars(cerl_prettypr:format(Tree, [{hook, cerl_typean:pp_hook()}])),
+ io:nl(),
+ ok;
+debug_pp(Tree, false) ->
+ io:put_chars(cerl_prettypr:format(strip_annotations(Tree))),
+ io:nl(),
+ ok.
+
+strip_annotations(Tree) ->
+ Fun = fun(T) ->
+ case cerl:type(T) of
+ var ->
+ cerl:set_ann(T, [{label, cerl_trees:get_label(T)}]);
+ 'fun' ->
+ cerl:set_ann(T, [{label, cerl_trees:get_label(T)}]);
+ _ ->
+ cerl:set_ann(T, [])
+ end
+ end,
+ cerl_trees:map(Fun, Tree).
+
+-else.
+
+debug_pp(_Tree, _UseHook) ->
+ ok.
+-endif.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl
new file mode 100644
index 0000000000..637927c932
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl
@@ -0,0 +1,2494 @@
+%% -*- erlang-indent-level: 2 -*-
+%%-----------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%----------------------------------------------------------------------
+%%% File : dialyzer_races.erl
+%%% Author : Maria Christakis <[email protected]>
+%%% Description : Utility functions for race condition detection
+%%%
+%%% Created : 21 Nov 2008 by Maria Christakis <[email protected]>
+%%%----------------------------------------------------------------------
+-module(dialyzer_races).
+
+%% Race Analysis
+
+-export([store_race_call/5, race/1, get_race_warnings/2, format_args/4]).
+
+%% Record Interfaces
+
+-export([beg_clause_new/3, cleanup/1, end_case_new/1, end_clause_new/3,
+ get_curr_fun/1, get_curr_fun_args/1, get_new_table/1,
+ get_race_analysis/1, get_race_list/1, get_race_list_size/1,
+ get_race_list_and_size/1,
+ let_tag_new/2, new/0, put_curr_fun/3, put_fun_args/2,
+ put_race_analysis/2, put_race_list/3]).
+
+-export_type([races/0, core_vars/0]).
+
+-include("dialyzer.hrl").
+
+%%% ===========================================================================
+%%%
+%%% Definitions
+%%%
+%%% ===========================================================================
+
+-define(local, 5).
+-define(no_arg, no_arg).
+-define(no_label, no_label).
+-define(bypassed, bypassed).
+
+-define(WARN_WHEREIS_REGISTER, warn_whereis_register).
+-define(WARN_WHEREIS_UNREGISTER, warn_whereis_unregister).
+-define(WARN_ETS_LOOKUP_INSERT, warn_ets_lookup_insert).
+-define(WARN_MNESIA_DIRTY_READ_WRITE, warn_mnesia_dirty_read_write).
+-define(WARN_NO_WARN, warn_no_warn).
+
+%%% ===========================================================================
+%%%
+%%% Local Types
+%%%
+%%% ===========================================================================
+
+-type label_type() :: label() | [label()] | {label()} | ?no_label.
+-type args() :: [label_type() | [string()]].
+-type core_vars() :: cerl:cerl() | ?no_arg | ?bypassed.
+-type var_to_map1() :: core_vars() | [cerl:cerl()].
+-type var_to_map2() :: cerl:cerl() | [cerl:cerl()] | ?bypassed.
+-type core_args() :: [core_vars()] | 'empty'.
+-type op() :: 'bind' | 'unbind'.
+
+-type dep_calls() :: 'whereis' | 'ets_lookup' | 'mnesia_dirty_read'.
+-type warn_calls() :: 'register' | 'unregister' | 'ets_insert'
+ | 'mnesia_dirty_write'.
+-type call() :: 'whereis' | 'register' | 'unregister' | 'ets_new'
+ | 'ets_lookup' | 'ets_insert' | 'mnesia_dirty_read1'
+ | 'mnesia_dirty_read2' | 'mnesia_dirty_write1'
+ | 'mnesia_dirty_write2' | 'function_call'.
+-type race_tag() :: 'whereis_register' | 'whereis_unregister'
+ | 'ets_lookup_insert' | 'mnesia_dirty_read_write'.
+
+%% The following type is similar to the raw_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(), warning_info(), {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() | 'undefined',
+ pats :: var_to_map1() | 'undefined',
+ guard :: cerl:cerl() | 'undefined'}).
+-record(end_clause, {arg :: var_to_map1() | 'undefined',
+ pats :: var_to_map1() | 'undefined',
+ guard :: cerl:cerl() | 'undefined'}).
+-record(end_case, {clauses :: [#end_clause{}]}).
+-record(curr_fun, {status :: 'in' | 'out' | 'undefined',
+ mfa :: dialyzer_callgraph:mfa_or_funlbl()
+ | 'undefined',
+ label :: label() | 'undefined',
+ def_vars :: [core_vars()] | 'undefined',
+ arg_types :: [erl_types:erl_type()] | 'undefined',
+ call_vars :: [core_vars()] | 'undefined',
+ var_map :: dict:dict() | 'undefined'}).
+-record(dep_call, {call_name :: dep_calls(),
+ args :: args() | 'undefined',
+ arg_types :: [erl_types:erl_type()],
+ vars :: [core_vars()],
+ state :: dialyzer_dataflow:state(),
+ file_line :: file_line(),
+ var_map :: dict:dict() | 'undefined'}).
+-record(fun_call, {caller :: dialyzer_callgraph:mfa_or_funlbl(),
+ callee :: dialyzer_callgraph:mfa_or_funlbl(),
+ arg_types :: [erl_types:erl_type()],
+ vars :: [core_vars()]}).
+-record(let_tag, {var :: var_to_map1(),
+ arg :: var_to_map1()}).
+-record(warn_call, {call_name :: warn_calls(),
+ args :: args(),
+ var_map :: dict:dict() | 'undefined'}).
+
+-type case_tags() :: 'beg_case' | #beg_clause{} | #end_clause{} | #end_case{}.
+-type code() :: [#dep_call{} | #fun_call{} | #warn_call{} |
+ #curr_fun{} | #let_tag{} | case_tags() | race_tag()].
+
+-type table_var() :: label() | ?no_label.
+-type table() :: {'named', table_var(), [string()]} | 'other' | 'no_t'.
+
+-record(race_fun, {mfa :: mfa(),
+ args :: args(),
+ arg_types :: [erl_types:erl_type()],
+ vars :: [core_vars()],
+ file_line :: file_line(),
+ index :: non_neg_integer(),
+ fun_mfa :: dialyzer_callgraph:mfa_or_funlbl(),
+ fun_label :: label()}).
+
+-record(races, {curr_fun :: dialyzer_callgraph:mfa_or_funlbl()
+ | 'undefined',
+ curr_fun_label :: label() | 'undefined',
+ curr_fun_args = 'empty' :: core_args(),
+ new_table = 'no_t' :: table(),
+ race_list = [] :: code(),
+ race_list_size = 0 :: non_neg_integer(),
+ race_tags = [] :: [#race_fun{}],
+ %% true for fun types and warning mode
+ race_analysis = false :: boolean(),
+ race_warnings = [] :: [dial_race_warning()]}).
+
+%%% ===========================================================================
+%%%
+%%% Exported Types
+%%%
+%%% ===========================================================================
+
+-opaque races() :: #races{}.
+
+%%% ===========================================================================
+%%%
+%%% Race Analysis
+%%%
+%%% ===========================================================================
+
+-spec store_race_call(dialyzer_callgraph:mfa_or_funlbl(),
+ [erl_types:erl_type()], [core_vars()],
+ file_line(), dialyzer_dataflow:state()) ->
+ dialyzer_dataflow:state().
+
+store_race_call(Fun, ArgTypes, Args, FileLine, State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ CurrFun = Races#races.curr_fun,
+ CurrFunLabel = Races#races.curr_fun_label,
+ RaceTags = Races#races.race_tags,
+ CleanState = dialyzer_dataflow:state__records_only(State),
+ {NewRaceList, NewRaceListSize, NewRaceTags, NewTable} =
+ case CurrFun of
+ {_Module, module_info, A} when A =:= 0 orelse A =:= 1 ->
+ {[], 0, RaceTags, no_t};
+ _Thing ->
+ RaceList = Races#races.race_list,
+ RaceListSize = Races#races.race_list_size,
+ case Fun of
+ {erlang, get_module_info, A} when A =:= 1 orelse A =:= 2 ->
+ {[], 0, RaceTags, no_t};
+ {erlang, register, 2} ->
+ VarArgs = format_args(Args, ArgTypes, CleanState, register),
+ RaceFun = #race_fun{mfa = Fun, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ file_line = FileLine, index = RaceListSize,
+ fun_mfa = CurrFun, fun_label = CurrFunLabel},
+ {[#warn_call{call_name = register, args = VarArgs}|
+ RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t};
+ {erlang, unregister, 1} ->
+ VarArgs = format_args(Args, ArgTypes, CleanState, unregister),
+ RaceFun = #race_fun{mfa = Fun, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ file_line = FileLine, index = RaceListSize,
+ fun_mfa = CurrFun, fun_label = CurrFunLabel},
+ {[#warn_call{call_name = unregister, args = VarArgs}|
+ RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t};
+ {erlang, whereis, 1} ->
+ VarArgs = format_args(Args, ArgTypes, CleanState, whereis),
+ {[#dep_call{call_name = whereis, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ state = CleanState, file_line = FileLine}|
+ RaceList], RaceListSize + 1, RaceTags, no_t};
+ {ets, insert, 2} ->
+ VarArgs = format_args(Args, ArgTypes, CleanState, ets_insert),
+ RaceFun = #race_fun{mfa = Fun, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ file_line = FileLine, index = RaceListSize,
+ fun_mfa = CurrFun, fun_label = CurrFunLabel},
+ {[#warn_call{call_name = ets_insert, args = VarArgs}|
+ RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t};
+ {ets, lookup, 2} ->
+ VarArgs = format_args(Args, ArgTypes, CleanState, ets_lookup),
+ {[#dep_call{call_name = ets_lookup, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ state = CleanState, file_line = FileLine}|
+ RaceList], RaceListSize + 1, RaceTags, no_t};
+ {ets, new, 2} ->
+ VarArgs = format_args(Args, ArgTypes, CleanState, ets_new),
+ [VarArgs1, VarArgs2, _, Options] = VarArgs,
+ NewTable1 =
+ case lists:member("'public'", Options) of
+ true ->
+ case lists:member("'named_table'", Options) of
+ true ->
+ {named, VarArgs1, VarArgs2};
+ false -> other
+ end;
+ false -> no_t
+ end,
+ {RaceList, RaceListSize, RaceTags, NewTable1};
+ {mnesia, dirty_read, A} when A =:= 1 orelse A =:= 2 ->
+ VarArgs =
+ case A of
+ 1 ->
+ format_args(Args, ArgTypes, CleanState, mnesia_dirty_read1);
+ 2 ->
+ format_args(Args, ArgTypes, CleanState, mnesia_dirty_read2)
+ end,
+ {[#dep_call{call_name = mnesia_dirty_read, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ state = CleanState, file_line = FileLine}|RaceList],
+ RaceListSize + 1, RaceTags, no_t};
+ {mnesia, dirty_write, A} when A =:= 1 orelse A =:= 2 ->
+ VarArgs =
+ case A of
+ 1 ->
+ format_args(Args, ArgTypes, CleanState, mnesia_dirty_write1);
+ 2 ->
+ format_args(Args, ArgTypes, CleanState, mnesia_dirty_write2)
+ end,
+ RaceFun = #race_fun{mfa = Fun, args = VarArgs,
+ arg_types = ArgTypes, vars = Args,
+ file_line = FileLine, index = RaceListSize,
+ fun_mfa = CurrFun, fun_label = CurrFunLabel},
+ {[#warn_call{call_name = mnesia_dirty_write,
+ args = VarArgs}|RaceList],
+ RaceListSize + 1, [RaceFun|RaceTags], no_t};
+ Int when is_integer(Int) ->
+ {[#fun_call{caller = CurrFun, callee = Int, arg_types = ArgTypes,
+ vars = Args}|RaceList],
+ RaceListSize + 1, RaceTags, no_t};
+ _Other ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ case digraph:vertex(dialyzer_callgraph:get_digraph(Callgraph),
+ Fun) of
+ {Fun, confirmed} ->
+ {[#fun_call{caller = CurrFun, callee = Fun,
+ arg_types = ArgTypes, vars = Args}|RaceList],
+ RaceListSize + 1, RaceTags, no_t};
+ false ->
+ {RaceList, RaceListSize, RaceTags, no_t}
+ end
+ end
+ end,
+ state__renew_info(NewRaceList, NewRaceListSize, NewRaceTags, NewTable, State).
+
+-spec race(dialyzer_dataflow:state()) -> dialyzer_dataflow:state().
+
+race(State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ RaceTags = Races#races.race_tags,
+ RetState =
+ case RaceTags of
+ [] -> State;
+ [#race_fun{mfa = Fun,
+ args = VarArgs, arg_types = ArgTypes,
+ vars = Args, file_line = FileLine,
+ index = Index, fun_mfa = CurrFun,
+ fun_label = CurrFunLabel}|T] ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ {ok, [_Args, Code]} =
+ dict:find(CurrFun, dialyzer_callgraph:get_race_code(Callgraph)),
+ RaceList = lists:reverse(Code),
+ RaceWarnTag =
+ case Fun of
+ {erlang, register, 2} -> ?WARN_WHEREIS_REGISTER;
+ {erlang, unregister, 1} -> ?WARN_WHEREIS_UNREGISTER;
+ {ets, insert, 2} -> ?WARN_ETS_LOOKUP_INSERT;
+ {mnesia, dirty_write, _A} -> ?WARN_MNESIA_DIRTY_READ_WRITE
+ end,
+ State1 =
+ state__renew_curr_fun(CurrFun,
+ state__renew_curr_fun_label(CurrFunLabel,
+ state__renew_race_list(lists:nthtail(length(RaceList) - Index,
+ RaceList), State))),
+ DepList = fixup_race_list(RaceWarnTag, VarArgs, State1),
+ {State2, RaceWarn} =
+ get_race_warn(Fun, Args, ArgTypes, DepList, State),
+ {File, Line} = FileLine,
+ CurrMFA = dialyzer_dataflow:state__find_function(CurrFun, State),
+ WarningInfo = {File, Line, CurrMFA},
+ race(
+ state__add_race_warning(
+ state__renew_race_tags(T, State2), RaceWarn, RaceWarnTag,
+ WarningInfo))
+ end,
+ state__renew_race_tags([], RetState).
+
+fixup_race_list(RaceWarnTag, WarnVarArgs, State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ CurrFun = Races#races.curr_fun,
+ CurrFunLabel = Races#races.curr_fun_label,
+ RaceList = Races#races.race_list,
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ Digraph = dialyzer_callgraph:get_digraph(Callgraph),
+ Calls = digraph:edges(Digraph),
+ RaceTag =
+ case RaceWarnTag of
+ ?WARN_WHEREIS_REGISTER -> whereis_register;
+ ?WARN_WHEREIS_UNREGISTER -> whereis_unregister;
+ ?WARN_ETS_LOOKUP_INSERT -> ets_lookup_insert;
+ ?WARN_MNESIA_DIRTY_READ_WRITE -> mnesia_dirty_read_write
+ end,
+ NewRaceList = [RaceTag|RaceList],
+ CleanState = dialyzer_dataflow:state__cleanup(State),
+ NewState = state__renew_race_list(NewRaceList, CleanState),
+ DepList1 =
+ fixup_race_forward_pullout(CurrFun, CurrFunLabel, Calls,
+ lists:reverse(NewRaceList), [], CurrFun,
+ WarnVarArgs, RaceWarnTag, dict:new(),
+ [], [], [], 2 * ?local, NewState),
+ Parents = fixup_race_backward(CurrFun, Calls, Calls, [], ?local),
+ UParents = lists:usort(Parents),
+ Filtered = filter_parents(UParents, UParents, Digraph),
+ NewParents =
+ case lists:member(CurrFun, Filtered) of
+ true -> Filtered;
+ false -> [CurrFun|Filtered]
+ end,
+ DepList2 =
+ fixup_race_list_helper(NewParents, Calls, CurrFun, WarnVarArgs,
+ RaceWarnTag, NewState),
+ dialyzer_dataflow:dispose_state(CleanState),
+ lists:usort(cleanup_dep_calls(DepList1 ++ DepList2)).
+
+fixup_race_list_helper(Parents, Calls, CurrFun, WarnVarArgs, RaceWarnTag,
+ State) ->
+ case Parents of
+ [] -> [];
+ [Head|Tail] ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ Code =
+ case dict:find(Head, dialyzer_callgraph:get_race_code(Callgraph)) of
+ error -> [];
+ {ok, [_A, C]} -> C
+ end,
+ {ok, FunLabel} = dialyzer_callgraph:lookup_label(Head, Callgraph),
+ DepList1 =
+ fixup_race_forward_pullout(Head, FunLabel, Calls, Code, [], CurrFun,
+ WarnVarArgs, RaceWarnTag, dict:new(),
+ [], [], [], 2 * ?local, State),
+ DepList2 =
+ fixup_race_list_helper(Tail, Calls, CurrFun, WarnVarArgs,
+ RaceWarnTag, State),
+ DepList1 ++ DepList2
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Forward Analysis
+%%%
+%%% ===========================================================================
+
+fixup_race_forward_pullout(CurrFun, CurrFunLabel, Calls, Code, RaceList,
+ InitFun, WarnVarArgs, RaceWarnTag, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NestingLevel,
+ State) ->
+ TState = dialyzer_dataflow:state__duplicate(State),
+ {DepList, NewCurrFun, NewCurrFunLabel, NewCalls,
+ NewCode, NewRaceList, NewRaceVarMap, NewFunDefVars,
+ NewFunCallVars, NewFunArgTypes, NewNestingLevel} =
+ fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList,
+ InitFun, WarnVarArgs, RaceWarnTag, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NestingLevel,
+ cleanup_race_code(TState)),
+ dialyzer_dataflow:dispose_state(TState),
+ case NewCode of
+ [] -> DepList;
+ [#fun_call{caller = NewCurrFun, callee = Call, arg_types = FunTypes,
+ vars = FunArgs}|Tail] ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ OkCall = {ok, Call},
+ {Name, Label} =
+ case is_integer(Call) of
+ true ->
+ case dialyzer_callgraph:lookup_name(Call, Callgraph) of
+ error -> {OkCall, OkCall};
+ N -> {N, OkCall}
+ end;
+ false ->
+ {OkCall, dialyzer_callgraph:lookup_label(Call, Callgraph)}
+ end,
+ {NewCurrFun1, NewCurrFunLabel1, NewCalls1, NewCode1, NewRaceList1,
+ NewRaceVarMap1, NewFunDefVars1, NewFunCallVars1, NewFunArgTypes1,
+ NewNestingLevel1} =
+ case Label =:= error of
+ true ->
+ {NewCurrFun, NewCurrFunLabel, NewCalls, Tail, NewRaceList,
+ NewRaceVarMap, NewFunDefVars, NewFunCallVars, NewFunArgTypes,
+ NewNestingLevel};
+ false ->
+ {ok, Fun} = Name,
+ {ok, Int} = Label,
+ case dict:find(Fun, dialyzer_callgraph:get_race_code(Callgraph)) of
+ error ->
+ {NewCurrFun, NewCurrFunLabel, NewCalls, Tail, NewRaceList,
+ NewRaceVarMap, NewFunDefVars, NewFunCallVars, NewFunArgTypes,
+ NewNestingLevel};
+ {ok, [Args, CodeB]} ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ {RetCurrFun, RetCurrFunLabel, RetCalls, RetCode,
+ RetRaceList, RetRaceVarMap, RetFunDefVars, RetFunCallVars,
+ RetFunArgTypes, RetNestingLevel} =
+ fixup_race_forward_helper(NewCurrFun,
+ NewCurrFunLabel, Fun, Int, NewCalls, NewCalls,
+ [#curr_fun{status = out, mfa = NewCurrFun,
+ label = NewCurrFunLabel,
+ var_map = NewRaceVarMap,
+ def_vars = NewFunDefVars,
+ call_vars = NewFunCallVars,
+ arg_types = NewFunArgTypes}|
+ Tail],
+ NewRaceList, InitFun, FunArgs, FunTypes, RaceWarnTag,
+ NewRaceVarMap, NewFunDefVars, NewFunCallVars,
+ NewFunArgTypes, NewNestingLevel, Args, CodeB,
+ Races#races.race_list),
+ case RetCode of
+ [#curr_fun{}|_CodeTail] ->
+ {NewCurrFun, NewCurrFunLabel, RetCalls, RetCode,
+ RetRaceList, NewRaceVarMap, NewFunDefVars,
+ NewFunCallVars, NewFunArgTypes, RetNestingLevel};
+ _Else ->
+ {RetCurrFun, RetCurrFunLabel, RetCalls, RetCode,
+ RetRaceList, RetRaceVarMap, RetFunDefVars,
+ RetFunCallVars, RetFunArgTypes, RetNestingLevel}
+ end
+ end
+ end,
+ DepList ++
+ fixup_race_forward_pullout(NewCurrFun1, NewCurrFunLabel1, NewCalls1,
+ NewCode1, NewRaceList1, InitFun, WarnVarArgs,
+ RaceWarnTag, NewRaceVarMap1, NewFunDefVars1,
+ NewFunCallVars1, NewFunArgTypes1,
+ NewNestingLevel1, State)
+ end.
+
+fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList,
+ InitFun, WarnVarArgs, RaceWarnTag, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NestingLevel,
+ State) ->
+ case Code of
+ [] ->
+ {[], CurrFun, CurrFunLabel, Calls, Code, RaceList, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NestingLevel};
+ [Head|Tail] ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ {NewRL, DepList, NewNL, Return} =
+ case Head of
+ #dep_call{call_name = whereis} ->
+ case RaceWarnTag of
+ WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse
+ WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER ->
+ {[Head#dep_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
+ _Other ->
+ {RaceList, [], NestingLevel, false}
+ end;
+ #dep_call{call_name = ets_lookup} ->
+ case RaceWarnTag of
+ ?WARN_ETS_LOOKUP_INSERT ->
+ {[Head#dep_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
+ _Other ->
+ {RaceList, [], NestingLevel, false}
+ end;
+ #dep_call{call_name = mnesia_dirty_read} ->
+ case RaceWarnTag of
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ {[Head#dep_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
+ _Other ->
+ {RaceList, [], NestingLevel, false}
+ end;
+ #warn_call{call_name = RegCall} when RegCall =:= register orelse
+ RegCall =:= unregister ->
+ case RaceWarnTag of
+ WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse
+ WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER ->
+ {[Head#warn_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
+ _Other ->
+ {RaceList, [], NestingLevel, false}
+ end;
+ #warn_call{call_name = ets_insert} ->
+ case RaceWarnTag of
+ ?WARN_ETS_LOOKUP_INSERT ->
+ {[Head#warn_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
+ _Other ->
+ {RaceList, [], NestingLevel, false}
+ end;
+ #warn_call{call_name = mnesia_dirty_write} ->
+ case RaceWarnTag of
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ {[Head#warn_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
+ _Other ->
+ {RaceList, [], NestingLevel, false}
+ end;
+ #fun_call{caller = CurrFun, callee = InitFun} ->
+ {RaceList, [], NestingLevel, false};
+ #fun_call{caller = CurrFun} ->
+ {RaceList, [], NestingLevel - 1, false};
+ beg_case ->
+ {[Head|RaceList], [], NestingLevel, false};
+ #beg_clause{} ->
+ {[#beg_clause{}|RaceList], [], NestingLevel, false};
+ #end_clause{} ->
+ {[#end_clause{}|RaceList], [], NestingLevel, false};
+ #end_case{} ->
+ {[Head|RaceList], [], NestingLevel, false};
+ #let_tag{} ->
+ {RaceList, [], NestingLevel, false};
+ #curr_fun{status = in, mfa = InitFun,
+ label = _InitFunLabel, var_map = _NewRVM,
+ def_vars = NewFDV, call_vars = NewFCV,
+ arg_types = _NewFAT} ->
+ {[#curr_fun{status = out, var_map = RaceVarMap,
+ def_vars = NewFDV, call_vars = NewFCV}|
+ RaceList], [], NestingLevel - 1, false};
+ #curr_fun{status = in, def_vars = NewFDV,
+ call_vars = NewFCV} ->
+ {[#curr_fun{status = out, var_map = RaceVarMap,
+ def_vars = NewFDV, call_vars = NewFCV}|
+ RaceList],
+ [], NestingLevel - 1, false};
+ #curr_fun{status = out} ->
+ {[#curr_fun{status = in, var_map = RaceVarMap}|RaceList], [],
+ NestingLevel + 1, false};
+ RaceTag ->
+ PublicTables = dialyzer_callgraph:get_public_tables(Callgraph),
+ NamedTables = dialyzer_callgraph:get_named_tables(Callgraph),
+ WarnVarArgs1 =
+ var_type_analysis(FunDefVars, FunArgTypes, WarnVarArgs,
+ RaceWarnTag, RaceVarMap,
+ dialyzer_dataflow:state__records_only(State)),
+ {NewDepList, IsPublic, _Return} =
+ get_deplist_paths(RaceList, WarnVarArgs1, RaceWarnTag,
+ RaceVarMap, 0, PublicTables, NamedTables),
+ {NewHead, NewDepList1} =
+ case RaceTag of
+ whereis_register ->
+ {[#warn_call{call_name = register, args = WarnVarArgs,
+ var_map = RaceVarMap}],
+ NewDepList};
+ whereis_unregister ->
+ {[#warn_call{call_name = unregister, args = WarnVarArgs,
+ var_map = RaceVarMap}],
+ NewDepList};
+ ets_lookup_insert ->
+ NewWarnCall =
+ [#warn_call{call_name = ets_insert, args = WarnVarArgs,
+ var_map = RaceVarMap}],
+ [Tab, Names, _, _] = WarnVarArgs,
+ case IsPublic orelse
+ compare_var_list(Tab, PublicTables, RaceVarMap)
+ orelse
+ length(Names -- NamedTables) < length(Names) of
+ true ->
+ {NewWarnCall, NewDepList};
+ false -> {NewWarnCall, []}
+ end;
+ mnesia_dirty_read_write ->
+ {[#warn_call{call_name = mnesia_dirty_write,
+ args = WarnVarArgs, var_map = RaceVarMap}],
+ NewDepList}
+ end,
+ {NewHead ++ RaceList, NewDepList1, NestingLevel,
+ is_last_race(RaceTag, InitFun, Tail, Callgraph)}
+ end,
+ {NewCurrFun, NewCurrFunLabel, NewCode, NewRaceList, NewRaceVarMap,
+ NewFunDefVars, NewFunCallVars, NewFunArgTypes, NewNestingLevel,
+ PullOut} =
+ case Head of
+ #fun_call{caller = CurrFun} ->
+ case NewNL =:= 0 of
+ true ->
+ {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL, false};
+ false ->
+ {CurrFun, CurrFunLabel, Code, NewRL, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL, true}
+ end;
+ #beg_clause{arg = Arg, pats = Pats, guard = Guard} ->
+ {RaceVarMap1, RemoveClause} =
+ race_var_map_guard(Arg, Pats, Guard, RaceVarMap, bind),
+ case RemoveClause of
+ true ->
+ {RaceList2,
+ #curr_fun{mfa = CurrFun2, label = CurrFunLabel2,
+ var_map = RaceVarMap2, def_vars = FunDefVars2,
+ call_vars = FunCallVars2, arg_types = FunArgTypes2},
+ Code2, NestingLevel2} =
+ remove_clause(NewRL,
+ #curr_fun{mfa = CurrFun, label = CurrFunLabel,
+ var_map = RaceVarMap1,
+ def_vars = FunDefVars,
+ call_vars = FunCallVars,
+ arg_types = FunArgTypes},
+ Tail, NewNL),
+ {CurrFun2, CurrFunLabel2, Code2, RaceList2,
+ RaceVarMap2, FunDefVars2, FunCallVars2, FunArgTypes2,
+ NestingLevel2, false};
+ false ->
+ {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL, false}
+ end;
+ #end_clause{arg = Arg, pats = Pats, guard = Guard} ->
+ {RaceVarMap1, _RemoveClause} =
+ race_var_map_guard(Arg, Pats, Guard, RaceVarMap, unbind),
+ {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL,
+ false};
+ #end_case{clauses = Clauses} ->
+ RaceVarMap1 =
+ race_var_map_clauses(Clauses, RaceVarMap),
+ {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL,
+ false};
+ #let_tag{var = Var, arg = Arg} ->
+ {CurrFun, CurrFunLabel, Tail, NewRL,
+ race_var_map(Var, Arg, RaceVarMap, bind), FunDefVars,
+ FunCallVars, FunArgTypes, NewNL, false};
+ #curr_fun{mfa = CurrFun1, label = CurrFunLabel1,
+ var_map = RaceVarMap1, def_vars = FunDefVars1,
+ call_vars = FunCallVars1, arg_types = FunArgTypes1} ->
+ case NewNL =:= 0 of
+ true ->
+ {CurrFun, CurrFunLabel,
+ remove_nonlocal_functions(Tail, 1), NewRL, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL, false};
+ false ->
+ {CurrFun1, CurrFunLabel1, Tail, NewRL, RaceVarMap1,
+ FunDefVars1, FunCallVars1, FunArgTypes1, NewNL, false}
+ end;
+ _Thing ->
+ {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap,
+ FunDefVars, FunCallVars, FunArgTypes, NewNL, false}
+ end,
+ case Return of
+ true ->
+ {DepList, NewCurrFun, NewCurrFunLabel, Calls,
+ [], NewRaceList, NewRaceVarMap, NewFunDefVars,
+ NewFunCallVars, NewFunArgTypes, NewNestingLevel};
+ false ->
+ NewNestingLevel1 =
+ case NewNestingLevel =:= 0 of
+ true -> NewNestingLevel + 1;
+ false -> NewNestingLevel
+ end,
+ case PullOut of
+ true ->
+ {DepList, NewCurrFun, NewCurrFunLabel, Calls,
+ NewCode, NewRaceList, NewRaceVarMap, NewFunDefVars,
+ NewFunCallVars, NewFunArgTypes, NewNestingLevel1};
+ false ->
+ {RetDepList, NewCurrFun1, NewCurrFunLabel1, NewCalls1,
+ NewCode1, NewRaceList1, NewRaceVarMap1, NewFunDefVars1,
+ NewFunCallVars1, NewFunArgTypes1, NewNestingLevel2} =
+ fixup_race_forward(NewCurrFun, NewCurrFunLabel, Calls,
+ NewCode, NewRaceList, InitFun, WarnVarArgs,
+ RaceWarnTag, NewRaceVarMap, NewFunDefVars,
+ NewFunCallVars, NewFunArgTypes,
+ NewNestingLevel1, State),
+ {DepList ++ RetDepList, NewCurrFun1, NewCurrFunLabel1,
+ NewCalls1, NewCode1, NewRaceList1, NewRaceVarMap1,
+ NewFunDefVars1, NewFunCallVars1, NewFunArgTypes1,
+ NewNestingLevel2}
+ end
+ end
+ end.
+
+get_deplist_paths(RaceList, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel,
+ PublicTables, NamedTables) ->
+ case RaceList of
+ [] -> {[], false, true};
+ [Head|Tail] ->
+ case Head of
+ #end_case{} ->
+ {RaceList1, DepList1, IsPublic1, Continue1} =
+ handle_case(Tail, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel,
+ PublicTables, NamedTables),
+ case Continue1 of
+ true ->
+ {DepList2, IsPublic2, Continue2} =
+ get_deplist_paths(RaceList1, WarnVarArgs, RaceWarnTag,
+ RaceVarMap, CurrLevel, PublicTables,
+ NamedTables),
+ {DepList1 ++ DepList2, IsPublic1 orelse IsPublic2, Continue2};
+ false -> {DepList1, IsPublic1, false}
+ end;
+ #beg_clause{} ->
+ get_deplist_paths(fixup_before_case_path(Tail), WarnVarArgs,
+ RaceWarnTag, RaceVarMap, CurrLevel, PublicTables,
+ NamedTables);
+ #curr_fun{status = in, var_map = RaceVarMap1} ->
+ {DepList, IsPublic, Continue} =
+ get_deplist_paths(Tail, WarnVarArgs, RaceWarnTag, RaceVarMap,
+ CurrLevel + 1, PublicTables, NamedTables),
+ IsPublic1 =
+ case RaceWarnTag of
+ ?WARN_ETS_LOOKUP_INSERT ->
+ [Tabs, Names, _, _] = WarnVarArgs,
+ IsPublic orelse
+ lists:any(
+ fun (T) ->
+ compare_var_list(T, PublicTables, RaceVarMap1)
+ end, Tabs)
+ orelse
+ length(Names -- NamedTables) < length(Names);
+ _ -> true
+ end,
+ {DepList, IsPublic1, Continue};
+ #curr_fun{status = out, var_map = RaceVarMap1, def_vars = FunDefVars,
+ call_vars = FunCallVars} ->
+ WarnVarArgs1 =
+ var_analysis([format_arg(DefVar) || DefVar <- FunDefVars],
+ [format_arg(CallVar) || CallVar <- FunCallVars],
+ WarnVarArgs, RaceWarnTag),
+ {WarnVarArgs2, Stop} =
+ case RaceWarnTag of
+ ?WARN_WHEREIS_REGISTER ->
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs1,
+ Vars =
+ lists:flatten(
+ [find_all_bound_vars(V, RaceVarMap1) || V <- WVA1]),
+ case {Vars, CurrLevel} of
+ {[], 0} ->
+ {WarnVarArgs, true};
+ {[], _} ->
+ {WarnVarArgs, false};
+ _ ->
+ {[Vars, WVA2, WVA3, WVA4], false}
+ end;
+ ?WARN_WHEREIS_UNREGISTER ->
+ [WVA1, WVA2] = WarnVarArgs1,
+ Vars =
+ lists:flatten(
+ [find_all_bound_vars(V, RaceVarMap1) || V <- WVA1]),
+ case {Vars, CurrLevel} of
+ {[], 0} ->
+ {WarnVarArgs, true};
+ {[], _} ->
+ {WarnVarArgs, false};
+ _ ->
+ {[Vars, WVA2], false}
+ end;
+ ?WARN_ETS_LOOKUP_INSERT ->
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs1,
+ Vars1 =
+ lists:flatten(
+ [find_all_bound_vars(V1, RaceVarMap1) || V1 <- WVA1]),
+ Vars2 =
+ lists:flatten(
+ [find_all_bound_vars(V2, RaceVarMap1) || V2 <- WVA3]),
+ case {Vars1, Vars2, CurrLevel} of
+ {[], _, 0} ->
+ {WarnVarArgs, true};
+ {[], _, _} ->
+ {WarnVarArgs, false};
+ {_, [], 0} ->
+ {WarnVarArgs, true};
+ {_, [], _} ->
+ {WarnVarArgs, false};
+ _ ->
+ {[Vars1, WVA2, Vars2, WVA4], false}
+ end;
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ [WVA1, WVA2|T] = WarnVarArgs1,
+ Vars =
+ lists:flatten(
+ [find_all_bound_vars(V, RaceVarMap1) || V <- WVA1]),
+ case {Vars, CurrLevel} of
+ {[], 0} ->
+ {WarnVarArgs, true};
+ {[], _} ->
+ {WarnVarArgs, false};
+ _ ->
+ {[Vars, WVA2|T], false}
+ end
+ end,
+ case Stop of
+ true -> {[], false, false};
+ false ->
+ CurrLevel1 =
+ case CurrLevel of
+ 0 -> CurrLevel;
+ _ -> CurrLevel - 1
+ end,
+ get_deplist_paths(Tail, WarnVarArgs2, RaceWarnTag, RaceVarMap1,
+ CurrLevel1, PublicTables, NamedTables)
+ end;
+ #warn_call{call_name = RegCall, args = WarnVarArgs1,
+ var_map = RaceVarMap1} when RegCall =:= register orelse
+ RegCall =:= unregister ->
+ case compare_first_arg(WarnVarArgs, WarnVarArgs1, RaceVarMap1) of
+ true -> {[], false, false};
+ NewWarnVarArgs ->
+ get_deplist_paths(Tail, NewWarnVarArgs, RaceWarnTag, RaceVarMap,
+ CurrLevel, PublicTables, NamedTables)
+ end;
+ #warn_call{call_name = ets_insert, args = WarnVarArgs1,
+ var_map = RaceVarMap1} ->
+ case compare_ets_insert(WarnVarArgs, WarnVarArgs1, RaceVarMap1) of
+ true -> {[], false, false};
+ NewWarnVarArgs ->
+ get_deplist_paths(Tail, NewWarnVarArgs, RaceWarnTag, RaceVarMap,
+ CurrLevel, PublicTables, NamedTables)
+ end;
+ #warn_call{call_name = mnesia_dirty_write, args = WarnVarArgs1,
+ var_map = RaceVarMap1} ->
+ case compare_first_arg(WarnVarArgs, WarnVarArgs1, RaceVarMap1) of
+ true -> {[], false, false};
+ NewWarnVarArgs ->
+ get_deplist_paths(Tail, NewWarnVarArgs, RaceWarnTag, RaceVarMap,
+ CurrLevel, PublicTables, NamedTables)
+ end;
+ #dep_call{var_map = RaceVarMap1} ->
+ {DepList, IsPublic, Continue} =
+ get_deplist_paths(Tail, WarnVarArgs, RaceWarnTag, RaceVarMap,
+ CurrLevel, PublicTables, NamedTables),
+ {refine_race(Head, WarnVarArgs, RaceWarnTag, DepList, RaceVarMap1),
+ IsPublic, Continue}
+ end
+ end.
+
+handle_case(RaceList, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel,
+ PublicTables, NamedTables) ->
+ case RaceList of
+ [] -> {[], [], false, true};
+ [Head|Tail] ->
+ case Head of
+ #end_clause{} ->
+ {RestRaceList, DepList1, IsPublic1, Continue1} =
+ do_clause(Tail, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel,
+ PublicTables, NamedTables),
+ {RetRaceList, DepList2, IsPublic2, Continue2} =
+ handle_case(RestRaceList, WarnVarArgs, RaceWarnTag, RaceVarMap,
+ CurrLevel, PublicTables, NamedTables),
+ {RetRaceList, DepList1 ++ DepList2, IsPublic1 orelse IsPublic2,
+ Continue1 orelse Continue2};
+ beg_case -> {Tail, [], false, false}
+ end
+ end.
+
+do_clause(RaceList, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel,
+ PublicTables, NamedTables) ->
+ {DepList, IsPublic, Continue} =
+ get_deplist_paths(fixup_case_path(RaceList, 0), WarnVarArgs,
+ RaceWarnTag, RaceVarMap, CurrLevel,
+ PublicTables, NamedTables),
+ {fixup_case_rest_paths(RaceList, 0), DepList, IsPublic, Continue}.
+
+fixup_case_path(RaceList, NestingLevel) ->
+ case RaceList of
+ [] -> [];
+ [Head|Tail] ->
+ {NewNestingLevel, Return} =
+ case Head of
+ beg_case -> {NestingLevel - 1, false};
+ #end_case{} -> {NestingLevel + 1, false};
+ #beg_clause{} ->
+ case NestingLevel =:= 0 of
+ true -> {NestingLevel, true};
+ false -> {NestingLevel, false}
+ end;
+ _Other -> {NestingLevel, false}
+ end,
+ case Return of
+ true -> [];
+ false -> [Head|fixup_case_path(Tail, NewNestingLevel)]
+ end
+ end.
+
+%% Gets the race list before a case clause.
+fixup_before_case_path(RaceList) ->
+ case RaceList of
+ [] -> [];
+ [Head|Tail] ->
+ case Head of
+ #end_clause{} ->
+ fixup_before_case_path(fixup_case_rest_paths(Tail, 0));
+ beg_case -> Tail
+ end
+ end.
+
+fixup_case_rest_paths(RaceList, NestingLevel) ->
+ case RaceList of
+ [] -> [];
+ [Head|Tail] ->
+ {NewNestingLevel, Return} =
+ case Head of
+ beg_case -> {NestingLevel - 1, false};
+ #end_case{} -> {NestingLevel + 1, false};
+ #beg_clause{} ->
+ case NestingLevel =:= 0 of
+ true -> {NestingLevel, true};
+ false -> {NestingLevel, false}
+ end;
+ _Other -> {NestingLevel, false}
+ end,
+ case Return of
+ true -> Tail;
+ false -> fixup_case_rest_paths(Tail, NewNestingLevel)
+ end
+ end.
+
+fixup_race_forward_helper(CurrFun, CurrFunLabel, Fun, FunLabel,
+ Calls, CallsToAnalyze, Code, RaceList,
+ InitFun, NewFunArgs, NewFunTypes,
+ RaceWarnTag, RaceVarMap, FunDefVars,
+ FunCallVars, FunArgTypes, NestingLevel,
+ Args, CodeB, StateRaceList) ->
+ case Calls of
+ [] ->
+ {NewRaceList,
+ #curr_fun{mfa = NewCurrFun, label = NewCurrFunLabel,
+ var_map = NewRaceVarMap, def_vars = NewFunDefVars,
+ call_vars = NewFunCallVars, arg_types = NewFunArgTypes},
+ NewCode, NewNestingLevel} =
+ remove_clause(RaceList,
+ #curr_fun{mfa = CurrFun, label = CurrFunLabel, var_map = RaceVarMap,
+ def_vars = FunDefVars, call_vars = FunCallVars,
+ arg_types = FunArgTypes},
+ Code, NestingLevel),
+ {NewCurrFun, NewCurrFunLabel, CallsToAnalyze, NewCode, NewRaceList,
+ NewRaceVarMap, NewFunDefVars, NewFunCallVars, NewFunArgTypes,
+ NewNestingLevel};
+ [Head|Tail] ->
+ case Head of
+ {InitFun, InitFun} when CurrFun =:= InitFun, Fun =:= InitFun ->
+ NewCallsToAnalyze = lists:delete(Head, CallsToAnalyze),
+ NewRaceVarMap =
+ race_var_map(Args, NewFunArgs, RaceVarMap, bind),
+ RetC =
+ fixup_all_calls(InitFun, InitFun, FunLabel, Args,
+ CodeB ++
+ [#curr_fun{status = out, mfa = InitFun,
+ label = CurrFunLabel, var_map = RaceVarMap,
+ def_vars = FunDefVars, call_vars = FunCallVars,
+ arg_types = FunArgTypes}],
+ Code, RaceVarMap),
+ NewCode =
+ fixup_all_calls(InitFun, InitFun, FunLabel, Args,
+ CodeB ++
+ [#curr_fun{status = out, mfa = InitFun,
+ label = CurrFunLabel, var_map = NewRaceVarMap,
+ def_vars = Args, call_vars = NewFunArgs,
+ arg_types = NewFunTypes}],
+ [#curr_fun{status = in, mfa = Fun,
+ label = FunLabel, var_map = NewRaceVarMap,
+ def_vars = Args, call_vars = NewFunArgs,
+ arg_types = NewFunTypes}|
+ lists:reverse(StateRaceList)] ++
+ RetC, NewRaceVarMap),
+ {InitFun, FunLabel, NewCallsToAnalyze, NewCode, RaceList,
+ NewRaceVarMap, Args, NewFunArgs, NewFunTypes, NestingLevel};
+ {CurrFun, Fun} ->
+ NewCallsToAnalyze = lists:delete(Head, CallsToAnalyze),
+ NewRaceVarMap = race_var_map(Args, NewFunArgs, RaceVarMap, bind),
+ RetC =
+ case Fun of
+ InitFun ->
+ fixup_all_calls(CurrFun, Fun, FunLabel, Args,
+ lists:reverse(StateRaceList) ++
+ [#curr_fun{status = out, mfa = CurrFun,
+ label = CurrFunLabel, var_map = RaceVarMap,
+ def_vars = FunDefVars, call_vars = FunCallVars,
+ arg_types = FunArgTypes}],
+ Code, RaceVarMap);
+ _Other1 ->
+ fixup_all_calls(CurrFun, Fun, FunLabel, Args,
+ CodeB ++
+ [#curr_fun{status = out, mfa = CurrFun,
+ label = CurrFunLabel, var_map = RaceVarMap,
+ def_vars = FunDefVars, call_vars = FunCallVars,
+ arg_types = FunArgTypes}],
+ Code, RaceVarMap)
+ end,
+ NewCode =
+ case Fun of
+ InitFun ->
+ [#curr_fun{status = in, mfa = Fun,
+ label = FunLabel, var_map = NewRaceVarMap,
+ def_vars = Args, call_vars = NewFunArgs,
+ arg_types = NewFunTypes}|
+ lists:reverse(StateRaceList)] ++ RetC;
+ _ ->
+ [#curr_fun{status = in, mfa = Fun,
+ label = FunLabel, var_map = NewRaceVarMap,
+ def_vars = Args, call_vars = NewFunArgs,
+ arg_types = NewFunTypes}|CodeB] ++
+ RetC
+ end,
+ {Fun, FunLabel, NewCallsToAnalyze, NewCode, RaceList, NewRaceVarMap,
+ Args, NewFunArgs, NewFunTypes, NestingLevel};
+ {_TupleA, _TupleB} ->
+ fixup_race_forward_helper(CurrFun, CurrFunLabel, Fun, FunLabel,
+ Tail, CallsToAnalyze, Code, RaceList, InitFun, NewFunArgs,
+ NewFunTypes, RaceWarnTag, RaceVarMap, FunDefVars, FunCallVars,
+ FunArgTypes, NestingLevel, Args, CodeB, StateRaceList)
+ end
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Backward Analysis
+%%%
+%%% ===========================================================================
+
+fixup_race_backward(CurrFun, Calls, CallsToAnalyze, Parents, Height) ->
+ case Height =:= 0 of
+ true -> Parents;
+ false ->
+ case Calls of
+ [] ->
+ case is_integer(CurrFun) orelse lists:member(CurrFun, Parents) of
+ true -> Parents;
+ false -> [CurrFun|Parents]
+ end;
+ [Head|Tail] ->
+ {Parent, TupleB} = Head,
+ case TupleB =:= CurrFun of
+ true -> % more paths are needed
+ NewCallsToAnalyze = lists:delete(Head, CallsToAnalyze),
+ NewParents =
+ fixup_race_backward(Parent, NewCallsToAnalyze,
+ NewCallsToAnalyze, Parents, Height - 1),
+ fixup_race_backward(CurrFun, Tail, NewCallsToAnalyze, NewParents,
+ Height);
+ false ->
+ fixup_race_backward(CurrFun, Tail, CallsToAnalyze, Parents,
+ Height)
+ end
+ end
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Utilities
+%%%
+%%% ===========================================================================
+
+are_bound_labels(Label1, Label2, RaceVarMap) ->
+ case dict:find(Label1, RaceVarMap) of
+ error -> false;
+ {ok, Labels} ->
+ lists:member(Label2, Labels) orelse
+ are_bound_labels_helper(Labels, Label1, Label2, RaceVarMap)
+ end.
+
+are_bound_labels_helper(Labels, OldLabel, CompLabel, RaceVarMap) ->
+ case dict:size(RaceVarMap) of
+ 0 -> false;
+ _ ->
+ case Labels of
+ [] -> false;
+ [Head|Tail] ->
+ NewRaceVarMap = dict:erase(OldLabel, RaceVarMap),
+ are_bound_labels(Head, CompLabel, NewRaceVarMap) orelse
+ are_bound_labels_helper(Tail, Head, CompLabel, NewRaceVarMap)
+ end
+ end.
+
+are_bound_vars(Vars1, Vars2, RaceVarMap) ->
+ case is_list(Vars1) andalso is_list(Vars2) of
+ true ->
+ case Vars1 of
+ [] -> false;
+ [AHead|ATail] ->
+ case Vars2 of
+ [] -> false;
+ [PHead|PTail] ->
+ are_bound_vars(AHead, PHead, RaceVarMap) andalso
+ are_bound_vars(ATail, PTail, RaceVarMap)
+ end
+ end;
+ false ->
+ {NewVars1, NewVars2, IsList} =
+ case is_list(Vars1) of
+ true ->
+ case Vars1 of
+ [Var1] -> {Var1, Vars2, true};
+ _Thing -> {Vars1, Vars2, false}
+ end;
+ false ->
+ case is_list(Vars2) of
+ true ->
+ case Vars2 of
+ [Var2] -> {Vars1, Var2, true};
+ _Thing -> {Vars1, Vars2, false}
+ end;
+ false -> {Vars1, Vars2, true}
+ end
+ end,
+ case IsList of
+ true ->
+ case cerl:type(NewVars1) of
+ var ->
+ case cerl:type(NewVars2) of
+ var ->
+ ALabel = cerl_trees:get_label(NewVars1),
+ PLabel = cerl_trees:get_label(NewVars2),
+ are_bound_labels(ALabel, PLabel, RaceVarMap) orelse
+ are_bound_labels(PLabel, ALabel, RaceVarMap);
+ alias ->
+ are_bound_vars(NewVars1, cerl:alias_var(NewVars2),
+ RaceVarMap);
+ values ->
+ are_bound_vars(NewVars1, cerl:values_es(NewVars2),
+ RaceVarMap);
+ _Other -> false
+ end;
+ tuple ->
+ case cerl:type(NewVars2) of
+ tuple ->
+ are_bound_vars(cerl:tuple_es(NewVars1),
+ cerl:tuple_es(NewVars2), RaceVarMap);
+ alias ->
+ are_bound_vars(NewVars1, cerl:alias_var(NewVars2),
+ RaceVarMap);
+ values ->
+ are_bound_vars(NewVars1, cerl:values_es(NewVars2),
+ RaceVarMap);
+ _Other -> false
+ end;
+ cons ->
+ case cerl:type(NewVars2) of
+ cons ->
+ are_bound_vars(cerl:cons_hd(NewVars1),
+ cerl:cons_hd(NewVars2), RaceVarMap)
+ andalso
+ are_bound_vars(cerl:cons_tl(NewVars1),
+ cerl:cons_tl(NewVars2), RaceVarMap);
+ alias ->
+ are_bound_vars(NewVars1, cerl:alias_var(NewVars2),
+ RaceVarMap);
+ values ->
+ are_bound_vars(NewVars1, cerl:values_es(NewVars2),
+ RaceVarMap);
+ _Other -> false
+ end;
+ alias ->
+ case cerl:type(NewVars2) of
+ alias ->
+ are_bound_vars(cerl:alias_var(NewVars1),
+ cerl:alias_var(NewVars2), RaceVarMap);
+ _Other ->
+ are_bound_vars(cerl:alias_var(NewVars1),
+ NewVars2, RaceVarMap)
+ end;
+ values ->
+ case cerl:type(NewVars2) of
+ values ->
+ are_bound_vars(cerl:values_es(NewVars1),
+ cerl:values_es(NewVars2), RaceVarMap);
+ _Other ->
+ are_bound_vars(cerl:values_es(NewVars1),
+ NewVars2, RaceVarMap)
+ end;
+ _Other -> false
+ end;
+ false -> false
+ end
+ end.
+
+callgraph__renew_tables(Table, Callgraph) ->
+ case Table of
+ {named, NameLabel, Names} ->
+ PTablesToAdd =
+ case NameLabel of
+ ?no_label -> [];
+ _Other -> [NameLabel]
+ end,
+ NamesToAdd = filter_named_tables(Names),
+ PTables = dialyzer_callgraph:get_public_tables(Callgraph),
+ NTables = dialyzer_callgraph:get_named_tables(Callgraph),
+ dialyzer_callgraph:put_public_tables(
+ lists:usort(PTablesToAdd ++ PTables),
+ dialyzer_callgraph:put_named_tables(
+ NamesToAdd ++ NTables, Callgraph));
+ _Other ->
+ Callgraph
+ end.
+
+cleanup_clause_code(#curr_fun{mfa = CurrFun} = CurrTuple, Code,
+ NestingLevel, LocalNestingLevel) ->
+ case Code of
+ [] -> {CurrTuple, []};
+ [Head|Tail] ->
+ {NewLocalNestingLevel, NewNestingLevel, NewCurrTuple, Return} =
+ case Head of
+ beg_case ->
+ {LocalNestingLevel, NestingLevel + 1, CurrTuple, false};
+ #end_case{} ->
+ {LocalNestingLevel, NestingLevel - 1, CurrTuple, false};
+ #end_clause{} ->
+ case NestingLevel =:= 0 of
+ true ->
+ {LocalNestingLevel, NestingLevel, CurrTuple, true};
+ false ->
+ {LocalNestingLevel, NestingLevel, CurrTuple, false}
+ end;
+ #fun_call{caller = CurrFun} ->
+ {LocalNestingLevel - 1, NestingLevel, CurrTuple, false};
+ #curr_fun{status = in} ->
+ {LocalNestingLevel - 1, NestingLevel, Head, false};
+ #curr_fun{status = out} ->
+ {LocalNestingLevel + 1, NestingLevel, Head, false};
+ Other when Other =/= #fun_call{} ->
+ {LocalNestingLevel, NestingLevel, CurrTuple, false}
+ end,
+ case Return of
+ true -> {NewCurrTuple, Tail};
+ false ->
+ cleanup_clause_code(NewCurrTuple, Tail, NewNestingLevel,
+ NewLocalNestingLevel)
+ end
+ end.
+
+cleanup_dep_calls(DepList) ->
+ case DepList of
+ [] -> [];
+ [#dep_call{call_name = CallName, arg_types = ArgTypes,
+ vars = Vars, state = State, file_line = FileLine}|T] ->
+ [#dep_call{call_name = CallName, arg_types = ArgTypes,
+ vars = Vars, state = State, file_line = FileLine}|
+ cleanup_dep_calls(T)]
+ end.
+
+cleanup_race_code(State) ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ dialyzer_dataflow:state__put_callgraph(
+ dialyzer_callgraph:race_code_new(Callgraph), State).
+
+filter_named_tables(NamesList) ->
+ case NamesList of
+ [] -> [];
+ [Head|Tail] ->
+ NewHead =
+ case string:rstr(Head, "()") of
+ 0 -> [Head];
+ _Other -> []
+ end,
+ NewHead ++ filter_named_tables(Tail)
+ end.
+
+filter_parents(Parents, NewParents, Digraph) ->
+ case Parents of
+ [] -> NewParents;
+ [Head|Tail] ->
+ NewParents1 = filter_parents_helper1(Head, Tail, NewParents, Digraph),
+ filter_parents(Tail, NewParents1, Digraph)
+ end.
+
+filter_parents_helper1(First, Rest, NewParents, Digraph) ->
+ case Rest of
+ [] -> NewParents;
+ [Head|Tail] ->
+ NewParents1 = filter_parents_helper2(First, Head, NewParents, Digraph),
+ filter_parents_helper1(First, Tail, NewParents1, Digraph)
+ end.
+
+filter_parents_helper2(Parent1, Parent2, NewParents, Digraph) ->
+ case digraph:get_path(Digraph, Parent1, Parent2) of
+ false ->
+ case digraph:get_path(Digraph, Parent2, Parent1) of
+ false -> NewParents;
+ _Vertices -> NewParents -- [Parent1]
+ end;
+ _Vertices -> NewParents -- [Parent2]
+ end.
+
+find_all_bound_vars(Label, RaceVarMap) ->
+ case dict:find(Label, RaceVarMap) of
+ error -> [Label];
+ {ok, Labels} ->
+ lists:usort(Labels ++
+ find_all_bound_vars_helper(Labels, Label, RaceVarMap))
+ end.
+
+find_all_bound_vars_helper(Labels, Label, RaceVarMap) ->
+ case dict:size(RaceVarMap) of
+ 0 -> [];
+ _ ->
+ case Labels of
+ [] -> [];
+ [Head|Tail] ->
+ NewRaceVarMap = dict:erase(Label, RaceVarMap),
+ find_all_bound_vars(Head, NewRaceVarMap) ++
+ find_all_bound_vars_helper(Tail, Head, NewRaceVarMap)
+ end
+ end.
+
+fixup_all_calls(CurrFun, NextFun, NextFunLabel, Args, CodeToReplace,
+ Code, RaceVarMap) ->
+ case Code of
+ [] -> [];
+ [Head|Tail] ->
+ NewCode =
+ case Head of
+ #fun_call{caller = CurrFun, callee = Callee,
+ arg_types = FunArgTypes, vars = FunArgs}
+ when Callee =:= NextFun orelse Callee =:= NextFunLabel ->
+ RaceVarMap1 = race_var_map(Args, FunArgs, RaceVarMap, bind),
+ [#curr_fun{status = in, mfa = NextFun, label = NextFunLabel,
+ var_map = RaceVarMap1, def_vars = Args,
+ call_vars = FunArgs, arg_types = FunArgTypes}|
+ CodeToReplace];
+ _Other -> [Head]
+ end,
+ RetCode =
+ fixup_all_calls(CurrFun, NextFun, NextFunLabel, Args, CodeToReplace,
+ Tail, RaceVarMap),
+ NewCode ++ RetCode
+ end.
+
+is_last_race(RaceTag, InitFun, Code, Callgraph) ->
+ case Code of
+ [] -> true;
+ [Head|Tail] ->
+ case Head of
+ RaceTag -> false;
+ #fun_call{callee = Fun} ->
+ FunName =
+ case is_integer(Fun) of
+ true ->
+ case dialyzer_callgraph:lookup_name(Fun, Callgraph) of
+ error -> Fun;
+ {ok, Name} -> Name
+ end;
+ false -> Fun
+ end,
+ Digraph = dialyzer_callgraph:get_digraph(Callgraph),
+ case FunName =:= InitFun orelse
+ digraph:get_path(Digraph, FunName, InitFun) of
+ false -> is_last_race(RaceTag, InitFun, Tail, Callgraph);
+ _Vertices -> false
+ end;
+ _Other -> is_last_race(RaceTag, InitFun, Tail, Callgraph)
+ end
+ end.
+
+lists_key_member(Member, List, N) when is_integer(Member) ->
+ case List of
+ [] -> 0;
+ [Head|Tail] ->
+ NewN = N + 1,
+ case Head of
+ Member -> NewN;
+ _Other -> lists_key_member(Member, Tail, NewN)
+ end
+ end;
+lists_key_member(_M, _L, _N) ->
+ 0.
+
+lists_key_member_lists(MemberList, List) ->
+ case MemberList of
+ [] -> 0;
+ [Head|Tail] ->
+ case lists_key_member(Head, List, 0) of
+ 0 -> lists_key_member_lists(Tail, List);
+ Other -> Other
+ end
+ end.
+
+lists_key_members_lists(MemberList, List) ->
+ case MemberList of
+ [] -> [];
+ [Head|Tail] ->
+ lists:usort(
+ lists_key_members_lists_helper(Head, List, 1) ++
+ lists_key_members_lists(Tail, List))
+ end.
+
+lists_key_members_lists_helper(Elem, List, N) when is_integer(Elem) ->
+ case List of
+ [] -> [];
+ [Head|Tail] ->
+ NewHead =
+ case Head =:= Elem of
+ true -> [N];
+ false -> []
+ end,
+ NewHead ++ lists_key_members_lists_helper(Elem, Tail, N + 1)
+ end;
+lists_key_members_lists_helper(_Elem, _List, _N) ->
+ [0].
+
+lists_key_replace(N, List, NewMember) ->
+ {Before, [_|After]} = lists:split(N - 1, List),
+ Before ++ [NewMember|After].
+
+lists_get(0, _List) -> ?no_label;
+lists_get(N, List) -> lists:nth(N, List).
+
+refine_race(RaceCall, WarnVarArgs, RaceWarnTag, DependencyList, RaceVarMap) ->
+ case RaceWarnTag of
+ WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse
+ WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER ->
+ case RaceCall of
+ #dep_call{call_name = ets_lookup} ->
+ DependencyList;
+ #dep_call{call_name = mnesia_dirty_read} ->
+ DependencyList;
+ #dep_call{call_name = whereis, args = VarArgs} ->
+ refine_race_helper(RaceCall, VarArgs, WarnVarArgs, RaceWarnTag,
+ DependencyList, RaceVarMap)
+ end;
+ ?WARN_ETS_LOOKUP_INSERT ->
+ case RaceCall of
+ #dep_call{call_name = whereis} ->
+ DependencyList;
+ #dep_call{call_name = mnesia_dirty_read} ->
+ DependencyList;
+ #dep_call{call_name = ets_lookup, args = VarArgs} ->
+ refine_race_helper(RaceCall, VarArgs, WarnVarArgs, RaceWarnTag,
+ DependencyList, RaceVarMap)
+ end;
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ case RaceCall of
+ #dep_call{call_name = whereis} ->
+ DependencyList;
+ #dep_call{call_name = ets_lookup} ->
+ DependencyList;
+ #dep_call{call_name = mnesia_dirty_read, args = VarArgs} ->
+ refine_race_helper(RaceCall, VarArgs, WarnVarArgs, RaceWarnTag,
+ DependencyList, RaceVarMap)
+ end
+ end.
+
+refine_race_helper(RaceCall, VarArgs, WarnVarArgs, RaceWarnTag, DependencyList,
+ RaceVarMap) ->
+ case compare_types(VarArgs, WarnVarArgs, RaceWarnTag, RaceVarMap) of
+ true -> [RaceCall|DependencyList];
+ false -> DependencyList
+ end.
+
+remove_clause(RaceList, CurrTuple, Code, NestingLevel) ->
+ NewRaceList = fixup_case_rest_paths(RaceList, 0),
+ {NewCurrTuple, NewCode} =
+ cleanup_clause_code(CurrTuple, Code, 0, NestingLevel),
+ ReturnTuple = {NewRaceList, NewCurrTuple, NewCode, NestingLevel},
+ case NewRaceList of
+ [beg_case|RTail] ->
+ case NewCode of
+ [#end_case{}|CTail] ->
+ remove_clause(RTail, NewCurrTuple, CTail, NestingLevel);
+ _Other -> ReturnTuple
+ end;
+ _Else -> ReturnTuple
+ end.
+
+remove_nonlocal_functions(Code, NestingLevel) ->
+ case Code of
+ [] -> [];
+ [H|T] ->
+ NewNL =
+ case H of
+ #curr_fun{status = in} ->
+ NestingLevel + 1;
+ #curr_fun{status = out} ->
+ NestingLevel - 1;
+ _Other ->
+ NestingLevel
+ end,
+ case NewNL =:= 0 of
+ true -> T;
+ false -> remove_nonlocal_functions(T, NewNL)
+ end
+ end.
+
+renew_curr_fun(CurrFun, Races) ->
+ Races#races{curr_fun = CurrFun}.
+
+renew_curr_fun_label(CurrFunLabel, Races) ->
+ Races#races{curr_fun_label = CurrFunLabel}.
+
+renew_race_list(RaceList, Races) ->
+ Races#races{race_list = RaceList}.
+
+renew_race_list_size(RaceListSize, Races) ->
+ Races#races{race_list_size = RaceListSize}.
+
+renew_race_tags(RaceTags, Races) ->
+ Races#races{race_tags = RaceTags}.
+
+renew_table(Table, Races) ->
+ Races#races{new_table = Table}.
+
+state__renew_curr_fun(CurrFun, State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ dialyzer_dataflow:state__put_races(renew_curr_fun(CurrFun, Races), State).
+
+state__renew_curr_fun_label(CurrFunLabel, State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ dialyzer_dataflow:state__put_races(
+ renew_curr_fun_label(CurrFunLabel, Races), State).
+
+state__renew_race_list(RaceList, State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ dialyzer_dataflow:state__put_races(renew_race_list(RaceList, Races), State).
+
+state__renew_race_tags(RaceTags, State) ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ dialyzer_dataflow:state__put_races(renew_race_tags(RaceTags, Races), State).
+
+state__renew_info(RaceList, RaceListSize, RaceTags, Table, State) ->
+ Callgraph = dialyzer_dataflow:state__get_callgraph(State),
+ Races = dialyzer_dataflow:state__get_races(State),
+ dialyzer_dataflow:state__put_callgraph(
+ callgraph__renew_tables(Table, Callgraph),
+ dialyzer_dataflow:state__put_races(
+ renew_table(Table,
+ renew_race_list(RaceList,
+ renew_race_list_size(RaceListSize,
+ renew_race_tags(RaceTags, Races)))), State)).
+
+%%% ===========================================================================
+%%%
+%%% Variable and Type Utilities
+%%%
+%%% ===========================================================================
+
+any_args(StrList) ->
+ case StrList of
+ [] -> false;
+ [Head|Tail] ->
+ case string:rstr(Head, "()") of
+ 0 -> any_args(Tail);
+ _Other -> true
+ end
+ end.
+
+-spec bind_dict_vars(label(), label(), dict:dict()) -> dict:dict().
+
+bind_dict_vars(Key, Label, RaceVarMap) ->
+ case Key =:= Label of
+ true -> RaceVarMap;
+ false ->
+ case dict:find(Key, RaceVarMap) of
+ error -> dict:store(Key, [Label], RaceVarMap);
+ {ok, Labels} ->
+ case lists:member(Label, Labels) of
+ true -> RaceVarMap;
+ false -> dict:store(Key, [Label|Labels], RaceVarMap)
+ end
+ end
+ end.
+
+bind_dict_vars_list(Key, Labels, RaceVarMap) ->
+ case Labels of
+ [] -> RaceVarMap;
+ [Head|Tail] ->
+ bind_dict_vars_list(Key, Tail, bind_dict_vars(Key, Head, RaceVarMap))
+ end.
+
+compare_ets_insert(OldWarnVarArgs, NewWarnVarArgs, RaceVarMap) ->
+ [Old1, Old2, Old3, Old4] = OldWarnVarArgs,
+ [New1, New2, New3, New4] = NewWarnVarArgs,
+ Bool =
+ case any_args(Old2) of
+ true -> compare_var_list(New1, Old1, RaceVarMap);
+ false ->
+ case any_args(New2) of
+ true -> compare_var_list(New1, Old1, RaceVarMap);
+ false -> compare_var_list(New1, Old1, RaceVarMap)
+ orelse (Old2 =:= New2)
+ end
+ end,
+ case Bool of
+ true ->
+ case any_args(Old4) of
+ true ->
+ case compare_list_vars(Old3, ets_list_args(New3), [], RaceVarMap) of
+ true -> true;
+ Args3 -> lists_key_replace(3, OldWarnVarArgs, Args3)
+ end;
+ false ->
+ case any_args(New4) of
+ true ->
+ case compare_list_vars(Old3, ets_list_args(New3), [],
+ RaceVarMap) of
+ true -> true;
+ Args3 -> lists_key_replace(3, OldWarnVarArgs, Args3)
+ end;
+ false ->
+ case compare_list_vars(Old3, ets_list_args(New3), [],
+ RaceVarMap) of
+ true -> true;
+ Args3 ->
+ lists_key_replace(4,
+ lists_key_replace(3, OldWarnVarArgs, Args3), Old4 -- New4)
+ end
+ end
+ end;
+ false -> OldWarnVarArgs
+ end.
+
+compare_first_arg(OldWarnVarArgs, NewWarnVarArgs, RaceVarMap) ->
+ [Old1, Old2|_OldT] = OldWarnVarArgs,
+ [New1, New2|_NewT] = NewWarnVarArgs,
+ case any_args(Old2) of
+ true ->
+ case compare_var_list(New1, Old1, RaceVarMap) of
+ true -> true;
+ false -> OldWarnVarArgs
+ end;
+ false ->
+ case any_args(New2) of
+ true ->
+ case compare_var_list(New1, Old1, RaceVarMap) of
+ true -> true;
+ false -> OldWarnVarArgs
+ end;
+ false ->
+ case compare_var_list(New1, Old1, RaceVarMap) of
+ true -> true;
+ false -> lists_key_replace(2, OldWarnVarArgs, Old2 -- New2)
+ end
+ end
+ end.
+
+compare_argtypes(ArgTypes, WarnArgTypes) ->
+ lists:any(fun (X) -> lists:member(X, WarnArgTypes) end, ArgTypes).
+
+%% Compares the argument types of the two suspicious calls.
+compare_types(VarArgs, WarnVarArgs, RaceWarnTag, RaceVarMap) ->
+ case RaceWarnTag of
+ ?WARN_WHEREIS_REGISTER ->
+ [VA1, VA2] = VarArgs,
+ [WVA1, WVA2, _, _] = WarnVarArgs,
+ case any_args(VA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ case any_args(WVA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ compare_var_list(VA1, WVA1, RaceVarMap) orelse
+ compare_argtypes(VA2, WVA2)
+ end
+ end;
+ ?WARN_WHEREIS_UNREGISTER ->
+ [VA1, VA2] = VarArgs,
+ [WVA1, WVA2] = WarnVarArgs,
+ case any_args(VA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ case any_args(WVA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ compare_var_list(VA1, WVA1, RaceVarMap) orelse
+ compare_argtypes(VA2, WVA2)
+ end
+ end;
+ ?WARN_ETS_LOOKUP_INSERT ->
+ [VA1, VA2, VA3, VA4] = VarArgs,
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
+ Bool =
+ case any_args(VA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ case any_args(WVA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ compare_var_list(VA1, WVA1, RaceVarMap) orelse
+ compare_argtypes(VA2, WVA2)
+ end
+ end,
+ Bool andalso
+ (case any_args(VA4) of
+ true ->
+ compare_var_list(VA3, WVA3, RaceVarMap);
+ false ->
+ case any_args(WVA4) of
+ true ->
+ compare_var_list(VA3, WVA3, RaceVarMap);
+ false ->
+ compare_var_list(VA3, WVA3, RaceVarMap) orelse
+ compare_argtypes(VA4, WVA4)
+ end
+ end);
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ [VA1, VA2|_] = VarArgs, %% Two or four elements
+ [WVA1, WVA2|_] = WarnVarArgs,
+ case any_args(VA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ case any_args(WVA2) of
+ true -> compare_var_list(VA1, WVA1, RaceVarMap);
+ false ->
+ compare_var_list(VA1, WVA1, RaceVarMap) orelse
+ compare_argtypes(VA2, WVA2)
+ end
+ end
+ end.
+
+compare_list_vars(VarList1, VarList2, NewVarList1, RaceVarMap) ->
+ case VarList1 of
+ [] ->
+ case NewVarList1 of
+ [] -> true;
+ _Other -> NewVarList1
+ end;
+ [Head|Tail] ->
+ NewHead =
+ case compare_var_list(Head, VarList2, RaceVarMap) of
+ true -> [];
+ false -> [Head]
+ end,
+ compare_list_vars(Tail, VarList2, NewHead ++ NewVarList1, RaceVarMap)
+ end.
+
+compare_vars(Var1, Var2, RaceVarMap) when is_integer(Var1), is_integer(Var2) ->
+ Var1 =:= Var2 orelse
+ are_bound_labels(Var1, Var2, RaceVarMap) orelse
+ are_bound_labels(Var2, Var1, RaceVarMap);
+compare_vars(_Var1, _Var2, _RaceVarMap) ->
+ false.
+
+-spec compare_var_list(label_type(), [label_type()], dict:dict()) -> boolean().
+
+compare_var_list(Var, VarList, RaceVarMap) ->
+ lists:any(fun (V) -> compare_vars(Var, V, RaceVarMap) end, VarList).
+
+ets_list_args(MaybeList) ->
+ case is_list(MaybeList) of
+ true ->
+ try [ets_tuple_args(T) || T <- MaybeList]
+ catch _:_ -> [?no_label]
+ end;
+ false -> [ets_tuple_args(MaybeList)]
+ end.
+
+ets_list_argtypes(ListStr) ->
+ ListStr1 = string:strip(ListStr, left, $[),
+ ListStr2 = string:strip(ListStr1, right, $]),
+ ListStr3 = string:strip(ListStr2, right, $.),
+ string:strip(ListStr3, right, $,).
+
+ets_tuple_args(MaybeTuple) ->
+ case is_tuple(MaybeTuple) of
+ true -> element(1, MaybeTuple);
+ false -> ?no_label
+ end.
+
+ets_tuple_argtypes2(TupleList, ElemList) ->
+ case TupleList of
+ [] -> ElemList;
+ [H|T] ->
+ ets_tuple_argtypes2(T,
+ ets_tuple_argtypes2_helper(H, [], 0) ++ ElemList)
+ end.
+
+ets_tuple_argtypes2_helper(TupleStr, ElemStr, NestingLevel) ->
+ case TupleStr of
+ [] -> [];
+ [H|T] ->
+ {NewElemStr, NewNestingLevel, Return} =
+ case H of
+ ${ when NestingLevel =:= 0 ->
+ {ElemStr, NestingLevel + 1, false};
+ ${ ->
+ {[H|ElemStr], NestingLevel + 1, false};
+ $[ ->
+ {[H|ElemStr], NestingLevel + 1, false};
+ $( ->
+ {[H|ElemStr], NestingLevel + 1, false};
+ $} ->
+ {[H|ElemStr], NestingLevel - 1, false};
+ $] ->
+ {[H|ElemStr], NestingLevel - 1, false};
+ $) ->
+ {[H|ElemStr], NestingLevel - 1, false};
+ $, when NestingLevel =:= 1 ->
+ {lists:reverse(ElemStr), NestingLevel, true};
+ _Other ->
+ {[H|ElemStr], NestingLevel, false}
+ end,
+ case Return of
+ true -> string:tokens(NewElemStr, " |");
+ false ->
+ ets_tuple_argtypes2_helper(T, NewElemStr, NewNestingLevel)
+ end
+ end.
+
+ets_tuple_argtypes1(Str, Tuple, TupleList, NestingLevel) ->
+ case Str of
+ [] -> TupleList;
+ [H|T] ->
+ {NewTuple, NewNestingLevel, Add} =
+ case H of
+ ${ ->
+ {[H|Tuple], NestingLevel + 1, false};
+ $} ->
+ case NestingLevel of
+ 1 ->
+ {[H|Tuple], NestingLevel - 1, true};
+ _Else ->
+ {[H|Tuple], NestingLevel - 1, false}
+ end;
+ _Other1 when NestingLevel =:= 0 ->
+ {Tuple, NestingLevel, false};
+ _Other2 ->
+ {[H|Tuple], NestingLevel, false}
+ end,
+ case Add of
+ true ->
+ ets_tuple_argtypes1(T, [],
+ [lists:reverse(NewTuple)|TupleList],
+ NewNestingLevel);
+ false ->
+ ets_tuple_argtypes1(T, NewTuple, TupleList, NewNestingLevel)
+ end
+ end.
+
+format_arg(?bypassed) -> ?no_label;
+format_arg(Arg0) ->
+ Arg = cerl:fold_literal(Arg0),
+ case cerl:type(Arg) of
+ var -> cerl_trees:get_label(Arg);
+ tuple -> list_to_tuple([format_arg(A) || A <- cerl:tuple_es(Arg)]);
+ cons -> [format_arg(cerl:cons_hd(Arg))|format_arg(cerl:cons_tl(Arg))];
+ alias -> format_arg(cerl:alias_var(Arg));
+ literal ->
+ case cerl:is_c_nil(Arg) of
+ true -> [];
+ false -> ?no_label
+ end;
+ _Other -> ?no_label
+ end.
+
+-spec format_args([core_vars()], [erl_types:erl_type()],
+ dialyzer_dataflow:state(), call()) ->
+ args().
+
+format_args([], [], _State, _Call) ->
+ [];
+format_args(ArgList, TypeList, CleanState, Call) ->
+ format_args_2(format_args_1(ArgList, TypeList, CleanState), Call).
+
+format_args_1([Arg], [Type], CleanState) ->
+ [format_arg(Arg), format_type(Type, CleanState)];
+format_args_1([Arg|Args], [Type|Types], CleanState) ->
+ List =
+ case Arg =:= ?bypassed of
+ true -> [?no_label, format_type(Type, CleanState)];
+ false ->
+ case cerl:is_literal(cerl:fold_literal(Arg)) of
+ true -> [?no_label, format_cerl(Arg)];
+ false -> [format_arg(Arg), format_type(Type, CleanState)]
+ end
+ end,
+ List ++ format_args_1(Args, Types, CleanState).
+
+format_args_2(StrArgList, Call) ->
+ case Call of
+ whereis ->
+ lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |"));
+ register ->
+ lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |"));
+ unregister ->
+ lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |"));
+ ets_new ->
+ StrArgList1 = lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |")),
+ lists_key_replace(4, StrArgList1,
+ string:tokens(ets_list_argtypes(lists:nth(4, StrArgList1)), " |"));
+ ets_lookup ->
+ StrArgList1 = lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |")),
+ lists_key_replace(4, StrArgList1,
+ string:tokens(lists:nth(4, StrArgList1), " |"));
+ ets_insert ->
+ StrArgList1 = lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |")),
+ lists_key_replace(4, StrArgList1,
+ ets_tuple_argtypes2(
+ ets_tuple_argtypes1(lists:nth(4, StrArgList1), [], [], 0),
+ []));
+ mnesia_dirty_read1 ->
+ lists_key_replace(2, StrArgList,
+ [mnesia_tuple_argtypes(T) || T <- string:tokens(
+ lists:nth(2, StrArgList), " |")]);
+ mnesia_dirty_read2 ->
+ lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |"));
+ mnesia_dirty_write1 ->
+ lists_key_replace(2, StrArgList,
+ [mnesia_record_tab(R) || R <- string:tokens(
+ lists:nth(2, StrArgList), " |")]);
+ mnesia_dirty_write2 ->
+ lists_key_replace(2, StrArgList,
+ string:tokens(lists:nth(2, StrArgList), " |"));
+ function_call -> StrArgList
+ end.
+
+format_cerl(Tree) ->
+ cerl_prettypr:format(cerl:set_ann(Tree, []),
+ [{hook, dialyzer_utils:pp_hook()},
+ {noann, true},
+ {paper, 100000},
+ {ribbon, 100000}
+ ]).
+
+format_type(Type, State) ->
+ R = dialyzer_dataflow:state__get_records(State),
+ erl_types:t_to_string(Type, R).
+
+mnesia_record_tab(RecordStr) ->
+ case string:str(RecordStr, "#") =:= 1 of
+ true ->
+ "'" ++
+ string:sub_string(RecordStr, 2, string:str(RecordStr, "{") - 1) ++
+ "'";
+ false -> RecordStr
+ end.
+
+mnesia_tuple_argtypes(TupleStr) ->
+ TupleStr1 = string:strip(TupleStr, left, ${),
+ [TupleStr2|_T] = string:tokens(TupleStr1, " ,"),
+ lists:flatten(string:tokens(TupleStr2, " |")).
+
+-spec race_var_map(var_to_map1(), var_to_map2(), dict:dict(), op()) ->
+ dict:dict().
+
+race_var_map(Vars1, Vars2, RaceVarMap, Op) ->
+ case Vars1 =:= ?no_arg orelse Vars1 =:= ?bypassed
+ orelse Vars2 =:= ?bypassed of
+ true -> RaceVarMap;
+ false ->
+ case is_list(Vars1) andalso is_list(Vars2) of
+ true ->
+ case Vars1 of
+ [] -> RaceVarMap;
+ [AHead|ATail] ->
+ case Vars2 of
+ [] -> RaceVarMap;
+ [PHead|PTail] ->
+ NewRaceVarMap = race_var_map(AHead, PHead, RaceVarMap, Op),
+ race_var_map(ATail, PTail, NewRaceVarMap, Op)
+ end
+ end;
+ false ->
+ {NewVars1, NewVars2, Bool} =
+ case is_list(Vars1) of
+ true ->
+ case Vars1 of
+ [Var1] -> {Var1, Vars2, true};
+ _Thing -> {Vars1, Vars2, false}
+ end;
+ false ->
+ case is_list(Vars2) of
+ true ->
+ case Vars2 of
+ [Var2] -> {Vars1, Var2, true};
+ _Thing -> {Vars1, Vars2, false}
+ end;
+ false -> {Vars1, Vars2, true}
+ end
+ end,
+ case Bool of
+ true ->
+ case cerl:type(NewVars1) of
+ var ->
+ case cerl:type(NewVars2) of
+ var ->
+ ALabel = cerl_trees:get_label(NewVars1),
+ PLabel = cerl_trees:get_label(NewVars2),
+ case Op of
+ bind ->
+ TempRaceVarMap =
+ bind_dict_vars(ALabel, PLabel, RaceVarMap),
+ bind_dict_vars(PLabel, ALabel, TempRaceVarMap);
+ unbind ->
+ TempRaceVarMap =
+ unbind_dict_vars(ALabel, PLabel, RaceVarMap),
+ unbind_dict_vars(PLabel, ALabel, TempRaceVarMap)
+ end;
+ alias ->
+ race_var_map(NewVars1, cerl:alias_var(NewVars2),
+ RaceVarMap, Op);
+ values ->
+ race_var_map(NewVars1, cerl:values_es(NewVars2),
+ RaceVarMap, Op);
+ _Other -> RaceVarMap
+ end;
+ tuple ->
+ case cerl:type(NewVars2) of
+ tuple ->
+ race_var_map(cerl:tuple_es(NewVars1),
+ cerl:tuple_es(NewVars2), RaceVarMap, Op);
+ alias ->
+ race_var_map(NewVars1, cerl:alias_var(NewVars2),
+ RaceVarMap, Op);
+ values ->
+ race_var_map(NewVars1, cerl:values_es(NewVars2),
+ RaceVarMap, Op);
+ _Other -> RaceVarMap
+ end;
+ cons ->
+ case cerl:type(NewVars2) of
+ cons ->
+ NewRaceVarMap = race_var_map(cerl:cons_hd(NewVars1),
+ cerl:cons_hd(NewVars2), RaceVarMap, Op),
+ race_var_map(cerl:cons_tl(NewVars1),
+ cerl:cons_tl(NewVars2), NewRaceVarMap, Op);
+ alias ->
+ race_var_map(NewVars1, cerl:alias_var(NewVars2),
+ RaceVarMap, Op);
+ values ->
+ race_var_map(NewVars1, cerl:values_es(NewVars2),
+ RaceVarMap, Op);
+ _Other -> RaceVarMap
+ end;
+ alias ->
+ case cerl:type(NewVars2) of
+ alias ->
+ race_var_map(cerl:alias_var(NewVars1),
+ cerl:alias_var(NewVars2), RaceVarMap, Op);
+ _Other ->
+ race_var_map(cerl:alias_var(NewVars1),
+ NewVars2, RaceVarMap, Op)
+ end;
+ values ->
+ case cerl:type(NewVars2) of
+ values ->
+ race_var_map(cerl:values_es(NewVars1),
+ cerl:values_es(NewVars2), RaceVarMap, Op);
+ _Other ->
+ race_var_map(cerl:values_es(NewVars1),
+ NewVars2, RaceVarMap, Op)
+ end;
+ _Other -> RaceVarMap
+ end;
+ false -> RaceVarMap
+ end
+ end
+ end.
+
+race_var_map_clauses(Clauses, RaceVarMap) ->
+ case Clauses of
+ [] -> RaceVarMap;
+ [#end_clause{arg = Arg, pats = Pats, guard = Guard}|T] ->
+ {RaceVarMap1, _RemoveClause} =
+ race_var_map_guard(Arg, Pats, Guard, RaceVarMap, bind),
+ race_var_map_clauses(T, RaceVarMap1)
+ end.
+
+race_var_map_guard(Arg, Pats, Guard, RaceVarMap, Op) ->
+ {NewRaceVarMap, RemoveClause} =
+ case cerl:type(Guard) of
+ call ->
+ CallName = cerl:call_name(Guard),
+ case cerl:is_literal(CallName) of
+ true ->
+ case cerl:concrete(CallName) of
+ '=:=' ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ {race_var_map(Arg1, Arg2, RaceVarMap, Op), false};
+ '==' ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ {race_var_map(Arg1, Arg2, RaceVarMap, Op), false};
+ '=/=' ->
+ case Op of
+ bind ->
+ [Arg1, Arg2] = cerl:call_args(Guard),
+ {RaceVarMap, are_bound_vars(Arg1, Arg2, RaceVarMap)};
+ unbind -> {RaceVarMap, false}
+ end;
+ _Other -> {RaceVarMap, false}
+ end;
+ false -> {RaceVarMap, false}
+ end;
+ _Other -> {RaceVarMap, false}
+ end,
+ {RaceVarMap1, RemoveClause1} =
+ race_var_map_guard_helper1(Arg, Pats,
+ race_var_map(Arg, Pats, NewRaceVarMap, Op), Op),
+ {RaceVarMap1, RemoveClause orelse RemoveClause1}.
+
+race_var_map_guard_helper1(Arg, Pats, RaceVarMap, Op) ->
+ case Arg =:= ?no_arg orelse Arg =:= ?bypassed of
+ true -> {RaceVarMap, false};
+ false ->
+ case cerl:type(Arg) of
+ call ->
+ case Pats of
+ [NewPat] ->
+ ModName = cerl:call_module(Arg),
+ CallName = cerl:call_name(Arg),
+ case cerl:is_literal(ModName) andalso
+ cerl:is_literal(CallName) of
+ true ->
+ case {cerl:concrete(ModName),
+ cerl:concrete(CallName)} of
+ {erlang, '=:='} ->
+ race_var_map_guard_helper2(Arg, NewPat, true,
+ RaceVarMap, Op);
+ {erlang, '=='} ->
+ race_var_map_guard_helper2(Arg, NewPat, true,
+ RaceVarMap, Op);
+ {erlang, '=/='} ->
+ race_var_map_guard_helper2(Arg, NewPat, false,
+ RaceVarMap, Op);
+ _Else -> {RaceVarMap, false}
+ end;
+ false -> {RaceVarMap, false}
+ end;
+ _Other -> {RaceVarMap, false}
+ end;
+ _Other -> {RaceVarMap, false}
+ end
+ end.
+
+race_var_map_guard_helper2(Arg, Pat0, Bool, RaceVarMap, Op) ->
+ Pat = cerl:fold_literal(Pat0),
+ case cerl:type(Pat) of
+ literal ->
+ [Arg1, Arg2] = cerl:call_args(Arg),
+ case cerl:concrete(Pat) of
+ Bool ->
+ {race_var_map(Arg1, Arg2, RaceVarMap, Op), false};
+ _Else ->
+ case Op of
+ bind ->
+ {RaceVarMap, are_bound_vars(Arg1, Arg2, RaceVarMap)};
+ unbind -> {RaceVarMap, false}
+ end
+ end;
+ _Else -> {RaceVarMap, false}
+ end.
+
+unbind_dict_vars(Var, Var, RaceVarMap) ->
+ RaceVarMap;
+unbind_dict_vars(Var1, Var2, RaceVarMap) ->
+ case dict:find(Var1, RaceVarMap) of
+ error -> RaceVarMap;
+ {ok, Labels} ->
+ case Labels of
+ [] -> dict:erase(Var1, RaceVarMap);
+ _Else ->
+ case lists:member(Var2, Labels) of
+ true ->
+ unbind_dict_vars(Var1, Var2,
+ bind_dict_vars_list(Var1, Labels -- [Var2],
+ dict:erase(Var1, RaceVarMap)));
+ false ->
+ unbind_dict_vars_helper(Labels, Var1, Var2, RaceVarMap)
+ end
+ end
+ end.
+
+unbind_dict_vars_helper(Labels, Key, CompLabel, RaceVarMap) ->
+ case dict:size(RaceVarMap) of
+ 0 -> RaceVarMap;
+ _ ->
+ case Labels of
+ [] -> RaceVarMap;
+ [Head|Tail] ->
+ NewRaceVarMap =
+ case are_bound_labels(Head, CompLabel, RaceVarMap) orelse
+ are_bound_labels(CompLabel, Head, RaceVarMap) of
+ true ->
+ bind_dict_vars_list(Key, Labels -- [Head],
+ dict:erase(Key, RaceVarMap));
+ false -> RaceVarMap
+ end,
+ unbind_dict_vars_helper(Tail, Key, CompLabel, NewRaceVarMap)
+ end
+ end.
+
+var_analysis(FunDefArgs, FunCallArgs, WarnVarArgs, RaceWarnTag) ->
+ case RaceWarnTag of
+ ?WARN_WHEREIS_REGISTER ->
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
+ ArgNos = lists_key_members_lists(WVA1, FunDefArgs),
+ [[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2, WVA3, WVA4];
+ ?WARN_WHEREIS_UNREGISTER ->
+ [WVA1, WVA2] = WarnVarArgs,
+ ArgNos = lists_key_members_lists(WVA1, FunDefArgs),
+ [[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2];
+ ?WARN_ETS_LOOKUP_INSERT ->
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
+ ArgNos1 = lists_key_members_lists(WVA1, FunDefArgs),
+ ArgNos2 = lists_key_members_lists(WVA3, FunDefArgs),
+ [[lists_get(N1, FunCallArgs) || N1 <- ArgNos1], WVA2,
+ [lists_get(N2, FunCallArgs) || N2 <- ArgNos2], WVA4];
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ [WVA1, WVA2|T] = WarnVarArgs,
+ ArgNos = lists_key_members_lists(WVA1, FunDefArgs),
+ [[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2|T]
+ end.
+
+var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
+ RaceVarMap, CleanState) ->
+ FunVarArgs = format_args(FunDefArgs, FunCallTypes, CleanState, function_call),
+ case RaceWarnTag of
+ ?WARN_WHEREIS_REGISTER ->
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
+ Vars = find_all_bound_vars(WVA1, RaceVarMap),
+ case lists_key_member_lists(Vars, FunVarArgs) of
+ 0 -> [Vars, WVA2, WVA3, WVA4];
+ N when is_integer(N) ->
+ NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
+ [Vars, NewWVA2, WVA3, WVA4]
+ end;
+ ?WARN_WHEREIS_UNREGISTER ->
+ [WVA1, WVA2] = WarnVarArgs,
+ Vars = find_all_bound_vars(WVA1, RaceVarMap),
+ case lists_key_member_lists(Vars, FunVarArgs) of
+ 0 -> [Vars, WVA2];
+ N when is_integer(N) ->
+ NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
+ [Vars, NewWVA2]
+ end;
+ ?WARN_ETS_LOOKUP_INSERT ->
+ [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
+ Vars1 = find_all_bound_vars(WVA1, RaceVarMap),
+ FirstVarArg =
+ case lists_key_member_lists(Vars1, FunVarArgs) of
+ 0 -> [Vars1, WVA2];
+ N1 when is_integer(N1) ->
+ NewWVA2 = string:tokens(lists:nth(N1 + 1, FunVarArgs), " |"),
+ [Vars1, NewWVA2]
+ end,
+ Vars2 =
+ lists:flatten(
+ [find_all_bound_vars(A, RaceVarMap) || A <- ets_list_args(WVA3)]),
+ case lists_key_member_lists(Vars2, FunVarArgs) of
+ 0 -> FirstVarArg ++ [Vars2, WVA4];
+ N2 when is_integer(N2) ->
+ NewWVA4 =
+ ets_tuple_argtypes2(
+ ets_tuple_argtypes1(lists:nth(N2 + 1, FunVarArgs), [], [], 0),
+ []),
+ FirstVarArg ++ [Vars2, NewWVA4]
+
+ end;
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ [WVA1, WVA2|T] = WarnVarArgs,
+ Arity =
+ case T of
+ [] -> 1;
+ _Else -> 2
+ end,
+ Vars = find_all_bound_vars(WVA1, RaceVarMap),
+ case lists_key_member_lists(Vars, FunVarArgs) of
+ 0 -> [Vars, WVA2|T];
+ N when is_integer(N) ->
+ NewWVA2 =
+ case Arity of
+ 1 ->
+ [mnesia_record_tab(R) || R <- string:tokens(
+ lists:nth(2, FunVarArgs), " |")];
+ 2 ->
+ string:tokens(lists:nth(N + 1, FunVarArgs), " |")
+ end,
+ [Vars, NewWVA2|T]
+ end
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Warning Format Utilities
+%%%
+%%% ===========================================================================
+
+add_race_warning(Warn, #races{race_warnings = Warns} = Races) ->
+ Races#races{race_warnings = [Warn|Warns]}.
+
+get_race_warn(Fun, Args, ArgTypes, DepList, State) ->
+ {M, F, _A} = Fun,
+ case DepList of
+ [] -> {State, no_race};
+ _Other ->
+ {State, {race_condition, [M, F, Args, ArgTypes, State, DepList]}}
+ end.
+
+-spec get_race_warnings(races(), dialyzer_dataflow:state()) ->
+ {races(), dialyzer_dataflow:state()}.
+
+get_race_warnings(#races{race_warnings = RaceWarnings}, State) ->
+ get_race_warnings_helper(RaceWarnings, State).
+
+get_race_warnings_helper(Warnings, State) ->
+ case Warnings of
+ [] ->
+ {dialyzer_dataflow:state__get_races(State), State};
+ [H|T] ->
+ {RaceWarnTag, WarningInfo, {race_condition, [M, F, A, AT, S, DepList]}} = H,
+ Reason =
+ case RaceWarnTag of
+ ?WARN_WHEREIS_REGISTER ->
+ get_reason(lists:keysort(7, DepList),
+ "might fail due to a possible race condition "
+ "caused by its combination with ");
+ ?WARN_WHEREIS_UNREGISTER ->
+ get_reason(lists:keysort(7, DepList),
+ "might fail due to a possible race condition "
+ "caused by its combination with ");
+ ?WARN_ETS_LOOKUP_INSERT ->
+ get_reason(lists:keysort(7, DepList),
+ "might have an unintended effect due to " ++
+ "a possible race condition " ++
+ "caused by its combination with ");
+ ?WARN_MNESIA_DIRTY_READ_WRITE ->
+ get_reason(lists:keysort(7, DepList),
+ "might have an unintended effect due to " ++
+ "a possible race condition " ++
+ "caused by its combination with ")
+ end,
+ W =
+ {?WARN_RACE_CONDITION, WarningInfo,
+ {race_condition,
+ [M, F, dialyzer_dataflow:format_args(A, AT, S), Reason]}},
+ get_race_warnings_helper(T,
+ dialyzer_dataflow:state__add_warning(W, State))
+ end.
+
+get_reason(DependencyList, Reason) ->
+ case DependencyList of
+ [] -> "";
+ [#dep_call{call_name = Call, arg_types = ArgTypes, vars = Args,
+ state = State, file_line = {File, Line}}|T] ->
+ R =
+ Reason ++
+ case Call of
+ whereis -> "the erlang:whereis";
+ ets_lookup -> "the ets:lookup";
+ mnesia_dirty_read -> "the mnesia:dirty_read"
+ end ++
+ dialyzer_dataflow:format_args(Args, ArgTypes, State) ++
+ " call in " ++
+ filename:basename(File) ++
+ " on line " ++
+ lists:flatten(io_lib:write(Line)),
+ case T of
+ [] -> R;
+ _ -> get_reason(T, R ++ ", ")
+ end
+ end.
+
+state__add_race_warning(State, RaceWarn, RaceWarnTag, WarningInfo) ->
+ case RaceWarn of
+ no_race -> State;
+ _Else ->
+ Races = dialyzer_dataflow:state__get_races(State),
+ Warn = {RaceWarnTag, WarningInfo, RaceWarn},
+ dialyzer_dataflow:state__put_races(add_race_warning(Warn, Races), State)
+ end.
+
+%%% ===========================================================================
+%%%
+%%% Record Interfaces
+%%%
+%%% ===========================================================================
+
+-spec beg_clause_new(var_to_map1(), var_to_map1(), cerl:cerl()) ->
+ #beg_clause{}.
+
+beg_clause_new(Arg, Pats, Guard) ->
+ #beg_clause{arg = Arg, pats = Pats, guard = Guard}.
+
+-spec cleanup(races()) -> races().
+
+cleanup(#races{race_list = RaceList}) ->
+ #races{race_list = RaceList}.
+
+-spec end_case_new([#end_clause{}]) -> #end_case{}.
+
+end_case_new(Clauses) ->
+ #end_case{clauses = Clauses}.
+
+-spec end_clause_new(var_to_map1(), var_to_map1(), cerl:cerl()) ->
+ #end_clause{}.
+
+end_clause_new(Arg, Pats, Guard) ->
+ #end_clause{arg = Arg, pats = Pats, guard = Guard}.
+
+-spec get_curr_fun(races()) -> dialyzer_callgraph:mfa_or_funlbl().
+
+get_curr_fun(#races{curr_fun = CurrFun}) ->
+ CurrFun.
+
+-spec get_curr_fun_args(races()) -> core_args().
+
+get_curr_fun_args(#races{curr_fun_args = CurrFunArgs}) ->
+ CurrFunArgs.
+
+-spec get_new_table(races()) -> table().
+
+get_new_table(#races{new_table = Table}) ->
+ Table.
+
+-spec get_race_analysis(races()) -> boolean().
+
+get_race_analysis(#races{race_analysis = RaceAnalysis}) ->
+ RaceAnalysis.
+
+-spec get_race_list(races()) -> code().
+
+get_race_list(#races{race_list = RaceList}) ->
+ RaceList.
+
+-spec get_race_list_size(races()) -> non_neg_integer().
+
+get_race_list_size(#races{race_list_size = RaceListSize}) ->
+ RaceListSize.
+
+-spec get_race_list_and_size(races()) -> {code(), non_neg_integer()}.
+
+get_race_list_and_size(#races{race_list = RaceList,
+ race_list_size = RaceListSize}) ->
+ {RaceList, RaceListSize}.
+
+-spec let_tag_new(var_to_map1(), var_to_map1()) -> #let_tag{}.
+
+let_tag_new(Var, Arg) ->
+ #let_tag{var = Var, arg = Arg}.
+
+-spec new() -> races().
+
+new() -> #races{}.
+
+-spec put_curr_fun(dialyzer_callgraph:mfa_or_funlbl(), label(), races()) ->
+ races().
+
+put_curr_fun(CurrFun, CurrFunLabel, Races) ->
+ Races#races{curr_fun = CurrFun,
+ curr_fun_label = CurrFunLabel,
+ curr_fun_args = empty}.
+
+-spec put_fun_args(core_args(), races()) -> races().
+
+put_fun_args(Args, #races{curr_fun_args = CurrFunArgs} = Races) ->
+ case CurrFunArgs of
+ empty -> Races#races{curr_fun_args = Args};
+ _Other -> Races
+ end.
+
+-spec put_race_analysis(boolean(), races()) ->
+ races().
+
+put_race_analysis(Analysis, Races) ->
+ Races#races{race_analysis = Analysis}.
+
+-spec put_race_list(code(), non_neg_integer(), races()) ->
+ races().
+
+put_race_list(RaceList, RaceListSize, Races) ->
+ Races#races{race_list = RaceList, race_list_size = RaceListSize}.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl
new file mode 100644
index 0000000000..449bf4cbb6
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl
@@ -0,0 +1,5741 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% ======================================================================
+%% Copyright (C) 2000-2003 Richard Carlsson
+%%
+%% ======================================================================
+%% Provides a representation of Erlang types.
+%%
+%% The initial author of this file is Richard Carlsson (2000-2004).
+%% In July 2006, the type representation was totally re-designed by
+%% Tobias Lindahl. This is the representation which is used currently.
+%% In late 2008, Manouk Manoukian and Kostis Sagonas added support for
+%% opaque types to the structure-based representation of types.
+%% During February and March 2009, Kostis Sagonas significantly
+%% cleaned up the type representation and added spec declarations.
+%%
+%% ======================================================================
+
+-module(erl_types).
+
+-export([any_none/1,
+ any_none_or_unit/1,
+ lookup_record/3,
+ max/2,
+ min/2,
+ number_max/1, number_max/2,
+ number_min/1, number_min/2,
+ t_abstract_records/2,
+ t_any/0,
+ t_arity/0,
+ t_atom/0,
+ t_atom/1,
+ t_atoms/1,
+ t_atom_vals/1, t_atom_vals/2,
+ t_binary/0,
+ t_bitstr/0,
+ t_bitstr/2,
+ t_bitstr_base/1,
+ t_bitstr_concat/1,
+ t_bitstr_concat/2,
+ t_bitstr_match/2,
+ t_bitstr_unit/1,
+ t_bitstrlist/0,
+ t_boolean/0,
+ t_byte/0,
+ t_char/0,
+ t_collect_vars/1,
+ t_cons/0,
+ t_cons/2,
+ t_cons_hd/1, t_cons_hd/2,
+ t_cons_tl/1, t_cons_tl/2,
+ t_contains_opaque/1, t_contains_opaque/2,
+ t_decorate_with_opaque/3,
+ t_elements/1,
+ t_find_opaque_mismatch/3,
+ t_find_unknown_opaque/3,
+ t_fixnum/0,
+ t_map/2,
+ t_non_neg_fixnum/0,
+ t_pos_fixnum/0,
+ t_float/0,
+ t_var_names/1,
+ t_form_to_string/1,
+ t_from_form/6,
+ t_from_form_without_remote/3,
+ t_check_record_fields/6,
+ t_from_range/2,
+ t_from_range_unsafe/2,
+ t_from_term/1,
+ t_fun/0,
+ t_fun/1,
+ t_fun/2,
+ t_fun_args/1, t_fun_args/2,
+ t_fun_arity/1, t_fun_arity/2,
+ t_fun_range/1, t_fun_range/2,
+ t_has_opaque_subtype/2,
+ t_has_var/1,
+ t_identifier/0,
+ %% t_improper_list/2,
+ t_inf/1,
+ t_inf/2,
+ t_inf/3,
+ t_inf_lists/2,
+ t_inf_lists/3,
+ t_integer/0,
+ t_integer/1,
+ t_non_neg_integer/0,
+ t_pos_integer/0,
+ t_integers/1,
+ t_iodata/0,
+ t_iolist/0,
+ t_is_any/1,
+ t_is_atom/1, t_is_atom/2,
+ t_is_any_atom/2, t_is_any_atom/3,
+ t_is_binary/1, t_is_binary/2,
+ t_is_bitstr/1, t_is_bitstr/2,
+ t_is_bitwidth/1,
+ t_is_boolean/1, t_is_boolean/2,
+ %% t_is_byte/1,
+ %% t_is_char/1,
+ t_is_cons/1, t_is_cons/2,
+ t_is_equal/2,
+ t_is_fixnum/1,
+ t_is_float/1, t_is_float/2,
+ t_is_fun/1, t_is_fun/2,
+ 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,
+ t_is_none/1,
+ t_is_none_or_unit/1,
+ t_is_number/1, t_is_number/2,
+ t_is_opaque/1, t_is_opaque/2,
+ t_is_pid/1, t_is_pid/2,
+ t_is_port/1, t_is_port/2,
+ t_is_maybe_improper_list/1, t_is_maybe_improper_list/2,
+ t_is_reference/1, t_is_reference/2,
+ t_is_singleton/1,
+ t_is_singleton/2,
+ t_is_string/1,
+ t_is_subtype/2,
+ t_is_tuple/1, t_is_tuple/2,
+ t_is_unit/1,
+ t_is_var/1,
+ t_limit/2,
+ t_list/0,
+ t_list/1,
+ t_list_elements/1, t_list_elements/2,
+ t_list_termination/1, t_list_termination/2,
+ t_map/0,
+ t_map/1,
+ t_map/3,
+ t_map_entries/2, t_map_entries/1,
+ t_map_def_key/2, t_map_def_key/1,
+ t_map_def_val/2, t_map_def_val/1,
+ t_map_get/2, t_map_get/3,
+ t_map_is_key/2, t_map_is_key/3,
+ t_map_update/2, t_map_update/3,
+ t_map_put/2, t_map_put/3,
+ t_matchstate/0,
+ t_matchstate/2,
+ t_matchstate_present/1,
+ t_matchstate_slot/2,
+ t_matchstate_slots/1,
+ t_matchstate_update_present/2,
+ t_matchstate_update_slot/3,
+ t_mfa/0,
+ t_module/0,
+ t_nil/0,
+ t_node/0,
+ t_none/0,
+ t_nonempty_list/0,
+ t_nonempty_list/1,
+ t_nonempty_string/0,
+ t_number/0,
+ t_number/1,
+ t_number_vals/1, t_number_vals/2,
+ t_opaque_from_records/1,
+ t_opaque_structure/1,
+ t_pid/0,
+ t_port/0,
+ t_maybe_improper_list/0,
+ %% t_maybe_improper_list/2,
+ t_product/1,
+ t_reference/0,
+ t_singleton_to_term/2,
+ t_string/0,
+ t_struct_from_opaque/2,
+ t_subst/2,
+ t_subtract/2,
+ t_subtract_list/2,
+ t_sup/1,
+ t_sup/2,
+ t_timeout/0,
+ t_to_string/1,
+ t_to_string/2,
+ t_to_tlist/1,
+ t_tuple/0,
+ t_tuple/1,
+ t_tuple_args/1, t_tuple_args/2,
+ t_tuple_size/1, t_tuple_size/2,
+ t_tuple_sizes/1,
+ t_tuple_subtypes/1,
+ t_tuple_subtypes/2,
+ t_unify/2,
+ t_unit/0,
+ t_unopaque/1, t_unopaque/2,
+ t_var/1,
+ t_var_name/1,
+ %% t_assign_variables_to_subtype/2,
+ type_is_defined/4,
+ record_field_diffs_to_string/2,
+ subst_all_vars_to_any/1,
+ lift_list_to_pos_empty/1, lift_list_to_pos_empty/2,
+ is_opaque_type/2,
+ is_erl_type/1,
+ atom_to_string/1,
+ var_table__new/0,
+ cache__new/0,
+ map_pairwise_merge/3
+ ]).
+
+%%-define(DO_ERL_TYPES_TEST, true).
+-compile({no_auto_import,[min/2,max/2]}).
+
+-ifdef(DO_ERL_TYPES_TEST).
+-export([test/0]).
+-else.
+-define(NO_UNUSED, true).
+-endif.
+
+-ifndef(NO_UNUSED).
+-export([t_is_identifier/1]).
+-endif.
+
+-export_type([erl_type/0, opaques/0, type_table/0, var_table/0, cache/0]).
+
+%%-define(DEBUG, true).
+
+-ifdef(DEBUG).
+-define(debug(__A), __A).
+-else.
+-define(debug(__A), ok).
+-endif.
+
+%%=============================================================================
+%%
+%% Definition of the type structure
+%%
+%%=============================================================================
+
+%%-----------------------------------------------------------------------------
+%% Limits
+%%
+
+-define(REC_TYPE_LIMIT, 2).
+-define(EXPAND_DEPTH, 16).
+-define(EXPAND_LIMIT, 10000).
+
+-define(TUPLE_TAG_LIMIT, 5).
+-define(TUPLE_ARITY_LIMIT, 8).
+-define(SET_LIMIT, 13).
+-define(MAX_BYTE, 255).
+-define(MAX_CHAR, 16#10ffff).
+
+-define(UNIT_MULTIPLIER, 8).
+
+-define(TAG_IMMED1_SIZE, 4).
+-define(BITS, (erlang:system_info(wordsize) * 8) - ?TAG_IMMED1_SIZE).
+
+-define(MAX_TUPLE_SIZE, (1 bsl 10)).
+
+%%-----------------------------------------------------------------------------
+%% Type tags and qualifiers
+%%
+
+-define(atom_tag, atom).
+-define(binary_tag, binary).
+-define(function_tag, function).
+-define(identifier_tag, identifier).
+-define(list_tag, list).
+-define(map_tag, map).
+-define(matchstate_tag, matchstate).
+-define(nil_tag, nil).
+-define(number_tag, number).
+-define(opaque_tag, opaque).
+-define(product_tag, product).
+-define(tuple_set_tag, tuple_set).
+-define(tuple_tag, tuple).
+-define(union_tag, union).
+-define(var_tag, var).
+
+-type tag() :: ?atom_tag | ?binary_tag | ?function_tag | ?identifier_tag
+ | ?list_tag | ?map_tag | ?matchstate_tag | ?nil_tag | ?number_tag
+ | ?opaque_tag | ?product_tag
+ | ?tuple_tag | ?tuple_set_tag | ?union_tag | ?var_tag.
+
+-define(float_qual, float).
+-define(integer_qual, integer).
+-define(nonempty_qual, nonempty).
+-define(pid_qual, pid).
+-define(port_qual, port).
+-define(reference_qual, reference).
+-define(unknown_qual, unknown).
+
+-type qual() :: ?float_qual | ?integer_qual | ?nonempty_qual | ?pid_qual
+ | ?port_qual | ?reference_qual | ?unknown_qual | {_, _}.
+
+%%-----------------------------------------------------------------------------
+%% The type representation
+%%
+
+-define(any, any).
+-define(none, none).
+-define(unit, unit).
+%% Generic constructor - elements can be many things depending on the tag.
+-record(c, {tag :: tag(),
+ elements = [] :: term(),
+ qualifier = ?unknown_qual :: qual()}).
+
+-opaque erl_type() :: ?any | ?none | ?unit | #c{}.
+
+%%-----------------------------------------------------------------------------
+%% Auxiliary types and convenient macros
+%%
+
+-type parse_form() :: erl_parse:abstract_type().
+-type rng_elem() :: 'pos_inf' | 'neg_inf' | integer().
+
+-record(int_set, {set :: [integer()]}).
+-record(int_rng, {from :: rng_elem(), to :: rng_elem()}).
+%% Note: the definition of #opaque{} was changed to 'mod' and 'name';
+%% it used to be an ordsets of {Mod, Name} pairs. The Dialyzer version
+%% was updated to 2.7 due to this change.
+-record(opaque, {mod :: module(), name :: atom(),
+ args = [] :: [erl_type()], struct :: erl_type()}).
+
+-define(atom(Set), #c{tag=?atom_tag, elements=Set}).
+-define(bitstr(Unit, Base), #c{tag=?binary_tag, elements=[Unit,Base]}).
+-define(float, ?number(?any, ?float_qual)).
+-define(function(Domain, Range), #c{tag=?function_tag,
+ elements=[Domain, Range]}).
+-define(identifier(Types), #c{tag=?identifier_tag, elements=Types}).
+-define(integer(Types), ?number(Types, ?integer_qual)).
+-define(int_range(From, To), ?integer(#int_rng{from=From, to=To})).
+-define(int_set(Set), ?integer(#int_set{set=Set})).
+-define(list(Types, Term, Size), #c{tag=?list_tag, elements=[Types,Term],
+ qualifier=Size}).
+-define(nil, #c{tag=?nil_tag}).
+-define(nonempty_list(Types, Term),?list(Types, Term, ?nonempty_qual)).
+-define(number(Set, Qualifier), #c{tag=?number_tag, elements=Set,
+ qualifier=Qualifier}).
+-define(map(Pairs,DefKey,DefVal),
+ #c{tag=?map_tag, elements={Pairs,DefKey,DefVal}}).
+-define(opaque(Optypes), #c{tag=?opaque_tag, elements=Optypes}).
+-define(product(Types), #c{tag=?product_tag, elements=Types}).
+-define(tuple(Types, Arity, Qual), #c{tag=?tuple_tag, elements=Types,
+ qualifier={Arity, Qual}}).
+-define(tuple_set(Tuples), #c{tag=?tuple_set_tag, elements=Tuples}).
+-define(var(Id), #c{tag=?var_tag, elements=Id}).
+
+-define(matchstate(P, Slots), #c{tag=?matchstate_tag, elements=[P,Slots]}).
+-define(any_matchstate, ?matchstate(t_bitstr(), ?any)).
+
+-define(byte, ?int_range(0, ?MAX_BYTE)).
+-define(char, ?int_range(0, ?MAX_CHAR)).
+-define(integer_pos, ?int_range(1, pos_inf)).
+-define(integer_non_neg, ?int_range(0, pos_inf)).
+-define(integer_neg, ?int_range(neg_inf, -1)).
+
+-type opaques() :: [erl_type()] | 'universe'.
+
+-type record_key() :: {'record', atom()}.
+-type type_key() :: {'type' | 'opaque', mfa()}.
+-type record_value() :: [{atom(), erl_parse:abstract_expr(), erl_type()}].
+-type type_value() :: {{module(), {file:name(), erl_anno:line()},
+ erl_parse:abstract_type(), ArgNames :: [atom()]},
+ erl_type()}.
+-type type_table() :: dict:dict(record_key() | type_key(),
+ record_value() | type_value()).
+
+-opaque var_table() :: #{atom() => erl_type()}.
+
+%%-----------------------------------------------------------------------------
+%% Unions
+%%
+
+-define(union(List), #c{tag=?union_tag, elements=[_,_,_,_,_,_,_,_,_,_]=List}).
+
+-define(atom_union(T), ?union([T,?none,?none,?none,?none,?none,?none,?none,?none,?none])).
+-define(bitstr_union(T), ?union([?none,T,?none,?none,?none,?none,?none,?none,?none,?none])).
+-define(function_union(T), ?union([?none,?none,T,?none,?none,?none,?none,?none,?none,?none])).
+-define(identifier_union(T), ?union([?none,?none,?none,T,?none,?none,?none,?none,?none,?none])).
+-define(list_union(T), ?union([?none,?none,?none,?none,T,?none,?none,?none,?none,?none])).
+-define(number_union(T), ?union([?none,?none,?none,?none,?none,T,?none,?none,?none,?none])).
+-define(tuple_union(T), ?union([?none,?none,?none,?none,?none,?none,T,?none,?none,?none])).
+-define(matchstate_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,T,?none,?none])).
+-define(opaque_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,?none,T,?none])).
+-define(map_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,?none,?none,T])).
+-define(integer_union(T), ?number_union(T)).
+-define(float_union(T), ?number_union(T)).
+-define(nil_union(T), ?list_union(T)).
+
+
+%%=============================================================================
+%%
+%% Primitive operations such as type construction and type tests
+%%
+%%=============================================================================
+
+%%-----------------------------------------------------------------------------
+%% Top and bottom
+%%
+
+-spec t_any() -> erl_type().
+
+t_any() ->
+ ?any.
+
+-spec t_is_any(erl_type()) -> boolean().
+
+t_is_any(Type) ->
+ do_opaque(Type, 'universe', fun is_any/1).
+
+is_any(?any) -> true;
+is_any(_) -> false.
+
+-spec t_none() -> erl_type().
+
+t_none() ->
+ ?none.
+
+-spec t_is_none(erl_type()) -> boolean().
+
+t_is_none(?none) -> true;
+t_is_none(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Opaque types
+%%
+
+-spec t_opaque(module(), atom(), [_], erl_type()) -> erl_type().
+
+t_opaque(Mod, Name, Args, Struct) ->
+ O = #opaque{mod = Mod, name = Name, args = Args, struct = Struct},
+ ?opaque(set_singleton(O)).
+
+-spec t_is_opaque(erl_type(), [erl_type()]) -> boolean().
+
+t_is_opaque(?opaque(_) = Type, Opaques) ->
+ not is_opaque_type(Type, Opaques);
+t_is_opaque(_Type, _Opaques) -> false.
+
+-spec t_is_opaque(erl_type()) -> boolean().
+
+t_is_opaque(?opaque(_)) -> true;
+t_is_opaque(_) -> false.
+
+-spec t_has_opaque_subtype(erl_type(), opaques()) -> boolean().
+
+t_has_opaque_subtype(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun has_opaque_subtype/1).
+
+has_opaque_subtype(?union(Ts)) ->
+ lists:any(fun t_is_opaque/1, Ts);
+has_opaque_subtype(T) ->
+ t_is_opaque(T).
+
+-spec t_opaque_structure(erl_type()) -> erl_type().
+
+t_opaque_structure(?opaque(Elements)) ->
+ t_sup([Struct || #opaque{struct = Struct} <- ordsets:to_list(Elements)]).
+
+-spec t_contains_opaque(erl_type()) -> boolean().
+
+t_contains_opaque(Type) ->
+ t_contains_opaque(Type, []).
+
+%% Returns 'true' iff there is an opaque type that is *not* one of
+%% the types of the second argument.
+
+-spec t_contains_opaque(erl_type(), [erl_type()]) -> boolean().
+
+t_contains_opaque(?any, _Opaques) -> false;
+t_contains_opaque(?none, _Opaques) -> false;
+t_contains_opaque(?unit, _Opaques) -> false;
+t_contains_opaque(?atom(_Set), _Opaques) -> false;
+t_contains_opaque(?bitstr(_Unit, _Base), _Opaques) -> false;
+t_contains_opaque(?float, _Opaques) -> false;
+t_contains_opaque(?function(Domain, Range), Opaques) ->
+ t_contains_opaque(Domain, Opaques)
+ orelse t_contains_opaque(Range, Opaques);
+t_contains_opaque(?identifier(_Types), _Opaques) -> false;
+t_contains_opaque(?integer(_Types), _Opaques) -> false;
+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(_, _, _) = Map, Opaques) ->
+ list_contains_opaque(map_all_types(Map), Opaques);
+t_contains_opaque(?matchstate(_P, _Slots), _Opaques) -> false;
+t_contains_opaque(?nil, _Opaques) -> false;
+t_contains_opaque(?number(_Set, _Tag), _Opaques) -> false;
+t_contains_opaque(?opaque(_)=T, Opaques) ->
+ not is_opaque_type(T, Opaques)
+ orelse t_contains_opaque(t_opaque_structure(T));
+t_contains_opaque(?product(Types), Opaques) ->
+ list_contains_opaque(Types, Opaques);
+t_contains_opaque(?tuple(?any, _, _), _Opaques) -> false;
+t_contains_opaque(?tuple(Types, _, _), Opaques) ->
+ list_contains_opaque(Types, Opaques);
+t_contains_opaque(?tuple_set(_Set) = T, Opaques) ->
+ list_contains_opaque(t_tuple_subtypes(T), Opaques);
+t_contains_opaque(?union(List), Opaques) ->
+ list_contains_opaque(List, Opaques);
+t_contains_opaque(?var(_Id), _Opaques) -> false.
+
+-spec list_contains_opaque([erl_type()], [erl_type()]) -> boolean().
+
+list_contains_opaque(List, Opaques) ->
+ lists:any(fun(E) -> t_contains_opaque(E, Opaques) end, List).
+
+%% t_find_opaque_mismatch/2 of two types should only be used if their
+%% t_inf is t_none() due to some opaque type violation.
+%%
+%% The first argument of the function is the pattern and its second
+%% argument the type we are matching against the pattern.
+
+-spec t_find_opaque_mismatch(erl_type(), erl_type(), [erl_type()]) ->
+ 'error' | {'ok', erl_type(), erl_type()}.
+
+t_find_opaque_mismatch(T1, T2, Opaques) ->
+ t_find_opaque_mismatch(T1, T2, T2, Opaques).
+
+t_find_opaque_mismatch(?any, _Type, _TopType, _Opaques) -> error;
+t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> error;
+t_find_opaque_mismatch(?list(T1, Tl1, _), ?list(T2, Tl2, _), TopType, Opaques) ->
+ t_find_opaque_mismatch_ordlists([T1, Tl1], [T2, Tl2], TopType, Opaques);
+t_find_opaque_mismatch(T1, ?opaque(_) = T2, TopType, Opaques) ->
+ case is_opaque_type(T2, Opaques) of
+ false -> {ok, TopType, T2};
+ true ->
+ t_find_opaque_mismatch(T1, t_opaque_structure(T2), TopType, Opaques)
+ end;
+t_find_opaque_mismatch(?opaque(_) = T1, T2, TopType, Opaques) ->
+ %% The generated message is somewhat misleading:
+ case is_opaque_type(T1, Opaques) of
+ false -> {ok, TopType, T1};
+ true ->
+ t_find_opaque_mismatch(t_opaque_structure(T1), T2, TopType, Opaques)
+ end;
+t_find_opaque_mismatch(?product(T1), ?product(T2), TopType, Opaques) ->
+ t_find_opaque_mismatch_ordlists(T1, T2, TopType, Opaques);
+t_find_opaque_mismatch(?tuple(T1, Arity, _), ?tuple(T2, Arity, _),
+ TopType, Opaques) ->
+ t_find_opaque_mismatch_ordlists(T1, T2, TopType, Opaques);
+t_find_opaque_mismatch(?tuple(_, _, _) = T1, ?tuple_set(_) = T2,
+ TopType, Opaques) ->
+ Tuples1 = t_tuple_subtypes(T1),
+ Tuples2 = t_tuple_subtypes(T2),
+ t_find_opaque_mismatch_lists(Tuples1, Tuples2, TopType, Opaques);
+t_find_opaque_mismatch(T1, ?union(U2), TopType, Opaques) ->
+ t_find_opaque_mismatch_lists([T1], U2, TopType, Opaques);
+t_find_opaque_mismatch(_T1, _T2, _TopType, _Opaques) -> error.
+
+t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
+ List = lists:zipwith(fun(T1, T2) ->
+ t_find_opaque_mismatch(T1, T2, TopType, Opaques)
+ end, L1, L2),
+ t_find_opaque_mismatch_list(List).
+
+t_find_opaque_mismatch_lists(L1, L2, _TopType, Opaques) ->
+ List = [t_find_opaque_mismatch(T1, T2, T2, Opaques) || T1 <- L1, T2 <- L2],
+ t_find_opaque_mismatch_list(List).
+
+t_find_opaque_mismatch_list([]) -> error;
+t_find_opaque_mismatch_list([H|T]) ->
+ case H of
+ {ok, _T1, _T2} -> H;
+ error -> t_find_opaque_mismatch_list(T)
+ end.
+
+-spec t_find_unknown_opaque(erl_type(), erl_type(), opaques()) ->
+ [pos_integer()].
+
+%% The nice thing about using two types and t_inf() as compared to
+%% calling t_contains_opaque/2 is that the traversal stops when
+%% there is a mismatch which means that unknown opaque types "below"
+%% the mismatch are not found.
+t_find_unknown_opaque(_T1, _T2, 'universe') -> [];
+t_find_unknown_opaque(T1, T2, Opaques) ->
+ try t_inf(T1, T2, {match, Opaques}) of
+ _ -> []
+ catch throw:{pos, Ns} -> Ns
+ end.
+
+-spec t_decorate_with_opaque(erl_type(), erl_type(), [erl_type()]) -> erl_type().
+
+%% The first argument can contain opaque types. The second argument
+%% is assumed to be taken from the contract.
+
+t_decorate_with_opaque(T1, T2, Opaques) ->
+ case t_is_equal(T1, T2) orelse not t_contains_opaque(T2) of
+ true -> T1;
+ false ->
+ T = t_inf(T1, T2),
+ case t_contains_opaque(T) of
+ false -> T1;
+ true ->
+ R = decorate(T1, T, Opaques),
+ ?debug(case catch t_is_equal(t_unopaque(R), t_unopaque(T1)) of
+ true -> ok;
+ false ->
+ io:format("T1 = ~p,\n", [T1]),
+ io:format("T2 = ~p,\n", [T2]),
+ io:format("O = ~p,\n", [Opaques]),
+ io:format("erl_types:t_decorate_with_opaque(T1,T2,O).\n"),
+ throw({error, "Failed to handle opaque types"})
+ end),
+ R
+ end
+ end.
+
+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) ->
+ ?list(decorate(Types, Ts, Opaques), decorate(Tail, Tl, Opaques), Size);
+decorate(?product(Types), ?product(Ts), Opaques) ->
+ ?product(list_decorate(Types, Ts, Opaques));
+decorate(?tuple(_, _, _)=T, ?tuple(?any, _, _), _Opaques) -> T;
+decorate(?tuple(?any, _, _)=T, ?tuple(_, _, _), _Opaques) -> T;
+decorate(?tuple(Types, Arity, Tag), ?tuple(Ts, Arity, _), Opaques) ->
+ ?tuple(list_decorate(Types, Ts, Opaques), Arity, Tag);
+decorate(?tuple_set(List), ?tuple(_, Arity, _) = T, Opaques) ->
+ decorate_tuple_sets(List, [{Arity, [T]}], Opaques);
+decorate(?tuple_set(List), ?tuple_set(L), Opaques) ->
+ decorate_tuple_sets(List, L, Opaques);
+decorate(?union(List), T, Opaques) when T =/= ?any ->
+ ?union(L) = force_union(T),
+ union_decorate(List, L, Opaques);
+decorate(?opaque(_)=T, _, _Opaques) -> T;
+decorate(T, ?union(L), Opaques) when T =/= ?any ->
+ ?union(List) = force_union(T),
+ union_decorate(List, L, Opaques);
+decorate(Type, ?opaque(_)=T, Opaques) ->
+ decorate_with_opaque(Type, T, Opaques);
+decorate(Type, _T, _Opaques) -> Type.
+
+%% Note: it is important that #opaque.struct is a subtype of the
+%% opaque type.
+decorate_with_opaque(Type, ?opaque(Set2), Opaques) ->
+ case decoration(set_to_list(Set2), Type, Opaques, [], false) of
+ {[], false} -> Type;
+ {List, All} when List =/= [] ->
+ NewType = ?opaque(ordsets:from_list(List)),
+ case All of
+ true -> NewType;
+ false -> t_sup(NewType, Type)
+ end
+ end.
+
+decoration([#opaque{struct = S} = Opaque|OpaqueTypes], Type, Opaques,
+ NewOpaqueTypes0, All) ->
+ IsOpaque = is_opaque_type2(Opaque, Opaques),
+ I = t_inf(Type, S),
+ case not IsOpaque orelse t_is_none(I) of
+ true -> decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes0, All);
+ false ->
+ NewOpaque = Opaque#opaque{struct = decorate(I, S, Opaques)},
+ NewAll = All orelse t_is_equal(I, Type),
+ NewOpaqueTypes = [NewOpaque|NewOpaqueTypes0],
+ decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes, NewAll)
+ end;
+decoration([], _Type, _Opaques, NewOpaqueTypes, All) ->
+ {NewOpaqueTypes, All}.
+
+-spec list_decorate([erl_type()], [erl_type()], opaques()) -> [erl_type()].
+
+list_decorate(List, L, Opaques) ->
+ [decorate(Elem, E, Opaques) || {Elem, E} <- lists:zip(List, L)].
+
+union_decorate(U1, U2, Opaques) ->
+ Union = union_decorate(U1, U2, Opaques, 0, []),
+ [A,B,F,I,L,N,T,M,_,Map] = U1,
+ [_,_,_,_,_,_,_,_,Opaque,_] = U2,
+ 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]).
+
+union_decorate([?none|Left1], [_|Left2], Opaques, N, Acc) ->
+ union_decorate(Left1, Left2, Opaques, N, [?none|Acc]);
+union_decorate([T1|Left1], [?none|Left2], Opaques, N, Acc) ->
+ union_decorate(Left1, Left2, Opaques, N+1, [T1|Acc]);
+union_decorate([T1|Left1], [T2|Left2], Opaques, N, Acc) ->
+ union_decorate(Left1, Left2, Opaques, N+1, [decorate(T1, T2, Opaques)|Acc]);
+union_decorate([], [], _Opaques, N, Acc) ->
+ if N =:= 0 -> ?none;
+ N =:= 1 ->
+ [Type] = [T || T <- Acc, T =/= ?none],
+ Type;
+ N >= 2 -> ?union(lists:reverse(Acc))
+ end.
+
+decorate_tuple_sets(List, L, Opaques) ->
+ decorate_tuple_sets(List, L, Opaques, []).
+
+decorate_tuple_sets([{Arity, Tuples}|List], [{Arity, Ts}|L], Opaques, Acc) ->
+ DecTs = decorate_tuples_in_sets(Tuples, Ts, Opaques),
+ decorate_tuple_sets(List, L, Opaques, [{Arity, DecTs}|Acc]);
+decorate_tuple_sets([ArTup|List], L, Opaques, Acc) ->
+ decorate_tuple_sets(List, L, Opaques, [ArTup|Acc]);
+decorate_tuple_sets([], _L, _Opaques, Acc) ->
+ ?tuple_set(lists:reverse(Acc)).
+
+decorate_tuples_in_sets([?tuple(Elements, _, ?any)], Ts, Opaques) ->
+ NewList = [list_decorate(Elements, Es, Opaques) || ?tuple(Es, _, _) <- Ts],
+ case t_sup([t_tuple(Es) || Es <- NewList]) of
+ ?tuple_set([{_Arity, Tuples}]) -> Tuples;
+ ?tuple(_, _, _)=Tuple -> [Tuple]
+ end;
+decorate_tuples_in_sets(Tuples, Ts, Opaques) ->
+ decorate_tuples_in_sets(Tuples, Ts, Opaques, []).
+
+decorate_tuples_in_sets([?tuple(Elements, Arity, Tag1) = T1|Tuples] = L1,
+ [?tuple(Es, Arity, Tag2)|Ts] = L2, Opaques, Acc) ->
+ if
+ Tag1 < Tag2 -> decorate_tuples_in_sets(Tuples, L2, Opaques, [T1|Acc]);
+ Tag1 > Tag2 -> decorate_tuples_in_sets(L1, Ts, Opaques, Acc);
+ Tag1 =:= Tag2 ->
+ NewElements = list_decorate(Elements, Es, Opaques),
+ NewAcc = [?tuple(NewElements, Arity, Tag1)|Acc],
+ decorate_tuples_in_sets(Tuples, Ts, Opaques, NewAcc)
+ end;
+decorate_tuples_in_sets([T1|Tuples], L2, Opaques, Acc) ->
+ decorate_tuples_in_sets(Tuples, L2, Opaques, [T1|Acc]);
+decorate_tuples_in_sets([], _L, _Opaques, Acc) ->
+ lists:reverse(Acc).
+
+-spec t_opaque_from_records(type_table()) -> [erl_type()].
+
+t_opaque_from_records(RecDict) ->
+ OpaqueRecDict =
+ dict:filter(fun(Key, _Value) ->
+ case Key of
+ {opaque, _Name, _Arity} -> true;
+ _ -> false
+ end
+ end, RecDict),
+ OpaqueTypeDict =
+ dict:map(fun({opaque, Name, _Arity},
+ {{Module, _FileLine, _Form, ArgNames}, _Type}) ->
+ %% Args = args_to_types(ArgNames),
+ %% List = lists:zip(ArgNames, Args),
+ %% TmpVarTab = maps:to_list(List),
+ %% Rep = t_from_form(Type, RecDict, TmpVarTab),
+ Rep = t_any(), % not used for anything right now
+ Args = [t_any() || _ <- ArgNames],
+ t_opaque(Module, Name, Args, Rep)
+ end, OpaqueRecDict),
+ [OpaqueType || {_Key, OpaqueType} <- dict:to_list(OpaqueTypeDict)].
+
+%% Decompose opaque instances of type arg2 to structured types, in arg1
+%% XXX: Same as t_unopaque
+-spec t_struct_from_opaque(erl_type(), [erl_type()]) -> erl_type().
+
+t_struct_from_opaque(?function(Domain, Range), Opaques) ->
+ ?function(t_struct_from_opaque(Domain, Opaques),
+ t_struct_from_opaque(Range, Opaques));
+t_struct_from_opaque(?list(Types, Term, Size), Opaques) ->
+ ?list(t_struct_from_opaque(Types, Opaques),
+ t_struct_from_opaque(Term, Opaques), Size);
+t_struct_from_opaque(?opaque(_) = T, Opaques) ->
+ case is_opaque_type(T, Opaques) of
+ true -> t_opaque_structure(T);
+ false -> T
+ end;
+t_struct_from_opaque(?product(Types), Opaques) ->
+ ?product(list_struct_from_opaque(Types, Opaques));
+t_struct_from_opaque(?tuple(?any, _, _) = T, _Opaques) -> T;
+t_struct_from_opaque(?tuple(Types, Arity, Tag), Opaques) ->
+ ?tuple(list_struct_from_opaque(Types, Opaques), Arity, Tag);
+t_struct_from_opaque(?tuple_set(Set), Opaques) ->
+ NewSet = [{Sz, [t_struct_from_opaque(T, Opaques) || T <- Tuples]}
+ || {Sz, Tuples} <- Set],
+ ?tuple_set(NewSet);
+t_struct_from_opaque(?union(List), Opaques) ->
+ t_sup(list_struct_from_opaque(List, Opaques));
+t_struct_from_opaque(Type, _Opaques) -> Type.
+
+list_struct_from_opaque(Types, Opaques) ->
+ [t_struct_from_opaque(Type, Opaques) || Type <- Types].
+
+%%-----------------------------------------------------------------------------
+
+-type mod_records() :: dict:dict(module(), type_table()).
+
+%%-----------------------------------------------------------------------------
+%% Unit type. Signals non termination.
+%%
+
+-spec t_unit() -> erl_type().
+
+t_unit() ->
+ ?unit.
+
+-spec t_is_unit(erl_type()) -> boolean().
+
+t_is_unit(?unit) -> true;
+t_is_unit(_) -> false.
+
+-spec t_is_none_or_unit(erl_type()) -> boolean().
+
+t_is_none_or_unit(?none) -> true;
+t_is_none_or_unit(?unit) -> true;
+t_is_none_or_unit(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Atoms and the derived type boolean
+%%
+
+-spec t_atom() -> erl_type().
+
+t_atom() ->
+ ?atom(?any).
+
+-spec t_atom(atom()) -> erl_type().
+
+t_atom(A) when is_atom(A) ->
+ ?atom(set_singleton(A)).
+
+-spec t_atoms([atom()]) -> erl_type().
+
+t_atoms(List) when is_list(List) ->
+ t_sup([t_atom(A) || A <- List]).
+
+-spec t_atom_vals(erl_type()) -> 'unknown' | [atom(),...].
+
+t_atom_vals(Type) ->
+ t_atom_vals(Type, 'universe').
+
+-spec t_atom_vals(erl_type(), opaques()) -> 'unknown' | [atom(),...].
+
+t_atom_vals(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun atom_vals/1).
+
+atom_vals(?atom(?any)) -> unknown;
+atom_vals(?atom(Set)) -> set_to_list(Set);
+atom_vals(?opaque(_)) -> unknown;
+atom_vals(Other) ->
+ ?atom(_) = Atm = t_inf(t_atom(), Other),
+ atom_vals(Atm).
+
+-spec t_is_atom(erl_type()) -> boolean().
+
+t_is_atom(Type) ->
+ t_is_atom(Type, 'universe').
+
+-spec t_is_atom(erl_type(), opaques()) -> boolean().
+
+t_is_atom(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_atom1/1).
+
+is_atom1(?atom(_)) -> true;
+is_atom1(_) -> false.
+
+-spec t_is_any_atom(atom(), erl_type()) -> boolean().
+
+t_is_any_atom(Atom, SomeAtomsType) ->
+ t_is_any_atom(Atom, SomeAtomsType, 'universe').
+
+-spec t_is_any_atom(atom(), erl_type(), opaques()) -> boolean().
+
+t_is_any_atom(Atom, SomeAtomsType, Opaques) ->
+ do_opaque(SomeAtomsType, Opaques,
+ fun(AtomsType) -> is_any_atom(Atom, AtomsType) end).
+
+is_any_atom(Atom, ?atom(?any)) when is_atom(Atom) -> false;
+is_any_atom(Atom, ?atom(Set)) when is_atom(Atom) ->
+ set_is_singleton(Atom, Set);
+is_any_atom(Atom, _) when is_atom(Atom) -> false.
+
+%%------------------------------------
+
+-spec t_is_boolean(erl_type()) -> boolean().
+
+t_is_boolean(Type) ->
+ t_is_boolean(Type, 'universe').
+
+-spec t_is_boolean(erl_type(), opaques()) -> boolean().
+
+t_is_boolean(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_boolean/1).
+
+-spec t_boolean() -> erl_type().
+
+t_boolean() ->
+ ?atom(set_from_list([false, true])).
+
+is_boolean(?atom(?any)) -> false;
+is_boolean(?atom(Set)) ->
+ case set_size(Set) of
+ 1 -> set_is_element(true, Set) orelse set_is_element(false, Set);
+ 2 -> set_is_element(true, Set) andalso set_is_element(false, Set);
+ N when is_integer(N), N > 2 -> false
+ end;
+is_boolean(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Binaries
+%%
+
+-spec t_binary() -> erl_type().
+
+t_binary() ->
+ ?bitstr(8, 0).
+
+-spec t_is_binary(erl_type()) -> boolean().
+
+t_is_binary(Type) ->
+ t_is_binary(Type, 'universe').
+
+-spec t_is_binary(erl_type(), opaques()) -> boolean().
+
+t_is_binary(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_binary/1).
+
+is_binary(?bitstr(U, B)) ->
+ ((U rem 8) =:= 0) andalso ((B rem 8) =:= 0);
+is_binary(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Bitstrings
+%%
+
+-spec t_bitstr() -> erl_type().
+
+t_bitstr() ->
+ ?bitstr(1, 0).
+
+-spec t_bitstr(non_neg_integer(), non_neg_integer()) -> erl_type().
+
+t_bitstr(U, B) ->
+ NewB =
+ if
+ U =:= 0 -> B;
+ B >= (U * (?UNIT_MULTIPLIER + 1)) ->
+ (B rem U) + U * ?UNIT_MULTIPLIER;
+ true ->
+ B
+ end,
+ ?bitstr(U, NewB).
+
+-spec t_bitstr_unit(erl_type()) -> non_neg_integer().
+
+t_bitstr_unit(?bitstr(U, _)) -> U.
+
+-spec t_bitstr_base(erl_type()) -> non_neg_integer().
+
+t_bitstr_base(?bitstr(_, B)) -> B.
+
+-spec t_bitstr_concat([erl_type()]) -> erl_type().
+
+t_bitstr_concat(List) ->
+ t_bitstr_concat_1(List, t_bitstr(0, 0)).
+
+t_bitstr_concat_1([T|Left], Acc) ->
+ t_bitstr_concat_1(Left, t_bitstr_concat(Acc, T));
+t_bitstr_concat_1([], Acc) ->
+ Acc.
+
+-spec t_bitstr_concat(erl_type(), erl_type()) -> erl_type().
+
+t_bitstr_concat(T1, T2) ->
+ T1p = t_inf(t_bitstr(), T1),
+ T2p = t_inf(t_bitstr(), T2),
+ bitstr_concat(t_unopaque(T1p), t_unopaque(T2p)).
+
+-spec t_bitstr_match(erl_type(), erl_type()) -> erl_type().
+
+t_bitstr_match(T1, T2) ->
+ T1p = t_inf(t_bitstr(), T1),
+ T2p = t_inf(t_bitstr(), T2),
+ bitstr_match(t_unopaque(T1p), t_unopaque(T2p)).
+
+-spec t_is_bitstr(erl_type()) -> boolean().
+
+t_is_bitstr(Type) ->
+ t_is_bitstr(Type, 'universe').
+
+-spec t_is_bitstr(erl_type(), opaques()) -> boolean().
+
+t_is_bitstr(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_bitstr/1).
+
+is_bitstr(?bitstr(_, _)) -> true;
+is_bitstr(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Matchstates
+%%
+
+-spec t_matchstate() -> erl_type().
+
+t_matchstate() ->
+ ?any_matchstate.
+
+-spec t_matchstate(erl_type(), non_neg_integer()) -> erl_type().
+
+t_matchstate(Init, 0) ->
+ ?matchstate(Init, Init);
+t_matchstate(Init, Max) when is_integer(Max) ->
+ Slots = [Init|[?none || _ <- lists:seq(1, Max)]],
+ ?matchstate(Init, t_product(Slots)).
+
+-spec t_is_matchstate(erl_type()) -> boolean().
+
+t_is_matchstate(?matchstate(_, _)) -> true;
+t_is_matchstate(_) -> false.
+
+-spec t_matchstate_present(erl_type()) -> erl_type().
+
+t_matchstate_present(Type) ->
+ case t_inf(t_matchstate(), Type) of
+ ?matchstate(P, _) -> P;
+ _ -> ?none
+ end.
+
+-spec t_matchstate_slot(erl_type(), non_neg_integer()) -> erl_type().
+
+t_matchstate_slot(Type, Slot) ->
+ RealSlot = Slot + 1,
+ case t_inf(t_matchstate(), Type) of
+ ?matchstate(_, ?any) -> ?any;
+ ?matchstate(_, ?product(Vals)) when length(Vals) >= RealSlot ->
+ lists:nth(RealSlot, Vals);
+ ?matchstate(_, ?product(_)) ->
+ ?none;
+ ?matchstate(_, SlotType) when RealSlot =:= 1 ->
+ SlotType;
+ _ ->
+ ?none
+ end.
+
+-spec t_matchstate_slots(erl_type()) -> erl_type().
+
+t_matchstate_slots(?matchstate(_, Slots)) ->
+ Slots.
+
+-spec t_matchstate_update_present(erl_type(), erl_type()) -> erl_type().
+
+t_matchstate_update_present(New, Type) ->
+ case t_inf(t_matchstate(), Type) of
+ ?matchstate(_, Slots) ->
+ ?matchstate(New, Slots);
+ _ -> ?none
+ end.
+
+-spec t_matchstate_update_slot(erl_type(), erl_type(), non_neg_integer()) -> erl_type().
+
+t_matchstate_update_slot(New, Type, Slot) ->
+ RealSlot = Slot + 1,
+ case t_inf(t_matchstate(), Type) of
+ ?matchstate(Pres, Slots) ->
+ NewSlots =
+ case Slots of
+ ?any ->
+ ?any;
+ ?product(Vals) when length(Vals) >= RealSlot ->
+ NewTuple = setelement(RealSlot, list_to_tuple(Vals), New),
+ NewVals = tuple_to_list(NewTuple),
+ ?product(NewVals);
+ ?product(_) ->
+ ?none;
+ _ when RealSlot =:= 1 ->
+ New;
+ _ ->
+ ?none
+ end,
+ ?matchstate(Pres, NewSlots);
+ _ ->
+ ?none
+ end.
+
+%%-----------------------------------------------------------------------------
+%% Functions
+%%
+
+-spec t_fun() -> erl_type().
+
+t_fun() ->
+ ?function(?any, ?any).
+
+-spec t_fun(erl_type()) -> erl_type().
+
+t_fun(Range) ->
+ ?function(?any, Range).
+
+-spec t_fun([erl_type()] | arity(), erl_type()) -> erl_type().
+
+t_fun(Domain, Range) when is_list(Domain) ->
+ ?function(?product(Domain), Range);
+t_fun(Arity, Range) when is_integer(Arity), 0 =< Arity, Arity =< 255 ->
+ ?function(?product(lists:duplicate(Arity, ?any)), Range).
+
+-spec t_fun_args(erl_type()) -> 'unknown' | [erl_type()].
+
+t_fun_args(Type) ->
+ t_fun_args(Type, 'universe').
+
+-spec t_fun_args(erl_type(), opaques()) -> 'unknown' | [erl_type()].
+
+t_fun_args(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun fun_args/1).
+
+fun_args(?function(?any, _)) ->
+ unknown;
+fun_args(?function(?product(Domain), _)) when is_list(Domain) ->
+ Domain.
+
+-spec t_fun_arity(erl_type()) -> 'unknown' | non_neg_integer().
+
+t_fun_arity(Type) ->
+ t_fun_arity(Type, 'universe').
+
+-spec t_fun_arity(erl_type(), opaques()) -> 'unknown' | non_neg_integer().
+
+t_fun_arity(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun fun_arity/1).
+
+fun_arity(?function(?any, _)) ->
+ unknown;
+fun_arity(?function(?product(Domain), _)) ->
+ length(Domain).
+
+-spec t_fun_range(erl_type()) -> erl_type().
+
+t_fun_range(Type) ->
+ t_fun_range(Type, 'universe').
+
+-spec t_fun_range(erl_type(), opaques()) -> erl_type().
+
+t_fun_range(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun fun_range/1).
+
+fun_range(?function(_, Range)) ->
+ Range.
+
+-spec t_is_fun(erl_type()) -> boolean().
+
+t_is_fun(Type) ->
+ t_is_fun(Type, 'universe').
+
+-spec t_is_fun(erl_type(), opaques()) -> boolean().
+
+t_is_fun(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_fun/1).
+
+is_fun(?function(_, _)) -> true;
+is_fun(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Identifiers. Includes ports, pids and refs.
+%%
+
+-spec t_identifier() -> erl_type().
+
+t_identifier() ->
+ ?identifier(?any).
+
+-ifdef(DO_ERL_TYPES_TEST).
+-spec t_is_identifier(erl_type()) -> erl_type().
+
+t_is_identifier(?identifier(_)) -> true;
+t_is_identifier(_) -> false.
+-endif.
+
+%%------------------------------------
+
+-spec t_port() -> erl_type().
+
+t_port() ->
+ ?identifier(set_singleton(?port_qual)).
+
+-spec t_is_port(erl_type()) -> boolean().
+
+t_is_port(Type) ->
+ t_is_port(Type, 'universe').
+
+-spec t_is_port(erl_type(), opaques()) -> boolean().
+
+t_is_port(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_port1/1).
+
+is_port1(?identifier(?any)) -> false;
+is_port1(?identifier(Set)) -> set_is_singleton(?port_qual, Set);
+is_port1(_) -> false.
+
+%%------------------------------------
+
+-spec t_pid() -> erl_type().
+
+t_pid() ->
+ ?identifier(set_singleton(?pid_qual)).
+
+-spec t_is_pid(erl_type()) -> boolean().
+
+t_is_pid(Type) ->
+ t_is_pid(Type, 'universe').
+
+-spec t_is_pid(erl_type(), opaques()) -> boolean().
+
+t_is_pid(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_pid1/1).
+
+is_pid1(?identifier(?any)) -> false;
+is_pid1(?identifier(Set)) -> set_is_singleton(?pid_qual, Set);
+is_pid1(_) -> false.
+
+%%------------------------------------
+
+-spec t_reference() -> erl_type().
+
+t_reference() ->
+ ?identifier(set_singleton(?reference_qual)).
+
+-spec t_is_reference(erl_type()) -> boolean().
+
+t_is_reference(Type) ->
+ t_is_reference(Type, 'universe').
+
+-spec t_is_reference(erl_type(), opaques()) -> boolean().
+
+t_is_reference(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_reference1/1).
+
+is_reference1(?identifier(?any)) -> false;
+is_reference1(?identifier(Set)) -> set_is_singleton(?reference_qual, Set);
+is_reference1(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Numbers are divided into floats, integers, chars and bytes.
+%%
+
+-spec t_number() -> erl_type().
+
+t_number() ->
+ ?number(?any, ?unknown_qual).
+
+-spec t_number(integer()) -> erl_type().
+
+t_number(X) when is_integer(X) ->
+ t_integer(X).
+
+-spec t_is_number(erl_type()) -> boolean().
+
+t_is_number(Type) ->
+ t_is_number(Type, 'universe').
+
+-spec t_is_number(erl_type(), opaques()) -> boolean().
+
+t_is_number(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_number/1).
+
+is_number(?number(_, _)) -> true;
+is_number(_) -> false.
+
+%% Currently, the type system collapses all floats to ?float and does
+%% not keep any information about their values. As a result, the list
+%% that this function returns contains only integers.
+
+-spec t_number_vals(erl_type()) -> 'unknown' | [integer(),...].
+
+t_number_vals(Type) ->
+ t_number_vals(Type, 'universe').
+
+-spec t_number_vals(erl_type(), opaques()) -> 'unknown' | [integer(),...].
+
+t_number_vals(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun number_vals/1).
+
+number_vals(?int_set(Set)) -> set_to_list(Set);
+number_vals(?number(_, _)) -> unknown;
+number_vals(?opaque(_)) -> unknown;
+number_vals(Other) ->
+ Inf = t_inf(Other, t_number()),
+ false = t_is_none(Inf), % sanity check
+ number_vals(Inf).
+
+%%------------------------------------
+
+-spec t_float() -> erl_type().
+
+t_float() ->
+ ?float.
+
+-spec t_is_float(erl_type()) -> boolean().
+
+t_is_float(Type) ->
+ t_is_float(Type, 'universe').
+
+-spec t_is_float(erl_type(), opaques()) -> boolean().
+
+t_is_float(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_float1/1).
+
+is_float1(?float) -> true;
+is_float1(_) -> false.
+
+%%------------------------------------
+
+-spec t_integer() -> erl_type().
+
+t_integer() ->
+ ?integer(?any).
+
+-spec t_integer(integer()) -> erl_type().
+
+t_integer(I) when is_integer(I) ->
+ ?int_set(set_singleton(I)).
+
+-spec t_integers([integer()]) -> erl_type().
+
+t_integers(List) when is_list(List) ->
+ t_sup([t_integer(I) || I <- List]).
+
+-spec t_is_integer(erl_type()) -> boolean().
+
+t_is_integer(Type) ->
+ t_is_integer(Type, 'universe').
+
+-spec t_is_integer(erl_type(), opaques()) -> boolean().
+
+t_is_integer(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_integer1/1).
+
+is_integer1(?integer(_)) -> true;
+is_integer1(_) -> false.
+
+%%------------------------------------
+
+-spec t_byte() -> erl_type().
+
+t_byte() ->
+ ?byte.
+
+-ifdef(DO_ERL_TYPES_TEST).
+-spec t_is_byte(erl_type()) -> boolean().
+
+t_is_byte(?int_range(neg_inf, _)) -> false;
+t_is_byte(?int_range(_, pos_inf)) -> false;
+t_is_byte(?int_range(From, To))
+ when is_integer(From), From >= 0, is_integer(To), To =< ?MAX_BYTE -> true;
+t_is_byte(?int_set(Set)) ->
+ (set_min(Set) >= 0) andalso (set_max(Set) =< ?MAX_BYTE);
+t_is_byte(_) -> false.
+-endif.
+
+%%------------------------------------
+
+-spec t_char() -> erl_type().
+
+t_char() ->
+ ?char.
+
+-spec t_is_char(erl_type()) -> boolean().
+
+t_is_char(?int_range(neg_inf, _)) -> false;
+t_is_char(?int_range(_, pos_inf)) -> false;
+t_is_char(?int_range(From, To))
+ when is_integer(From), From >= 0, is_integer(To), To =< ?MAX_CHAR -> true;
+t_is_char(?int_set(Set)) ->
+ (set_min(Set) >= 0) andalso (set_max(Set) =< ?MAX_CHAR);
+t_is_char(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Lists
+%%
+
+-spec t_cons() -> erl_type().
+
+t_cons() ->
+ ?nonempty_list(?any, ?any).
+
+%% Note that if the tail argument can be a list, we must collapse the
+%% content of the list to include both the content of the tail list
+%% and the head of the cons. If for example the tail argument is any()
+%% then there can be any list in the tail and the content of the
+%% returned list must be any().
+
+-spec t_cons(erl_type(), erl_type()) -> erl_type().
+
+t_cons(?none, _) -> ?none;
+t_cons(_, ?none) -> ?none;
+t_cons(?unit, _) -> ?none;
+t_cons(_, ?unit) -> ?none;
+t_cons(Hd, ?nil) ->
+ ?nonempty_list(Hd, ?nil);
+t_cons(Hd, ?list(Contents, Termination, _)) ->
+ ?nonempty_list(t_sup(Contents, Hd), Termination);
+t_cons(Hd, Tail) ->
+ case cons_tail(t_inf(Tail, t_maybe_improper_list())) of
+ ?list(Contents, Termination, _Size) ->
+ %% Collapse the list part of the termination but keep the
+ %% non-list part intact.
+ NewTermination = t_sup(t_subtract(Tail, t_maybe_improper_list()),
+ Termination),
+ ?nonempty_list(t_sup(Hd, Contents), NewTermination);
+ ?nil -> ?nonempty_list(Hd, Tail);
+ ?none -> ?nonempty_list(Hd, Tail);
+ ?unit -> ?none
+ end.
+
+cons_tail(Type) ->
+ do_opaque(Type, 'universe', fun(T) -> T end).
+
+-spec t_is_cons(erl_type()) -> boolean().
+
+t_is_cons(Type) ->
+ t_is_cons(Type, 'universe').
+
+-spec t_is_cons(erl_type(), opaques()) -> boolean().
+
+t_is_cons(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_cons/1).
+
+is_cons(?nonempty_list(_, _)) -> true;
+is_cons(_) -> false.
+
+-spec t_cons_hd(erl_type()) -> erl_type().
+
+t_cons_hd(Type) ->
+ t_cons_hd(Type, 'universe').
+
+-spec t_cons_hd(erl_type(), opaques()) -> erl_type().
+
+t_cons_hd(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun cons_hd/1).
+
+cons_hd(?nonempty_list(Contents, _Termination)) -> Contents.
+
+-spec t_cons_tl(erl_type()) -> erl_type().
+
+t_cons_tl(Type) ->
+ t_cons_tl(Type, 'universe').
+
+-spec t_cons_tl(erl_type(), opaques()) -> erl_type().
+
+t_cons_tl(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun cons_tl/1).
+
+cons_tl(?nonempty_list(_Contents, Termination) = T) ->
+ t_sup(Termination, T).
+
+-spec t_nil() -> erl_type().
+
+t_nil() ->
+ ?nil.
+
+-spec t_is_nil(erl_type()) -> boolean().
+
+t_is_nil(Type) ->
+ t_is_nil(Type, 'universe').
+
+-spec t_is_nil(erl_type(), opaques()) -> boolean().
+
+t_is_nil(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_nil/1).
+
+is_nil(?nil) -> true;
+is_nil(_) -> false.
+
+-spec t_list() -> erl_type().
+
+t_list() ->
+ ?list(?any, ?nil, ?unknown_qual).
+
+-spec t_list(erl_type()) -> erl_type().
+
+t_list(?none) -> ?none;
+t_list(?unit) -> ?none;
+t_list(Contents) ->
+ ?list(Contents, ?nil, ?unknown_qual).
+
+-spec t_list_elements(erl_type()) -> erl_type().
+
+t_list_elements(Type) ->
+ t_list_elements(Type, 'universe').
+
+-spec t_list_elements(erl_type(), opaques()) -> erl_type().
+
+t_list_elements(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun list_elements/1).
+
+list_elements(?list(Contents, _, _)) -> Contents;
+list_elements(?nil) -> ?none.
+
+-spec t_list_termination(erl_type(), opaques()) -> erl_type().
+
+t_list_termination(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun t_list_termination/1).
+
+-spec t_list_termination(erl_type()) -> erl_type().
+
+t_list_termination(?nil) -> ?nil;
+t_list_termination(?list(_, Term, _)) -> Term.
+
+-spec t_is_list(erl_type()) -> boolean().
+
+t_is_list(?list(_Contents, ?nil, _)) -> true;
+t_is_list(?nil) -> true;
+t_is_list(_) -> false.
+
+-spec t_nonempty_list() -> erl_type().
+
+t_nonempty_list() ->
+ t_cons(?any, ?nil).
+
+-spec t_nonempty_list(erl_type()) -> erl_type().
+
+t_nonempty_list(Type) ->
+ t_cons(Type, ?nil).
+
+-spec t_nonempty_string() -> erl_type().
+
+t_nonempty_string() ->
+ t_nonempty_list(t_char()).
+
+-spec t_string() -> erl_type().
+
+t_string() ->
+ t_list(t_char()).
+
+-spec t_is_string(erl_type()) -> boolean().
+
+t_is_string(X) ->
+ t_is_list(X) andalso t_is_char(t_list_elements(X)).
+
+-spec t_maybe_improper_list() -> erl_type().
+
+t_maybe_improper_list() ->
+ ?list(?any, ?any, ?unknown_qual).
+
+%% Should only be used if you know what you are doing. See t_cons/2
+-spec t_maybe_improper_list(erl_type(), erl_type()) -> erl_type().
+
+t_maybe_improper_list(_Content, ?unit) -> ?none;
+t_maybe_improper_list(?unit, _Termination) -> ?none;
+t_maybe_improper_list(Content, Termination) ->
+ %% Safety check: would be nice to have but does not work with remote types
+ %% true = t_is_subtype(t_nil(), Termination),
+ ?list(Content, Termination, ?unknown_qual).
+
+-spec t_is_maybe_improper_list(erl_type()) -> boolean().
+
+t_is_maybe_improper_list(Type) ->
+ t_is_maybe_improper_list(Type, 'universe').
+
+-spec t_is_maybe_improper_list(erl_type(), opaques()) -> boolean().
+
+t_is_maybe_improper_list(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_maybe_improper_list/1).
+
+is_maybe_improper_list(?list(_, _, _)) -> true;
+is_maybe_improper_list(?nil) -> true;
+is_maybe_improper_list(_) -> false.
+
+%% %% Should only be used if you know what you are doing. See t_cons/2
+%% -spec t_improper_list(erl_type(), erl_type()) -> erl_type().
+%%
+%% t_improper_list(?unit, _Termination) -> ?none;
+%% t_improper_list(_Content, ?unit) -> ?none;
+%% t_improper_list(Content, Termination) ->
+%% %% Safety check: would be nice to have but does not work with remote types
+%% %% false = t_is_subtype(t_nil(), Termination),
+%% ?list(Content, Termination, ?any).
+
+-spec lift_list_to_pos_empty(erl_type(), opaques()) -> erl_type().
+
+lift_list_to_pos_empty(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun lift_list_to_pos_empty/1).
+
+-spec lift_list_to_pos_empty(erl_type()) -> erl_type().
+
+lift_list_to_pos_empty(?nil) -> ?nil;
+lift_list_to_pos_empty(?list(Content, Termination, _)) ->
+ ?list(Content, Termination, ?unknown_qual).
+
+%%-----------------------------------------------------------------------------
+%% Maps
+%%
+%% Representation:
+%% ?map(Pairs, DefaultKey, DefaultValue)
+%%
+%% Pairs is a sorted dictionary of types with a mandatoriness tag on each pair
+%% (t_map_dict()). DefaultKey and DefaultValue are plain types.
+%%
+%% A map M belongs to this type iff
+%% For each pair {KT, mandatory, VT} in Pairs, there exists a pair {K, V} in M
+%% such that K \in KT and V \in VT.
+%% For each pair {KT, optional, VT} in Pairs, either there exists no key K in
+%% M s.t. K in KT, or there exists a pair {K, V} in M such that K \in KT and
+%% V \in VT.
+%% For each remaining pair {K, V} in M (where remaining means that there is no
+%% key KT in Pairs s.t. K \in KT), K \in DefaultKey and V \in DefaultValue.
+%%
+%% Invariants:
+%% * The keys in Pairs are singleton types.
+%% * The values of Pairs must not be unit, and may only be none if the
+%% mandatoriness tag is 'optional'.
+%% * Optional must contain no pair {K,V} s.t. K is a subtype of DefaultKey and
+%% V is equal to DefaultKey.
+%% * DefaultKey must be the empty type iff DefaultValue is the empty type.
+%% * DefaultKey must not be a singleton type.
+%% * For every key K in Pairs, DefaultKey - K must not be representable; i.e.
+%% t_subtract(DefaultKey, K) must return DefaultKey.
+%% * For every pair {K, 'optional', ?none} in Pairs, K must be a subtype of
+%% DefaultKey.
+%% * Pairs must be sorted and not contain any duplicate keys.
+%%
+%% These invariants ensure that equal map types are represented by equal terms.
+
+-define(mand, mandatory).
+-define(opt, optional).
+
+-type t_map_mandatoriness() :: ?mand | ?opt.
+-type t_map_pair() :: {erl_type(), t_map_mandatoriness(), erl_type()}.
+-type t_map_dict() :: [t_map_pair()].
+
+-spec t_map() -> erl_type().
+
+t_map() ->
+ t_map([], t_any(), t_any()).
+
+-spec t_map([{erl_type(), erl_type()}]) -> erl_type().
+
+t_map(L) ->
+ lists:foldl(fun t_map_put/2, t_map(), L).
+
+-spec t_map(t_map_dict(), erl_type(), erl_type()) -> erl_type().
+
+t_map(Pairs0, DefK0, DefV0) ->
+ DefK1 = lists:foldl(fun({K,_,_},Acc)->t_subtract(Acc,K)end, DefK0, Pairs0),
+ {DefK2, DefV1} =
+ case t_is_none_or_unit(DefK1) orelse t_is_none_or_unit(DefV0) of
+ true -> {?none, ?none};
+ false -> {DefK1, DefV0}
+ end,
+ {Pairs1, DefK, DefV}
+ = case is_singleton_type(DefK2) of
+ true -> {mapdict_insert({DefK2, ?opt, DefV1}, Pairs0), ?none, ?none};
+ false -> {Pairs0, DefK2, DefV1}
+ end,
+ Pairs = normalise_map_optionals(Pairs1, DefK, DefV),
+ %% Validate invariants of the map representation.
+ %% Since we needed to iterate over the arguments in order to normalise anyway,
+ %% we might as well save us some future pain and do this even without
+ %% define(DEBUG, true).
+ try
+ validate_map_elements(Pairs)
+ catch error:badarg -> error(badarg, [Pairs0,DefK0,DefV0]);
+ error:{badarg, E} -> error({badarg, E}, [Pairs0,DefK0,DefV0])
+ end,
+ ?map(Pairs, DefK, DefV).
+
+normalise_map_optionals([], _, _) -> [];
+normalise_map_optionals([E={K,?opt,?none}|T], DefK, DefV) ->
+ Diff = t_subtract(DefK, K),
+ case t_is_subtype(K, DefK) andalso DefK =:= Diff of
+ true -> [E|normalise_map_optionals(T, DefK, DefV)];
+ false -> normalise_map_optionals(T, Diff, DefV)
+ end;
+normalise_map_optionals([E={K,?opt,V}|T], DefK, DefV) ->
+ case t_is_equal(V, DefV) andalso t_is_subtype(K, DefK) of
+ true -> normalise_map_optionals(T, DefK, DefV);
+ false -> [E|normalise_map_optionals(T, DefK, DefV)]
+ end;
+normalise_map_optionals([E|T], DefK, DefV) ->
+ [E|normalise_map_optionals(T, DefK, DefV)].
+
+validate_map_elements([{_,?mand,?none}|_]) -> error({badarg, none_in_mand});
+validate_map_elements([{K1,_,_}|Rest=[{K2,_,_}|_]]) ->
+ case is_singleton_type(K1) andalso K1 < K2 of
+ false -> error(badarg);
+ true -> validate_map_elements(Rest)
+ end;
+validate_map_elements([{K,_,_}]) ->
+ case is_singleton_type(K) of
+ false -> error(badarg);
+ true -> true
+ end;
+validate_map_elements([]) -> true.
+
+-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) ->
+ do_opaque(Type, Opaques, fun is_map1/1).
+
+is_map1(?map(_, _, _)) -> true;
+is_map1(_) -> false.
+
+-spec t_map_entries(erl_type()) -> t_map_dict().
+
+t_map_entries(M) ->
+ t_map_entries(M, 'universe').
+
+-spec t_map_entries(erl_type(), opaques()) -> t_map_dict().
+
+t_map_entries(M, Opaques) ->
+ do_opaque(M, Opaques, fun map_entries/1).
+
+map_entries(?map(Pairs,_,_)) ->
+ Pairs.
+
+-spec t_map_def_key(erl_type()) -> erl_type().
+
+t_map_def_key(M) ->
+ t_map_def_key(M, 'universe').
+
+-spec t_map_def_key(erl_type(), opaques()) -> erl_type().
+
+t_map_def_key(M, Opaques) ->
+ do_opaque(M, Opaques, fun map_def_key/1).
+
+map_def_key(?map(_,DefK,_)) ->
+ DefK.
+
+-spec t_map_def_val(erl_type()) -> erl_type().
+
+t_map_def_val(M) ->
+ t_map_def_val(M, 'universe').
+
+-spec t_map_def_val(erl_type(), opaques()) -> erl_type().
+
+t_map_def_val(M, Opaques) ->
+ do_opaque(M, Opaques, fun map_def_val/1).
+
+map_def_val(?map(_,_,DefV)) ->
+ DefV.
+
+-spec mapdict_store(t_map_pair(), t_map_dict()) -> t_map_dict().
+
+mapdict_store(E={K,_,_}, [{K,_,_}|T]) -> [E|T];
+mapdict_store(E1={K1,_,_}, [E2={K2,_,_}|T]) when K1 > K2 ->
+ [E2|mapdict_store(E1, T)];
+mapdict_store(E={_,_,_}, T) -> [E|T].
+
+-spec mapdict_insert(t_map_pair(), t_map_dict()) -> t_map_dict().
+
+mapdict_insert(E={K,_,_}, D=[{K,_,_}|_]) -> error(badarg, [E, D]);
+mapdict_insert(E1={K1,_,_}, [E2={K2,_,_}|T]) when K1 > K2 ->
+ [E2|mapdict_insert(E1, T)];
+mapdict_insert(E={_,_,_}, T) -> [E|T].
+
+%% Merges the pairs of two maps together. Missing pairs become (?opt, DefV) or
+%% (?opt, ?none), depending on whether K \in DefK.
+-spec map_pairwise_merge(fun((erl_type(),
+ t_map_mandatoriness(), erl_type(),
+ t_map_mandatoriness(), erl_type())
+ -> t_map_pair() | false),
+ erl_type(), erl_type()) -> t_map_dict().
+map_pairwise_merge(F, ?map(APairs, ADefK, ADefV),
+ ?map(BPairs, BDefK, BDefV)) ->
+ map_pairwise_merge(F, APairs, ADefK, ADefV, BPairs, BDefK, BDefV).
+
+map_pairwise_merge(_, [], _, _, [], _, _) -> [];
+map_pairwise_merge(F, As0, ADefK, ADefV, Bs0, BDefK, BDefV) ->
+ {K1, AMNess1, AV1, As1, BMNess1, BV1, Bs1} =
+ case {As0, Bs0} of
+ {[{K,AMNess,AV}|As], [{K, BMNess,BV}|Bs]} ->
+ {K, AMNess, AV, As, BMNess, BV, Bs};
+ {[{K,AMNess,AV}|As], [{BK,_, _ }|_]=Bs} when K < BK ->
+ {K, AMNess, AV, As, ?opt, mapmerge_otherv(K, BDefK, BDefV), Bs};
+ {As, [{K, BMNess,BV}|Bs]} ->
+ {K, ?opt, mapmerge_otherv(K, ADefK, ADefV), As, BMNess, BV, Bs};
+ {[{K,AMNess,AV}|As], []=Bs} ->
+ {K, AMNess, AV, As, ?opt, mapmerge_otherv(K, BDefK, BDefV), Bs}
+ end,
+ MK = K1, %% Rename to make clear that we are matching below
+ case F(K1, AMNess1, AV1, BMNess1, BV1) of
+ false -> map_pairwise_merge(F,As1,ADefK,ADefV,Bs1,BDefK,BDefV);
+ {MK,_,_}=M -> [M|map_pairwise_merge(F,As1,ADefK,ADefV,Bs1,BDefK,BDefV)]
+ end.
+
+%% Folds over the pairs in two maps simultaneously in reverse key order. Missing
+%% pairs become (?opt, DefV) or (?opt, ?none), depending on whether K \in DefK.
+-spec map_pairwise_merge_foldr(fun((erl_type(),
+ t_map_mandatoriness(), erl_type(),
+ t_map_mandatoriness(), erl_type(),
+ Acc) -> Acc),
+ Acc, erl_type(), erl_type()) -> Acc.
+
+map_pairwise_merge_foldr(F, AccIn, ?map(APairs, ADefK, ADefV),
+ ?map(BPairs, BDefK, BDefV)) ->
+ map_pairwise_merge_foldr(F, AccIn, APairs, ADefK, ADefV, BPairs, BDefK, BDefV).
+
+map_pairwise_merge_foldr(_, Acc, [], _, _, [], _, _) -> Acc;
+map_pairwise_merge_foldr(F, AccIn, As0, ADefK, ADefV, Bs0, BDefK, BDefV) ->
+ {K1, AMNess1, AV1, As1, BMNess1, BV1, Bs1} =
+ case {As0, Bs0} of
+ {[{K,AMNess,AV}|As], [{K,BMNess,BV}|Bs]} ->
+ {K, AMNess, AV, As, BMNess, BV, Bs};
+ {[{K,AMNess,AV}|As], [{BK,_, _ }|_]=Bs} when K < BK ->
+ {K, AMNess, AV, As, ?opt, mapmerge_otherv(K, BDefK, BDefV), Bs};
+ {As, [{K,BMNess,BV}|Bs]} ->
+ {K, ?opt, mapmerge_otherv(K, ADefK, ADefV), As, BMNess, BV, Bs};
+ {[{K,AMNess,AV}|As], []=Bs} ->
+ {K, AMNess, AV, As, ?opt, mapmerge_otherv(K, BDefK, BDefV), Bs}
+ end,
+ F(K1, AMNess1, AV1, BMNess1, BV1,
+ map_pairwise_merge_foldr(F,AccIn,As1,ADefK,ADefV,Bs1,BDefK,BDefV)).
+
+%% By observing that a missing pair in a map is equivalent to an optional pair,
+%% with ?none or DefV value, depending on whether K \in DefK, we can simplify
+%% merging by denormalising the map pairs temporarily, removing all 'false'
+%% cases, at the cost of the creation of more tuples:
+mapmerge_otherv(K, ODefK, ODefV) ->
+ case t_inf(K, ODefK) of
+ ?none -> ?none;
+ _KOrOpaque -> ODefV
+ end.
+
+-spec t_map_put({erl_type(), erl_type()}, erl_type()) -> erl_type().
+
+t_map_put(KV, Map) ->
+ t_map_put(KV, Map, 'universe').
+
+-spec t_map_put({erl_type(), erl_type()}, erl_type(), opaques()) -> erl_type().
+
+t_map_put(KV, Map, Opaques) ->
+ do_opaque(Map, Opaques, fun(UM) -> map_put(KV, UM, Opaques) end).
+
+%% Key and Value are *not* unopaqued, but the map is
+map_put(_, ?none, _) -> ?none;
+map_put({Key, Value}, ?map(Pairs,DefK,DefV), Opaques) ->
+ case t_is_none_or_unit(Key) orelse t_is_none_or_unit(Value) of
+ true -> ?none;
+ false ->
+ case is_singleton_type(Key) of
+ true ->
+ t_map(mapdict_store({Key, ?mand, Value}, Pairs), DefK, DefV);
+ false ->
+ t_map([{K, MNess, case t_is_none(t_inf(K, Key, Opaques)) of
+ true -> V;
+ false -> t_sup(V, Value)
+ end} || {K, MNess, V} <- Pairs],
+ t_sup(DefK, Key),
+ t_sup(DefV, Value))
+ end
+ end.
+
+-spec t_map_update({erl_type(), erl_type()}, erl_type()) -> erl_type().
+
+t_map_update(KV, Map) ->
+ t_map_update(KV, Map, 'universe').
+
+-spec t_map_update({erl_type(), erl_type()}, erl_type(), opaques()) -> erl_type().
+
+t_map_update(_, ?none, _) -> ?none;
+t_map_update(KV={Key, _}, M, Opaques) ->
+ case t_is_subtype(t_atom('true'), t_map_is_key(Key, M, Opaques)) of
+ false -> ?none;
+ true -> t_map_put(KV, M, Opaques)
+ end.
+
+-spec t_map_get(erl_type(), erl_type()) -> erl_type().
+
+t_map_get(Key, Map) ->
+ t_map_get(Key, Map, 'universe').
+
+-spec t_map_get(erl_type(), erl_type(), opaques()) -> erl_type().
+
+t_map_get(Key, Map, Opaques) ->
+ do_opaque(Map, Opaques,
+ fun(UM) ->
+ do_opaque(Key, Opaques, fun(UK) -> map_get(UK, UM) end)
+ end).
+
+map_get(_, ?none) -> ?none;
+map_get(Key, ?map(Pairs, DefK, DefV)) ->
+ DefRes =
+ case t_do_overlap(DefK, Key) of
+ false -> t_none();
+ true -> DefV
+ end,
+ case is_singleton_type(Key) of
+ false ->
+ lists:foldl(fun({K, _, V}, Res) ->
+ case t_do_overlap(K, Key) of
+ false -> Res;
+ true -> t_sup(Res, V)
+ end
+ end, DefRes, Pairs);
+ true ->
+ case lists:keyfind(Key, 1, Pairs) of
+ false -> DefRes;
+ {_, _, ValType} -> ValType
+ end
+ end.
+
+-spec t_map_is_key(erl_type(), erl_type()) -> erl_type().
+
+t_map_is_key(Key, Map) ->
+ t_map_is_key(Key, Map, 'universe').
+
+-spec t_map_is_key(erl_type(), erl_type(), opaques()) -> erl_type().
+
+t_map_is_key(Key, Map, Opaques) ->
+ do_opaque(Map, Opaques,
+ fun(UM) ->
+ do_opaque(Key, Opaques, fun(UK) -> map_is_key(UK, UM) end)
+ end).
+
+map_is_key(_, ?none) -> ?none;
+map_is_key(Key, ?map(Pairs, DefK, _DefV)) ->
+ case is_singleton_type(Key) of
+ true ->
+ case lists:keyfind(Key, 1, Pairs) of
+ {Key, ?mand, _} -> t_atom(true);
+ {Key, ?opt, ?none} -> t_atom(false);
+ {Key, ?opt, _} -> t_boolean();
+ false ->
+ case t_do_overlap(DefK, Key) of
+ false -> t_atom(false);
+ true -> t_boolean()
+ end
+ end;
+ false ->
+ case t_do_overlap(DefK, Key)
+ orelse lists:any(fun({_,_,?none}) -> false;
+ ({K,_,_}) -> t_do_overlap(K, Key)
+ end, Pairs)
+ of
+ true -> t_boolean();
+ false -> t_atom(false)
+ end
+ end.
+
+%%-----------------------------------------------------------------------------
+%% Tuples
+%%
+
+-spec t_tuple() -> erl_type().
+
+t_tuple() ->
+ ?tuple(?any, ?any, ?any).
+
+-spec t_tuple(non_neg_integer() | [erl_type()]) -> erl_type().
+
+t_tuple(N) when is_integer(N), N > ?MAX_TUPLE_SIZE ->
+ t_tuple();
+t_tuple(N) when is_integer(N) ->
+ ?tuple(lists:duplicate(N, ?any), N, ?any);
+t_tuple(List) ->
+ case any_none_or_unit(List) of
+ true -> t_none();
+ false ->
+ Arity = length(List),
+ case get_tuple_tags(List) of
+ [Tag] -> ?tuple(List, Arity, Tag); %% Tag can also be ?any here
+ TagList ->
+ SortedTagList = lists:sort(TagList),
+ Tuples = [?tuple([T|tl(List)], Arity, T) || T <- SortedTagList],
+ ?tuple_set([{Arity, Tuples}])
+ end
+ end.
+
+-spec get_tuple_tags([erl_type()]) -> [erl_type(),...].
+
+get_tuple_tags([Tag|_]) ->
+ do_opaque(Tag, 'universe', fun tuple_tags/1);
+get_tuple_tags(_) -> [?any].
+
+tuple_tags(?atom(?any)) -> [?any];
+tuple_tags(?atom(Set)) ->
+ case set_size(Set) > ?TUPLE_TAG_LIMIT of
+ true -> [?any];
+ false -> [t_atom(A) || A <- set_to_list(Set)]
+ end;
+tuple_tags(_) -> [?any].
+
+%% to be used for a tuple with known types for its arguments (not ?any)
+-spec t_tuple_args(erl_type()) -> [erl_type()].
+
+t_tuple_args(Type) ->
+ t_tuple_args(Type, 'universe').
+
+%% to be used for a tuple with known types for its arguments (not ?any)
+-spec t_tuple_args(erl_type(), opaques()) -> [erl_type()].
+
+t_tuple_args(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun tuple_args/1).
+
+tuple_args(?tuple(Args, _, _)) when is_list(Args) -> Args.
+
+%% to be used for a tuple with a known size (not ?any)
+-spec t_tuple_size(erl_type()) -> non_neg_integer().
+
+t_tuple_size(Type) ->
+ t_tuple_size(Type, 'universe').
+
+%% to be used for a tuple with a known size (not ?any)
+-spec t_tuple_size(erl_type(), opaques()) -> non_neg_integer().
+
+t_tuple_size(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun tuple_size1/1).
+
+tuple_size1(?tuple(_, Size, _)) when is_integer(Size) -> Size.
+
+-spec t_tuple_sizes(erl_type()) -> 'unknown' | [non_neg_integer(),...].
+
+t_tuple_sizes(Type) ->
+ do_opaque(Type, 'universe', fun tuple_sizes/1).
+
+tuple_sizes(?tuple(?any, ?any, ?any)) -> unknown;
+tuple_sizes(?tuple(_, Size, _)) when is_integer(Size) -> [Size];
+tuple_sizes(?tuple_set(List)) -> [Size || {Size, _} <- List].
+
+-spec t_tuple_subtypes(erl_type(), opaques()) ->
+ 'unknown' | [erl_type(),...].
+
+t_tuple_subtypes(Type, Opaques) ->
+ Fun = fun(?tuple_set(List)) ->
+ t_tuple_subtypes_tuple_list(List, Opaques);
+ (?opaque(_)) -> unknown;
+ (T) -> t_tuple_subtypes(T)
+ end,
+ do_opaque(Type, Opaques, Fun).
+
+t_tuple_subtypes_tuple_list(List, Opaques) ->
+ lists:append([t_tuple_subtypes_list(Tuples, Opaques) ||
+ {_Size, Tuples} <- List]).
+
+t_tuple_subtypes_list(List, Opaques) ->
+ ListOfLists = [t_tuple_subtypes(E, Opaques) || E <- List, E =/= ?none],
+ lists:append([L || L <- ListOfLists, L =/= 'unknown']).
+
+-spec t_tuple_subtypes(erl_type()) -> 'unknown' | [erl_type(),...].
+
+%% XXX. Not the same as t_tuple_subtypes(T, 'universe')...
+t_tuple_subtypes(?tuple(?any, ?any, ?any)) -> unknown;
+t_tuple_subtypes(?tuple(_, _, _) = T) -> [T];
+t_tuple_subtypes(?tuple_set(List)) ->
+ lists:append([Tuples || {_Size, Tuples} <- List]).
+
+-spec t_is_tuple(erl_type()) -> boolean().
+
+t_is_tuple(Type) ->
+ t_is_tuple(Type, 'universe').
+
+-spec t_is_tuple(erl_type(), opaques()) -> boolean().
+
+t_is_tuple(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_tuple1/1).
+
+is_tuple1(?tuple(_, _, _)) -> true;
+is_tuple1(?tuple_set(_)) -> true;
+is_tuple1(_) -> false.
+
+%%-----------------------------------------------------------------------------
+%% Non-primitive types, including some handy syntactic sugar types
+%%
+
+-spec t_bitstrlist() -> erl_type().
+
+t_bitstrlist() ->
+ t_iolist(1, t_bitstr()).
+
+-spec t_arity() -> erl_type().
+
+t_arity() ->
+ t_from_range(0, 255). % was t_byte().
+
+-spec t_pos_integer() -> erl_type().
+
+t_pos_integer() ->
+ t_from_range(1, pos_inf).
+
+-spec t_non_neg_integer() -> erl_type().
+
+t_non_neg_integer() ->
+ t_from_range(0, pos_inf).
+
+-spec t_is_non_neg_integer(erl_type()) -> boolean().
+
+t_is_non_neg_integer(?integer(_) = T) ->
+ t_is_subtype(T, t_non_neg_integer());
+t_is_non_neg_integer(_) -> false.
+
+-spec t_neg_integer() -> erl_type().
+
+t_neg_integer() ->
+ t_from_range(neg_inf, -1).
+
+-spec t_fixnum() -> erl_type().
+
+t_fixnum() ->
+ t_integer(). % Gross over-approximation
+
+-spec t_pos_fixnum() -> erl_type().
+
+t_pos_fixnum() ->
+ t_pos_integer(). % Gross over-approximation
+
+-spec t_non_neg_fixnum() -> erl_type().
+
+t_non_neg_fixnum() ->
+ t_non_neg_integer(). % Gross over-approximation
+
+-spec t_mfa() -> erl_type().
+
+t_mfa() ->
+ t_tuple([t_atom(), t_atom(), t_arity()]).
+
+-spec t_module() -> erl_type().
+
+t_module() ->
+ t_atom().
+
+-spec t_node() -> erl_type().
+
+t_node() ->
+ t_atom().
+
+-spec t_iodata() -> erl_type().
+
+t_iodata() ->
+ t_sup(t_iolist(), t_binary()).
+
+-spec t_iolist() -> erl_type().
+
+t_iolist() ->
+ t_iolist(1, t_binary()).
+
+%% Added a second argument which currently is t_binary() | t_bitstr()
+-spec t_iolist(non_neg_integer(), erl_type()) -> erl_type().
+
+t_iolist(N, T) when N > 0 ->
+ t_maybe_improper_list(t_sup([t_iolist(N-1, T), T, t_byte()]),
+ t_sup(T, t_nil()));
+t_iolist(0, T) ->
+ t_maybe_improper_list(t_any(), t_sup(T, t_nil())).
+
+-spec t_timeout() -> erl_type().
+
+t_timeout() ->
+ t_sup(t_non_neg_integer(), t_atom('infinity')).
+
+%%------------------------------------
+
+%% ?none is allowed in products. A product of size 1 is not a product.
+
+-spec t_product([erl_type()]) -> erl_type().
+
+t_product([T]) -> T;
+t_product(Types) when is_list(Types) ->
+ ?product(Types).
+
+%% This function is intended to be the inverse of the one above.
+%% It should NOT be used with ?any, ?none or ?unit as input argument.
+
+-spec t_to_tlist(erl_type()) -> [erl_type()].
+
+t_to_tlist(?product(Types)) -> Types;
+t_to_tlist(T) when T =/= ?any orelse T =/= ?none orelse T =/= ?unit -> [T].
+
+%%------------------------------------
+
+-spec t_var(atom() | integer()) -> erl_type().
+
+t_var(Atom) when is_atom(Atom) -> ?var(Atom);
+t_var(Int) when is_integer(Int) -> ?var(Int).
+
+-spec t_is_var(erl_type()) -> boolean().
+
+t_is_var(?var(_)) -> true;
+t_is_var(_) -> false.
+
+-spec t_var_name(erl_type()) -> atom() | integer().
+
+t_var_name(?var(Id)) -> Id.
+
+-spec t_has_var(erl_type()) -> boolean().
+
+t_has_var(?var(_)) -> true;
+t_has_var(?function(Domain, Range)) ->
+ t_has_var(Domain) orelse t_has_var(Range);
+t_has_var(?list(Contents, Termination, _)) ->
+ t_has_var(Contents) orelse t_has_var(Termination);
+t_has_var(?product(Types)) -> t_has_var_list(Types);
+t_has_var(?tuple(?any, ?any, ?any)) -> false;
+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(_, DefK, _)= Map) ->
+ t_has_var_list(map_all_values(Map)) orelse
+ t_has_var(DefK);
+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)]);
+t_has_var(?union(List)) ->
+ t_has_var_list(List);
+t_has_var(_) -> false.
+
+-spec t_has_var_list([erl_type()]) -> boolean().
+
+t_has_var_list([T|Ts]) ->
+ t_has_var(T) orelse t_has_var_list(Ts);
+t_has_var_list([]) -> false.
+
+-spec t_collect_vars(erl_type()) -> [erl_type()].
+
+t_collect_vars(T) ->
+ t_collect_vars(T, []).
+
+-spec t_collect_vars(erl_type(), [erl_type()]) -> [erl_type()].
+
+t_collect_vars(?var(_) = Var, Acc) ->
+ ordsets:add_element(Var, Acc);
+t_collect_vars(?function(Domain, Range), Acc) ->
+ ordsets:union(t_collect_vars(Domain, Acc), t_collect_vars(Range, []));
+t_collect_vars(?list(Contents, Termination, _), Acc) ->
+ ordsets:union(t_collect_vars(Contents, Acc), t_collect_vars(Termination, []));
+t_collect_vars(?product(Types), Acc) ->
+ t_collect_vars_list(Types, Acc);
+t_collect_vars(?tuple(?any, ?any, ?any), Acc) ->
+ Acc;
+t_collect_vars(?tuple(Types, _, _), Acc) ->
+ t_collect_vars_list(Types, Acc);
+t_collect_vars(?tuple_set(_) = TS, Acc) ->
+ t_collect_vars_list(t_tuple_subtypes(TS), Acc);
+t_collect_vars(?map(_, DefK, _) = Map, Acc0) ->
+ Acc = t_collect_vars_list(map_all_values(Map), Acc0),
+ t_collect_vars(DefK, Acc);
+t_collect_vars(?opaque(Set), Acc) ->
+ %% Assume variables in 'args' are also present i 'struct'
+ 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.
+
+%%=============================================================================
+%%
+%% Type construction from Erlang terms.
+%%
+%%=============================================================================
+
+%%-----------------------------------------------------------------------------
+%% Make a type from a term. No type depth is enforced.
+%%
+
+-spec t_from_term(term()) -> erl_type().
+
+t_from_term([H|T]) -> t_cons(t_from_term(H), t_from_term(T));
+t_from_term([]) -> t_nil();
+t_from_term(T) when is_atom(T) -> t_atom(T);
+t_from_term(T) when is_bitstring(T) -> t_bitstr(0, erlang:bit_size(T));
+t_from_term(T) when is_float(T) -> t_float();
+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) ->
+ Pairs = [{t_from_term(K), ?mand, t_from_term(V)}
+ || {K, V} <- maps:to_list(T)],
+ {Stons, Rest} = lists:partition(fun({K,_,_}) -> is_singleton_type(K) end,
+ Pairs),
+ {DefK, DefV}
+ = lists:foldl(fun({K,_,V},{AK,AV}) -> {t_sup(K,AK), t_sup(V,AV)} end,
+ {t_none(), t_none()}, Rest),
+ t_map(lists:keysort(1, Stons), DefK, DefV);
+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();
+t_from_term(T) when is_tuple(T) ->
+ t_tuple([t_from_term(E) || E <- tuple_to_list(T)]).
+
+%%-----------------------------------------------------------------------------
+%% Integer types from a range.
+%%-----------------------------------------------------------------------------
+
+%%-define(USE_UNSAFE_RANGES, true).
+
+-spec t_from_range(rng_elem(), rng_elem()) -> erl_type().
+
+-ifdef(USE_UNSAFE_RANGES).
+
+t_from_range(X, Y) ->
+ t_from_range_unsafe(X, Y).
+
+-else.
+
+t_from_range(neg_inf, pos_inf) -> t_integer();
+t_from_range(neg_inf, Y) when is_integer(Y), Y < 0 -> ?integer_neg;
+t_from_range(neg_inf, Y) when is_integer(Y), Y >= 0 -> t_integer();
+t_from_range(X, pos_inf) when is_integer(X), X >= 1 -> ?integer_pos;
+t_from_range(X, pos_inf) when is_integer(X), X >= 0 -> ?integer_non_neg;
+t_from_range(X, pos_inf) when is_integer(X), X < 0 -> t_integer();
+t_from_range(X, Y) when is_integer(X), is_integer(Y), X > Y -> t_none();
+t_from_range(X, Y) when is_integer(X), is_integer(Y) ->
+ case ((Y - X) < ?SET_LIMIT) of
+ true -> t_integers(lists:seq(X, Y));
+ false ->
+ case X >= 0 of
+ false ->
+ if Y < 0 -> ?integer_neg;
+ true -> t_integer()
+ end;
+ true ->
+ if Y =< ?MAX_BYTE, X >= 1 -> ?int_range(1, ?MAX_BYTE);
+ Y =< ?MAX_BYTE -> t_byte();
+ Y =< ?MAX_CHAR, X >= 1 -> ?int_range(1, ?MAX_CHAR);
+ Y =< ?MAX_CHAR -> t_char();
+ X >= 1 -> ?integer_pos;
+ X >= 0 -> ?integer_non_neg
+ end
+ end
+ end;
+t_from_range(pos_inf, neg_inf) -> t_none().
+
+-endif.
+
+-spec t_from_range_unsafe(rng_elem(), rng_elem()) -> erl_type().
+
+t_from_range_unsafe(neg_inf, pos_inf) -> t_integer();
+t_from_range_unsafe(neg_inf, Y) -> ?int_range(neg_inf, Y);
+t_from_range_unsafe(X, pos_inf) -> ?int_range(X, pos_inf);
+t_from_range_unsafe(X, Y) when is_integer(X), is_integer(Y), X =< Y ->
+ if (Y - X) < ?SET_LIMIT -> t_integers(lists:seq(X, Y));
+ true -> ?int_range(X, Y)
+ end;
+t_from_range_unsafe(X, Y) when is_integer(X), is_integer(Y) -> t_none();
+t_from_range_unsafe(pos_inf, neg_inf) -> t_none().
+
+-spec t_is_fixnum(erl_type()) -> boolean().
+
+t_is_fixnum(?int_range(neg_inf, _)) -> false;
+t_is_fixnum(?int_range(_, pos_inf)) -> false;
+t_is_fixnum(?int_range(From, To)) ->
+ is_fixnum(From) andalso is_fixnum(To);
+t_is_fixnum(?int_set(Set)) ->
+ is_fixnum(set_min(Set)) andalso is_fixnum(set_max(Set));
+t_is_fixnum(_) -> false.
+
+-spec is_fixnum(integer()) -> boolean().
+
+is_fixnum(N) when is_integer(N) ->
+ Bits = ?BITS,
+ (N =< ((1 bsl (Bits - 1)) - 1)) andalso (N >= -(1 bsl (Bits - 1))).
+
+infinity_geq(pos_inf, _) -> true;
+infinity_geq(_, pos_inf) -> false;
+infinity_geq(_, neg_inf) -> true;
+infinity_geq(neg_inf, _) -> false;
+infinity_geq(A, B) -> A >= B.
+
+-spec t_is_bitwidth(erl_type()) -> boolean().
+
+t_is_bitwidth(?int_range(neg_inf, _)) -> false;
+t_is_bitwidth(?int_range(_, pos_inf)) -> false;
+t_is_bitwidth(?int_range(From, To)) ->
+ infinity_geq(From, 0) andalso infinity_geq(?BITS, To);
+t_is_bitwidth(?int_set(Set)) ->
+ infinity_geq(set_min(Set), 0) andalso infinity_geq(?BITS, set_max(Set));
+t_is_bitwidth(_) -> false.
+
+-spec number_min(erl_type()) -> rng_elem().
+
+number_min(Type) ->
+ number_min(Type, 'universe').
+
+-spec number_min(erl_type(), opaques()) -> rng_elem().
+
+number_min(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun number_min2/1).
+
+number_min2(?int_range(From, _)) -> From;
+number_min2(?int_set(Set)) -> set_min(Set);
+number_min2(?number(?any, _Tag)) -> neg_inf.
+
+-spec number_max(erl_type()) -> rng_elem().
+
+number_max(Type) ->
+ number_max(Type, 'universe').
+
+-spec number_max(erl_type(), opaques()) -> rng_elem().
+
+number_max(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun number_max2/1).
+
+number_max2(?int_range(_, To)) -> To;
+number_max2(?int_set(Set)) -> set_max(Set);
+number_max2(?number(?any, _Tag)) -> pos_inf.
+
+%% -spec int_range(rgn_elem(), rng_elem()) -> erl_type().
+%%
+%% int_range(neg_inf, pos_inf) -> t_integer();
+%% int_range(neg_inf, To) -> ?int_range(neg_inf, To);
+%% int_range(From, pos_inf) -> ?int_range(From, pos_inf);
+%% int_range(From, To) when From =< To -> t_from_range(From, To);
+%% int_range(From, To) when To < From -> ?none.
+
+in_range(_, ?int_range(neg_inf, pos_inf)) -> true;
+in_range(X, ?int_range(From, pos_inf)) -> X >= From;
+in_range(X, ?int_range(neg_inf, To)) -> X =< To;
+in_range(X, ?int_range(From, To)) -> (X >= From) andalso (X =< To).
+
+-spec min(rng_elem(), rng_elem()) -> rng_elem().
+
+min(neg_inf, _) -> neg_inf;
+min(_, neg_inf) -> neg_inf;
+min(pos_inf, Y) -> Y;
+min(X, pos_inf) -> X;
+min(X, Y) when X =< Y -> X;
+min(_, Y) -> Y.
+
+-spec max(rng_elem(), rng_elem()) -> rng_elem().
+
+max(neg_inf, Y) -> Y;
+max(X, neg_inf) -> X;
+max(pos_inf, _) -> pos_inf;
+max(_, pos_inf) -> pos_inf;
+max(X, Y) when X =< Y -> Y;
+max(X, _) -> X.
+
+expand_range_from_set(Range = ?int_range(From, To), Set) ->
+ Min = min(set_min(Set), From),
+ Max = max(set_max(Set), To),
+ if From =:= Min, To =:= Max -> Range;
+ true -> t_from_range(Min, Max)
+ end.
+
+%%=============================================================================
+%%
+%% Lattice operations
+%%
+%%=============================================================================
+
+%%-----------------------------------------------------------------------------
+%% Supremum
+%%
+
+-spec t_sup([erl_type()]) -> erl_type().
+
+t_sup([]) -> ?none;
+t_sup(Ts) ->
+ case lists:any(fun is_any/1, Ts) of
+ true -> ?any;
+ false ->
+ t_sup1(Ts, [])
+ end.
+
+t_sup1([H1, H2|T], L) ->
+ t_sup1(T, [t_sup(H1, H2)|L]);
+t_sup1([T], []) -> subst_all_vars_to_any(T);
+t_sup1(Ts, L) ->
+ t_sup1(Ts++L, []).
+
+-spec t_sup(erl_type(), erl_type()) -> erl_type().
+
+t_sup(?any, _) -> ?any;
+t_sup(_, ?any) -> ?any;
+t_sup(?none, T) -> T;
+t_sup(T, ?none) -> T;
+t_sup(?unit, T) -> T;
+t_sup(T, ?unit) -> T;
+t_sup(T, T) -> subst_all_vars_to_any(T);
+t_sup(?var(_), _) -> ?any;
+t_sup(_, ?var(_)) -> ?any;
+t_sup(?atom(Set1), ?atom(Set2)) ->
+ ?atom(set_union(Set1, Set2));
+t_sup(?bitstr(U1, B1), ?bitstr(U2, B2)) ->
+ t_bitstr(gcd(gcd(U1, U2), abs(B1-B2)), lists:min([B1, B2]));
+t_sup(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ %% The domain is either a product or any.
+ ?function(t_sup(Domain1, Domain2), t_sup(Range1, Range2));
+t_sup(?identifier(Set1), ?identifier(Set2)) ->
+ ?identifier(set_union(Set1, Set2));
+t_sup(?opaque(Set1), ?opaque(Set2)) ->
+ sup_opaque(set_to_list(ordsets:union(Set1, Set2)));
+%%Disallow unions with opaque types
+%%t_sup(T1=?opaque(_,_,_), T2) ->
+%% io:format("Debug: t_sup executed with args ~w and ~w~n",[T1, T2]), ?none;
+%%t_sup(T1, T2=?opaque(_,_,_)) ->
+%% io:format("Debug: t_sup executed with args ~w and ~w~n",[T1, T2]), ?none;
+t_sup(?matchstate(Pres1, Slots1), ?matchstate(Pres2, Slots2)) ->
+ ?matchstate(t_sup(Pres1, Pres2), t_sup(Slots1, Slots2));
+t_sup(?nil, ?nil) -> ?nil;
+t_sup(?nil, ?list(Contents, Termination, _)) ->
+ ?list(Contents, t_sup(?nil, Termination), ?unknown_qual);
+t_sup(?list(Contents, Termination, _), ?nil) ->
+ ?list(Contents, t_sup(?nil, Termination), ?unknown_qual);
+t_sup(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
+ NewSize =
+ case {Size1, Size2} of
+ {?unknown_qual, ?unknown_qual} -> ?unknown_qual;
+ {?unknown_qual, ?nonempty_qual} -> ?unknown_qual;
+ {?nonempty_qual, ?unknown_qual} -> ?unknown_qual;
+ {?nonempty_qual, ?nonempty_qual} -> ?nonempty_qual
+ end,
+ NewContents = t_sup(Contents1, Contents2),
+ NewTermination = t_sup(Termination1, Termination2),
+ TmpList = t_cons(NewContents, NewTermination),
+ case NewSize of
+ ?nonempty_qual -> TmpList;
+ ?unknown_qual ->
+ ?list(FinalContents, FinalTermination, _) = TmpList,
+ ?list(FinalContents, FinalTermination, ?unknown_qual)
+ end;
+t_sup(?number(_, _), ?number(?any, ?unknown_qual) = T) -> T;
+t_sup(?number(?any, ?unknown_qual) = T, ?number(_, _)) -> T;
+t_sup(?float, ?float) -> ?float;
+t_sup(?float, ?integer(_)) -> t_number();
+t_sup(?integer(_), ?float) -> t_number();
+t_sup(?integer(?any) = T, ?integer(_)) -> T;
+t_sup(?integer(_), ?integer(?any) = T) -> T;
+t_sup(?int_set(Set1), ?int_set(Set2)) ->
+ case set_union(Set1, Set2) of
+ ?any ->
+ t_from_range(min(set_min(Set1), set_min(Set2)),
+ max(set_max(Set1), set_max(Set2)));
+ Set -> ?int_set(Set)
+ end;
+t_sup(?int_range(From1, To1), ?int_range(From2, To2)) ->
+ t_from_range(min(From1, From2), max(To1, To2));
+t_sup(Range = ?int_range(_, _), ?int_set(Set)) ->
+ expand_range_from_set(Range, Set);
+t_sup(?int_set(Set), Range = ?int_range(_, _)) ->
+ expand_range_from_set(Range, Set);
+t_sup(?product(Types1), ?product(Types2)) ->
+ L1 = length(Types1),
+ L2 = length(Types2),
+ if L1 =:= L2 -> ?product(t_sup_lists(Types1, Types2));
+ true -> ?any
+ end;
+t_sup(?product(_), _) ->
+ ?any;
+t_sup(_, ?product(_)) ->
+ ?any;
+t_sup(?tuple(?any, ?any, ?any) = T, ?tuple(_, _, _)) -> T;
+t_sup(?tuple(_, _, _), ?tuple(?any, ?any, ?any) = T) -> T;
+t_sup(?tuple(?any, ?any, ?any) = T, ?tuple_set(_)) -> T;
+t_sup(?tuple_set(_), ?tuple(?any, ?any, ?any) = T) -> T;
+t_sup(?tuple(Elements1, Arity, Tag1) = T1,
+ ?tuple(Elements2, Arity, Tag2) = T2) ->
+ if Tag1 =:= Tag2 -> t_tuple(t_sup_lists(Elements1, Elements2));
+ Tag1 =:= ?any -> t_tuple(t_sup_lists(Elements1, Elements2));
+ Tag2 =:= ?any -> t_tuple(t_sup_lists(Elements1, Elements2));
+ Tag1 < Tag2 -> ?tuple_set([{Arity, [T1, T2]}]);
+ Tag1 > Tag2 -> ?tuple_set([{Arity, [T2, T1]}])
+ end;
+t_sup(?tuple(_, Arity1, _) = T1, ?tuple(_, Arity2, _) = T2) ->
+ sup_tuple_sets([{Arity1, [T1]}], [{Arity2, [T2]}]);
+t_sup(?tuple_set(List1), ?tuple_set(List2)) ->
+ sup_tuple_sets(List1, List2);
+t_sup(?tuple_set(List1), T2 = ?tuple(_, Arity, _)) ->
+ sup_tuple_sets(List1, [{Arity, [T2]}]);
+t_sup(?tuple(_, Arity, _) = T1, ?tuple_set(List2)) ->
+ sup_tuple_sets([{Arity, [T1]}], List2);
+t_sup(?map(_, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B) ->
+ Pairs =
+ map_pairwise_merge(
+ fun(K, MNess, V1, MNess, V2) -> {K, MNess, t_sup(V1, V2)};
+ (K, _, V1, _, V2) -> {K, ?opt, t_sup(V1, V2)}
+ end, A, B),
+ t_map(Pairs, t_sup(ADefK, BDefK), t_sup(ADefV, BDefV));
+t_sup(T1, T2) ->
+ ?union(U1) = force_union(T1),
+ ?union(U2) = force_union(T2),
+ sup_union(U1, U2).
+
+sup_opaque([]) -> ?none;
+sup_opaque(List) ->
+ L = sup_opaq(List),
+ ?opaque(ordsets:from_list(L)).
+
+sup_opaq(L0) ->
+ L1 = [{{Mod,Name,Args}, T} ||
+ #opaque{mod = Mod, name = Name, args = Args}=T <- L0],
+ F = family(L1),
+ [supl(Ts) || {_, Ts} <- F].
+
+supl([O]) -> O;
+supl(Ts) -> supl(Ts, t_none()).
+
+supl([#opaque{struct = S}=O|L], S0) ->
+ S1 = t_sup(S, S0),
+ case L =:= [] of
+ true -> O#opaque{struct = S1};
+ false -> supl(L, S1)
+ end.
+
+-spec t_sup_lists([erl_type()], [erl_type()]) -> [erl_type()].
+
+t_sup_lists([T1|Left1], [T2|Left2]) ->
+ [t_sup(T1, T2)|t_sup_lists(Left1, Left2)];
+t_sup_lists([], []) ->
+ [].
+
+sup_tuple_sets(L1, L2) ->
+ TotalArities = ordsets:union([Arity || {Arity, _} <- L1],
+ [Arity || {Arity, _} <- L2]),
+ if length(TotalArities) > ?TUPLE_ARITY_LIMIT -> t_tuple();
+ true ->
+ case sup_tuple_sets(L1, L2, []) of
+ [{_Arity, [OneTuple = ?tuple(_, _, _)]}] -> OneTuple;
+ List -> ?tuple_set(List)
+ end
+ end.
+
+sup_tuple_sets([{Arity, Tuples1}|Left1], [{Arity, Tuples2}|Left2], Acc) ->
+ NewAcc = [{Arity, sup_tuples_in_set(Tuples1, Tuples2)}|Acc],
+ sup_tuple_sets(Left1, Left2, NewAcc);
+sup_tuple_sets([{Arity1, _} = T1|Left1] = L1,
+ [{Arity2, _} = T2|Left2] = L2, Acc) ->
+ if Arity1 < Arity2 -> sup_tuple_sets(Left1, L2, [T1|Acc]);
+ Arity1 > Arity2 -> sup_tuple_sets(L1, Left2, [T2|Acc])
+ end;
+sup_tuple_sets([], L2, Acc) -> lists:reverse(Acc, L2);
+sup_tuple_sets(L1, [], Acc) -> lists:reverse(Acc, L1).
+
+sup_tuples_in_set([?tuple(_, _, ?any) = T], L) ->
+ [t_tuple(sup_tuple_elements([T|L]))];
+sup_tuples_in_set(L, [?tuple(_, _, ?any) = T]) ->
+ [t_tuple(sup_tuple_elements([T|L]))];
+sup_tuples_in_set(L1, L2) ->
+ FoldFun = fun(?tuple(_, _, Tag), AccTag) -> t_sup(Tag, AccTag) end,
+ TotalTag0 = lists:foldl(FoldFun, ?none, L1),
+ TotalTag = lists:foldl(FoldFun, TotalTag0, L2),
+ case TotalTag of
+ ?atom(?any) ->
+ %% We will reach the set limit. Widen now.
+ [t_tuple(sup_tuple_elements(L1 ++ L2))];
+ ?atom(Set) ->
+ case set_size(Set) > ?TUPLE_TAG_LIMIT of
+ true ->
+ %% We will reach the set limit. Widen now.
+ [t_tuple(sup_tuple_elements(L1 ++ L2))];
+ false ->
+ %% We can go on and build the tuple set.
+ sup_tuples_in_set(L1, L2, [])
+ end
+ end.
+
+sup_tuple_elements([?tuple(Elements, _, _)|L]) ->
+ lists:foldl(fun (?tuple(Es, _, _), Acc) -> t_sup_lists(Es, Acc) end,
+ Elements, L).
+
+sup_tuples_in_set([?tuple(Elements1, Arity, Tag1) = T1|Left1] = L1,
+ [?tuple(Elements2, Arity, Tag2) = T2|Left2] = L2, Acc) ->
+ if
+ Tag1 < Tag2 -> sup_tuples_in_set(Left1, L2, [T1|Acc]);
+ Tag1 > Tag2 -> sup_tuples_in_set(L1, Left2, [T2|Acc]);
+ Tag2 =:= Tag2 -> NewElements = t_sup_lists(Elements1, Elements2),
+ NewAcc = [?tuple(NewElements, Arity, Tag1)|Acc],
+ sup_tuples_in_set(Left1, Left2, NewAcc)
+ end;
+sup_tuples_in_set([], L2, Acc) -> lists:reverse(Acc, L2);
+sup_tuples_in_set(L1, [], Acc) -> lists:reverse(Acc, L1).
+
+sup_union(U1, U2) ->
+ sup_union(U1, U2, 0, []).
+
+sup_union([?none|Left1], [?none|Left2], N, Acc) ->
+ sup_union(Left1, Left2, N, [?none|Acc]);
+sup_union([T1|Left1], [T2|Left2], N, Acc) ->
+ sup_union(Left1, Left2, N+1, [t_sup(T1, T2)|Acc]);
+sup_union([], [], N, Acc) ->
+ if N =:= 0 -> ?none;
+ N =:= 1 ->
+ [Type] = [T || T <- Acc, T =/= ?none],
+ Type;
+ N =:= length(Acc) -> ?any;
+ true -> ?union(lists:reverse(Acc))
+ end.
+
+force_union(T = ?atom(_)) -> ?atom_union(T);
+force_union(T = ?bitstr(_, _)) -> ?bitstr_union(T);
+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 = ?opaque(_)) -> ?opaque_union(T);
+force_union(T = ?map(_,_,_)) -> ?map_union(T);
+force_union(T = ?tuple(_, _, _)) -> ?tuple_union(T);
+force_union(T = ?tuple_set(_)) -> ?tuple_union(T);
+force_union(T = ?matchstate(_, _)) -> ?matchstate_union(T);
+force_union(T = ?union(_)) -> T.
+
+%%-----------------------------------------------------------------------------
+%% An attempt to write the inverse operation of t_sup/1 -- XXX: INCOMPLETE !!
+%%
+
+-spec t_elements(erl_type()) -> [erl_type()].
+
+t_elements(?none) -> [];
+t_elements(?unit) -> [];
+t_elements(?any = T) -> [T];
+t_elements(?nil = T) -> [T];
+t_elements(?atom(?any) = T) -> [T];
+t_elements(?atom(Atoms)) ->
+ [t_atom(A) || A <- Atoms];
+t_elements(?bitstr(_, _) = T) -> [T];
+t_elements(?function(_, _) = T) -> [T];
+t_elements(?identifier(?any) = T) -> [T];
+t_elements(?identifier(IDs)) ->
+ [?identifier([T]) || T <- IDs];
+t_elements(?list(_, _, _) = T) -> [T];
+t_elements(?number(_, _) = T) ->
+ case T of
+ ?number(?any, ?unknown_qual) ->
+ [?float, ?integer(?any)];
+ ?float -> [T];
+ ?integer(?any) -> [T];
+ ?int_range(_, _) -> [T];
+ ?int_set(Set) ->
+ [t_integer(I) || I <- Set]
+ end;
+t_elements(?opaque(_) = T) ->
+ do_elements(T);
+t_elements(?map(_,_,_) = T) -> [T];
+t_elements(?tuple(_, _, _) = T) -> [T];
+t_elements(?tuple_set(_) = TS) ->
+ case t_tuple_subtypes(TS) of
+ unknown -> [];
+ Elems -> Elems
+ end;
+t_elements(?union(_) = T) ->
+ do_elements(T);
+t_elements(?var(_)) -> [?any]. %% yes, vars exist -- what else to do here?
+%% t_elements(T) ->
+%% io:format("T_ELEMENTS => ~p\n", [T]).
+
+do_elements(Type0) ->
+ case do_opaque(Type0, 'universe', fun(T) -> T end) of
+ ?union(List) -> lists:append([t_elements(T) || T <- List]);
+ Type -> t_elements(Type)
+ end.
+
+%%-----------------------------------------------------------------------------
+%% Infimum
+%%
+
+-spec t_inf([erl_type()]) -> erl_type().
+
+t_inf([H1, H2|T]) ->
+ case t_inf(H1, H2) of
+ ?none -> ?none;
+ NewH -> t_inf([NewH|T])
+ end;
+t_inf([H]) -> H;
+t_inf([]) -> ?none.
+
+-spec t_inf(erl_type(), erl_type()) -> erl_type().
+
+t_inf(T1, T2) ->
+ t_inf(T1, T2, 'universe').
+
+%% 'match' should be used from t_find_unknown_opaque() only
+-type t_inf_opaques() :: opaques() | {'match', [erl_type() | 'universe']}.
+
+-spec t_inf(erl_type(), erl_type(), t_inf_opaques()) -> erl_type().
+
+t_inf(?var(_), ?var(_), _Opaques) -> ?any;
+t_inf(?var(_), T, _Opaques) -> subst_all_vars_to_any(T);
+t_inf(T, ?var(_), _Opaques) -> subst_all_vars_to_any(T);
+t_inf(?any, T, _Opaques) -> subst_all_vars_to_any(T);
+t_inf(T, ?any, _Opaques) -> subst_all_vars_to_any(T);
+t_inf(?none, _, _Opaques) -> ?none;
+t_inf(_, ?none, _Opaques) -> ?none;
+t_inf(?unit, _, _Opaques) -> ?unit; % ?unit cases should appear below ?none
+t_inf(_, ?unit, _Opaques) -> ?unit;
+t_inf(T, T, _Opaques) -> subst_all_vars_to_any(T);
+t_inf(?atom(Set1), ?atom(Set2), _) ->
+ case set_intersection(Set1, Set2) of
+ ?none -> ?none;
+ NewSet -> ?atom(NewSet)
+ end;
+t_inf(?bitstr(U1, B1), ?bitstr(0, B2), _Opaques) ->
+ if B2 >= B1 andalso (B2-B1) rem U1 =:= 0 -> t_bitstr(0, B2);
+ true -> ?none
+ end;
+t_inf(?bitstr(0, B1), ?bitstr(U2, B2), _Opaques) ->
+ if B1 >= B2 andalso (B1-B2) rem U2 =:= 0 -> t_bitstr(0, B1);
+ true -> ?none
+ end;
+t_inf(?bitstr(U1, B1), ?bitstr(U1, B1), _Opaques) ->
+ t_bitstr(U1, B1);
+t_inf(?bitstr(U1, B1), ?bitstr(U2, B2), _Opaques) when U2 > U1 ->
+ inf_bitstr(U2, B2, U1, B1);
+t_inf(?bitstr(U1, B1), ?bitstr(U2, B2), _Opaques) ->
+ inf_bitstr(U1, B1, U2, B2);
+t_inf(?function(Domain1, Range1), ?function(Domain2, Range2), Opaques) ->
+ case t_inf(Domain1, Domain2, Opaques) of
+ ?none -> ?none;
+ Domain -> ?function(Domain, t_inf(Range1, Range2, Opaques))
+ end;
+t_inf(?identifier(Set1), ?identifier(Set2), _Opaques) ->
+ case set_intersection(Set1, Set2) of
+ ?none -> ?none;
+ Set -> ?identifier(Set)
+ end;
+t_inf(?map(_, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B, _Opaques) ->
+ %% Because it simplifies the anonymous function, we allow Pairs to temporarily
+ %% contain mandatory pairs with none values, since all such cases should
+ %% result in a none result.
+ Pairs =
+ map_pairwise_merge(
+ %% For optional keys in both maps, when the infinimum is none, we have
+ %% essentially concluded that K must not be a key in the map.
+ fun(K, ?opt, V1, ?opt, V2) -> {K, ?opt, t_inf(V1, V2)};
+ %% When a key is optional in one map, but mandatory in another, it
+ %% becomes mandatory in the infinumum
+ (K, _, V1, _, V2) -> {K, ?mand, t_inf(V1, V2)}
+ end, A, B),
+ %% If the infinimum of any mandatory values is ?none, the entire map infinimum
+ %% is ?none.
+ case lists:any(fun({_,?mand,?none})->true; ({_,_,_}) -> false end, Pairs) of
+ true -> t_none();
+ false -> t_map(Pairs, t_inf(ADefK, BDefK), t_inf(ADefV, BDefV))
+ end;
+t_inf(?matchstate(Pres1, Slots1), ?matchstate(Pres2, Slots2), _Opaques) ->
+ ?matchstate(t_inf(Pres1, Pres2), t_inf(Slots1, Slots2));
+t_inf(?nil, ?nil, _Opaques) -> ?nil;
+t_inf(?nil, ?nonempty_list(_, _), _Opaques) ->
+ ?none;
+t_inf(?nonempty_list(_, _), ?nil, _Opaques) ->
+ ?none;
+t_inf(?nil, ?list(_Contents, Termination, _), Opaques) ->
+ t_inf(?nil, t_unopaque(Termination), Opaques);
+t_inf(?list(_Contents, Termination, _), ?nil, Opaques) ->
+ t_inf(?nil, t_unopaque(Termination), Opaques);
+t_inf(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2), Opaques) ->
+ case t_inf(Termination1, Termination2, Opaques) of
+ ?none -> ?none;
+ Termination ->
+ case t_inf(Contents1, Contents2, Opaques) of
+ ?none ->
+ %% If none of the lists are nonempty, then the infimum is nil.
+ case (Size1 =:= ?unknown_qual) andalso (Size2 =:= ?unknown_qual) of
+ true -> t_nil();
+ false -> ?none
+ end;
+ Contents ->
+ Size =
+ case {Size1, Size2} of
+ {?unknown_qual, ?unknown_qual} -> ?unknown_qual;
+ {?unknown_qual, ?nonempty_qual} -> ?nonempty_qual;
+ {?nonempty_qual, ?unknown_qual} -> ?nonempty_qual;
+ {?nonempty_qual, ?nonempty_qual} -> ?nonempty_qual
+ end,
+ ?list(Contents, Termination, Size)
+ end
+ end;
+t_inf(?number(_, _) = T1, ?number(_, _) = T2, _Opaques) ->
+ case {T1, T2} of
+ {T, T} -> T;
+ {_, ?number(?any, ?unknown_qual)} -> T1;
+ {?number(?any, ?unknown_qual), _} -> T2;
+ {?float, ?integer(_)} -> ?none;
+ {?integer(_), ?float} -> ?none;
+ {?integer(?any), ?integer(_)} -> T2;
+ {?integer(_), ?integer(?any)} -> T1;
+ {?int_set(Set1), ?int_set(Set2)} ->
+ case set_intersection(Set1, Set2) of
+ ?none -> ?none;
+ Set -> ?int_set(Set)
+ end;
+ {?int_range(From1, To1), ?int_range(From2, To2)} ->
+ t_from_range(max(From1, From2), min(To1, To2));
+ {Range = ?int_range(_, _), ?int_set(Set)} ->
+ %% io:format("t_inf range, set args ~p ~p ~n", [T1, T2]),
+ Ans2 =
+ case set_filter(fun(X) -> in_range(X, Range) end, Set) of
+ ?none -> ?none;
+ NewSet -> ?int_set(NewSet)
+ end,
+ %% io:format("Ans2 ~p ~n", [Ans2]),
+ Ans2;
+ {?int_set(Set), ?int_range(_, _) = Range} ->
+ case set_filter(fun(X) -> in_range(X, Range) end, Set) of
+ ?none -> ?none;
+ NewSet -> ?int_set(NewSet)
+ end
+ end;
+t_inf(?product(Types1), ?product(Types2), Opaques) ->
+ L1 = length(Types1),
+ L2 = length(Types2),
+ if L1 =:= L2 -> ?product(t_inf_lists(Types1, Types2, Opaques));
+ true -> ?none
+ end;
+t_inf(?product(_), _, _Opaques) ->
+ ?none;
+t_inf(_, ?product(_), _Opaques) ->
+ ?none;
+t_inf(?tuple(?any, ?any, ?any), ?tuple(_, _, _) = T, _Opaques) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple(_, _, _) = T, ?tuple(?any, ?any, ?any), _Opaques) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple(?any, ?any, ?any), ?tuple_set(_) = T, _Opaques) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple_set(_) = T, ?tuple(?any, ?any, ?any), _Opaques) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple(Elements1, Arity, _Tag1), ?tuple(Elements2, Arity, _Tag2), Opaques) ->
+ case t_inf_lists_strict(Elements1, Elements2, Opaques) of
+ bottom -> ?none;
+ NewElements -> t_tuple(NewElements)
+ end;
+t_inf(?tuple_set(List1), ?tuple_set(List2), Opaques) ->
+ inf_tuple_sets(List1, List2, Opaques);
+t_inf(?tuple_set(List), ?tuple(_, Arity, _) = T, Opaques) ->
+ inf_tuple_sets(List, [{Arity, [T]}], Opaques);
+t_inf(?tuple(_, Arity, _) = T, ?tuple_set(List), Opaques) ->
+ inf_tuple_sets(List, [{Arity, [T]}], Opaques);
+%% be careful: here and in the next clause T can be ?opaque
+t_inf(?union(U1), T, Opaques) ->
+ ?union(U2) = force_union(T),
+ inf_union(U1, U2, Opaques);
+t_inf(T, ?union(U2), Opaques) ->
+ ?union(U1) = force_union(T),
+ inf_union(U1, U2, Opaques);
+t_inf(?opaque(Set1), ?opaque(Set2), Opaques) ->
+ inf_opaque(Set1, Set2, Opaques);
+t_inf(?opaque(_) = T1, T2, Opaques) ->
+ inf_opaque1(T2, T1, 1, Opaques);
+t_inf(T1, ?opaque(_) = T2, Opaques) ->
+ inf_opaque1(T1, T2, 2, Opaques);
+%% and as a result, the cases for ?opaque should appear *after* ?union
+t_inf(#c{}, #c{}, _) ->
+ ?none.
+
+inf_opaque1(T1, ?opaque(Set2)=T2, Pos, Opaques) ->
+ case Opaques =:= 'universe' orelse inf_is_opaque_type(T2, Pos, Opaques) of
+ false -> ?none;
+ true ->
+ List2 = set_to_list(Set2),
+ case inf_collect(T1, List2, Opaques, []) of
+ [] -> ?none;
+ OpL -> ?opaque(ordsets:from_list(OpL))
+ end
+ end.
+
+inf_is_opaque_type(T, Pos, {match, Opaques}) ->
+ is_opaque_type(T, Opaques) orelse throw({pos, [Pos]});
+inf_is_opaque_type(T, _Pos, Opaques) ->
+ is_opaque_type(T, Opaques).
+
+inf_collect(T1, [T2|List2], Opaques, OpL) ->
+ #opaque{struct = S2} = T2,
+ case t_inf(T1, S2, Opaques) of
+ ?none -> inf_collect(T1, List2, Opaques, OpL);
+ Inf ->
+ Op = T2#opaque{struct = Inf},
+ inf_collect(T1, List2, Opaques, [Op|OpL])
+ end;
+inf_collect(_T1, [], _Opaques, OpL) ->
+ OpL.
+
+combine(S, T1, T2) ->
+ #opaque{mod = Mod1, name = Name1, args = Args1} = T1,
+ #opaque{mod = Mod2, name = Name2, args = Args2} = T2,
+ Comb1 = comb(Mod1, Name1, Args1, S, T1),
+ case is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}) of
+ true -> Comb1;
+ false -> Comb1 ++ comb(Mod2, Name2, Args2, S, T2)
+ end.
+
+comb(Mod, Name, Args, S, T) ->
+ case can_combine_opaque_names(Mod, Name, Args, S) of
+ true ->
+ ?opaque(Set) = S,
+ Set;
+ false ->
+ [T#opaque{struct = S}]
+ end.
+
+can_combine_opaque_names(Mod1, Name1, Args1,
+ ?opaque([#opaque{mod = Mod2, name = Name2, args = Args2}])) ->
+ is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2});
+can_combine_opaque_names(_, _, _, _) -> false.
+
+%% Combining two lists this way can be very time consuming...
+%% Note: two parameterized opaque types are not the same if their
+%% actual parameters differ
+inf_opaque(Set1, Set2, Opaques) ->
+ List1 = inf_look_up(Set1, Opaques),
+ List2 = inf_look_up(Set2, Opaques),
+ List0 = [combine(Inf, T1, T2) ||
+ {Is1, ModNameArgs1, T1} <- List1,
+ {Is2, ModNameArgs2, T2} <- List2,
+ not t_is_none(Inf = inf_opaque_types(Is1, ModNameArgs1, T1,
+ Is2, ModNameArgs2, T2,
+ Opaques))],
+ List = lists:sort(lists:append(List0)),
+ sup_opaque(List).
+
+%% Optimization: do just one lookup.
+inf_look_up(Set, Opaques) ->
+ [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques),
+ {M, N, Args}, T} ||
+ #opaque{mod = M, name = N, args = Args} = T <- set_to_list(Set)].
+
+inf_is_opaque_type2(T, {match, Opaques}) ->
+ is_opaque_type2(T, Opaques);
+inf_is_opaque_type2(T, Opaques) ->
+ is_opaque_type2(T, Opaques).
+
+inf_opaque_types(IsOpaque1, ModNameArgs1, T1,
+ IsOpaque2, ModNameArgs2, T2, Opaques) ->
+ #opaque{struct = S1}=T1,
+ #opaque{struct = S2}=T2,
+ case
+ Opaques =:= 'universe' orelse
+ is_compat_opaque_names(ModNameArgs1, ModNameArgs2)
+ of
+ true -> t_inf(S1, S2, Opaques);
+ false ->
+ case {IsOpaque1, IsOpaque2} of
+ {true, true} -> t_inf(S1, S2, Opaques);
+ {true, false} -> t_inf(S1, ?opaque(set_singleton(T2)), Opaques);
+ {false, true} -> t_inf(?opaque(set_singleton(T1)), S2, Opaques);
+ {false, false} when element(1, Opaques) =:= match ->
+ throw({pos, [1, 2]});
+ {false, false} -> t_none()
+ end
+ end.
+
+is_compat_opaque_names(ModNameArgs, ModNameArgs) -> true;
+is_compat_opaque_names({Mod,Name,Args1}, {Mod,Name,Args2}) ->
+ is_compat_args(Args1, Args2);
+is_compat_opaque_names(_, _) -> false.
+
+is_compat_args([A1|Args1], [A2|Args2]) ->
+ is_compat_arg(A1, A2) andalso is_compat_args(Args1, Args2);
+is_compat_args([], []) -> true;
+is_compat_args(_, _) -> false.
+
+is_compat_arg(A1, A2) ->
+ is_specialization(A1, A2) orelse is_specialization(A2, A1).
+
+-spec is_specialization(erl_type(), erl_type()) -> boolean().
+
+%% Returns true if the first argument is a specialization of the
+%% second argument in the sense that every type is a specialization of
+%% any(). For example, {_,_} is a specialization of any(), but not of
+%% tuple(). Does not handle variables, but any() and unions (sort of).
+
+is_specialization(T, T) -> true;
+is_specialization(_, ?any) -> true;
+is_specialization(?any, _) -> false;
+is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_specialization(Domain1, Domain2) andalso
+ is_specialization(Range1, Range2));
+is_specialization(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
+ (Size1 =:= Size2 andalso
+ is_specialization(Contents1, Contents2) andalso
+ is_specialization(Termination1, Termination2));
+is_specialization(?product(Types1), ?product(Types2)) ->
+ specialization_list(Types1, Types2);
+is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_specialization(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ specialization_list(Elements1, Elements2);
+is_specialization(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ specialization_list(sup_tuple_elements(List), Elements2);
+is_specialization(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ specialization_list(Elements1, sup_tuple_elements(List));
+is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ try
+ specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
+ [sup_tuple_elements(T) || {_Arity, T} <- List2])
+ catch _:_ -> false
+ end;
+is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
+ case specialization_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_specialization(Type1, Type2);
+ no -> specialization_list(List1, List2)
+ end;
+is_specialization(?union(List), T2) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(Type, T2);
+ no -> false
+ end;
+is_specialization(T1, ?union(List)) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(T1, Type);
+ no -> false
+ end;
+is_specialization(?opaque(_) = T1, T2) ->
+ is_specialization(t_opaque_structure(T1), T2);
+is_specialization(T1, ?opaque(_) = T2) ->
+ is_specialization(T1, t_opaque_structure(T2));
+is_specialization(?var(_), _) -> exit(error);
+is_specialization(_, ?var(_)) -> exit(error);
+is_specialization(?none, _) -> false;
+is_specialization(_, ?none) -> false;
+is_specialization(?unit, _) -> false;
+is_specialization(_, ?unit) -> false;
+is_specialization(#c{}, #c{}) -> false.
+
+specialization_list_list(LL1, LL2) ->
+ length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2).
+
+specialization_list_list1([], []) -> true;
+specialization_list_list1([L1|LL1], [L2|LL2]) ->
+ specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2).
+
+specialization_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
+
+specialization_list1([], []) -> true;
+specialization_list1([T1|L1], [T2|L2]) ->
+ is_specialization(T1, T2) andalso specialization_list1(L1, L2).
+
+specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+ case {unify_union(List1), unify_union(List2)} of
+ {{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
+ {{yes, Type1}, no} -> {yes, Type1, T2};
+ {no, {yes, Type2}} -> {yes, T1, Type2};
+ {no, no} -> no
+ end.
+
+-spec t_inf_lists([erl_type()], [erl_type()]) -> [erl_type()].
+
+t_inf_lists(L1, L2) ->
+ t_inf_lists(L1, L2, 'universe').
+
+-spec t_inf_lists([erl_type()], [erl_type()], t_inf_opaques()) -> [erl_type()].
+
+t_inf_lists(L1, L2, Opaques) ->
+ t_inf_lists(L1, L2, [], Opaques).
+
+-spec t_inf_lists([erl_type()], [erl_type()], [erl_type()], [erl_type()]) -> [erl_type()].
+
+t_inf_lists([T1|Left1], [T2|Left2], Acc, Opaques) ->
+ t_inf_lists(Left1, Left2, [t_inf(T1, T2, Opaques)|Acc], Opaques);
+t_inf_lists([], [], Acc, _Opaques) ->
+ lists:reverse(Acc).
+
+%% Infimum of lists with strictness.
+%% If any element is the ?none type, the value 'bottom' is returned.
+
+-spec t_inf_lists_strict([erl_type()], [erl_type()], [erl_type()]) -> 'bottom' | [erl_type()].
+
+t_inf_lists_strict(L1, L2, Opaques) ->
+ t_inf_lists_strict(L1, L2, [], Opaques).
+
+-spec t_inf_lists_strict([erl_type()], [erl_type()], [erl_type()], [erl_type()]) -> 'bottom' | [erl_type()].
+
+t_inf_lists_strict([T1|Left1], [T2|Left2], Acc, Opaques) ->
+ case t_inf(T1, T2, Opaques) of
+ ?none -> bottom;
+ T -> t_inf_lists_strict(Left1, Left2, [T|Acc], Opaques)
+ end;
+t_inf_lists_strict([], [], Acc, _Opaques) ->
+ lists:reverse(Acc).
+
+inf_tuple_sets(L1, L2, Opaques) ->
+ case inf_tuple_sets(L1, L2, [], Opaques) of
+ [] -> ?none;
+ [{_Arity, [?tuple(_, _, _) = OneTuple]}] -> OneTuple;
+ List -> ?tuple_set(List)
+ end.
+
+inf_tuple_sets([{Arity, Tuples1}|Ts1], [{Arity, Tuples2}|Ts2], Acc, Opaques) ->
+ case inf_tuples_in_sets(Tuples1, Tuples2, Opaques) of
+ [] -> inf_tuple_sets(Ts1, Ts2, Acc, Opaques);
+ [?tuple_set([{Arity, NewTuples}])] ->
+ inf_tuple_sets(Ts1, Ts2, [{Arity, NewTuples}|Acc], Opaques);
+ NewTuples -> inf_tuple_sets(Ts1, Ts2, [{Arity, NewTuples}|Acc], Opaques)
+ end;
+inf_tuple_sets([{Arity1, _}|Ts1] = L1, [{Arity2, _}|Ts2] = L2, Acc, Opaques) ->
+ if Arity1 < Arity2 -> inf_tuple_sets(Ts1, L2, Acc, Opaques);
+ Arity1 > Arity2 -> inf_tuple_sets(L1, Ts2, Acc, Opaques)
+ end;
+inf_tuple_sets([], _, Acc, _Opaques) -> lists:reverse(Acc);
+inf_tuple_sets(_, [], Acc, _Opaques) -> lists:reverse(Acc).
+
+inf_tuples_in_sets([?tuple(Elements1, _, ?any)], L2, Opaques) ->
+ NewList = [t_inf_lists_strict(Elements1, Elements2, Opaques)
+ || ?tuple(Elements2, _, _) <- L2],
+ [t_tuple(Es) || Es <- NewList, Es =/= bottom];
+inf_tuples_in_sets(L1, [?tuple(Elements2, _, ?any)], Opaques) ->
+ NewList = [t_inf_lists_strict(Elements1, Elements2, Opaques)
+ || ?tuple(Elements1, _, _) <- L1],
+ [t_tuple(Es) || Es <- NewList, Es =/= bottom];
+inf_tuples_in_sets(L1, L2, Opaques) ->
+ inf_tuples_in_sets2(L1, L2, [], Opaques).
+
+inf_tuples_in_sets2([?tuple(Elements1, Arity, Tag)|Ts1],
+ [?tuple(Elements2, Arity, Tag)|Ts2], Acc, Opaques) ->
+ case t_inf_lists_strict(Elements1, Elements2, Opaques) of
+ bottom -> inf_tuples_in_sets2(Ts1, Ts2, Acc, Opaques);
+ NewElements ->
+ inf_tuples_in_sets2(Ts1, Ts2, [?tuple(NewElements, Arity, Tag)|Acc],
+ Opaques)
+ end;
+inf_tuples_in_sets2([?tuple(_, _, Tag1)|Ts1] = L1,
+ [?tuple(_, _, Tag2)|Ts2] = L2, Acc, Opaques) ->
+ if Tag1 < Tag2 -> inf_tuples_in_sets2(Ts1, L2, Acc, Opaques);
+ Tag1 > Tag2 -> inf_tuples_in_sets2(L1, Ts2, Acc, Opaques)
+ end;
+inf_tuples_in_sets2([], _, Acc, _Opaques) -> lists:reverse(Acc);
+inf_tuples_in_sets2(_, [], Acc, _Opaques) -> lists:reverse(Acc).
+
+inf_union(U1, U2, Opaques) ->
+ OpaqueFun =
+ fun(Union1, Union2, InfFun) ->
+ [_,_,_,_,_,_,_,_,Opaque,_] = Union1,
+ [A,B,F,I,L,N,T,M,_,Map] = Union2,
+ List = [A,B,F,I,L,N,T,M,Map],
+ inf_union_collect(List, Opaque, InfFun, [], [])
+ end,
+ {O1, ThrowList1} =
+ OpaqueFun(U1, U2, fun(E, Opaque) -> t_inf(Opaque, E, Opaques) end),
+ {O2, ThrowList2}
+ = OpaqueFun(U2, U1, fun(E, Opaque) -> t_inf(E, Opaque, Opaques) end),
+ {Union, ThrowList3} = inf_union(U1, U2, 0, [], [], Opaques),
+ ThrowList = lists:merge3(ThrowList1, ThrowList2, ThrowList3),
+ case t_sup([O1, O2, Union]) of
+ ?none when ThrowList =/= [] -> throw({pos, lists:usort(ThrowList)});
+ Sup -> Sup
+ end.
+
+inf_union_collect([], _Opaque, _InfFun, InfList, ThrowList) ->
+ {t_sup(InfList), lists:usort(ThrowList)};
+inf_union_collect([?none|L], Opaque, InfFun, InfList, ThrowList) ->
+ inf_union_collect(L, Opaque, InfFun, [?none|InfList], ThrowList);
+inf_union_collect([E|L], Opaque, InfFun, InfList, ThrowList) ->
+ try InfFun(E, Opaque)of
+ Inf ->
+ inf_union_collect(L, Opaque, InfFun, [Inf|InfList], ThrowList)
+ catch throw:{pos, Ns} ->
+ inf_union_collect(L, Opaque, InfFun, InfList, Ns ++ ThrowList)
+ end.
+
+inf_union([?none|Left1], [?none|Left2], N, Acc, ThrowList, Opaques) ->
+ inf_union(Left1, Left2, N, [?none|Acc], ThrowList, Opaques);
+inf_union([T1|Left1], [T2|Left2], N, Acc, ThrowList, Opaques) ->
+ try t_inf(T1, T2, Opaques) of
+ ?none -> inf_union(Left1, Left2, N, [?none|Acc], ThrowList, Opaques);
+ T -> inf_union(Left1, Left2, N+1, [T|Acc], ThrowList, Opaques)
+ catch throw:{pos, Ns} ->
+ inf_union(Left1, Left2, N, [?none|Acc], Ns ++ ThrowList, Opaques)
+ end;
+inf_union([], [], N, Acc, ThrowList, _Opaques) ->
+ if N =:= 0 -> {?none, ThrowList};
+ N =:= 1 ->
+ [Type] = [T || T <- Acc, T =/= ?none],
+ {Type, ThrowList};
+ N >= 2 -> {?union(lists:reverse(Acc)), ThrowList}
+ end.
+
+inf_bitstr(U1, B1, U2, B2) ->
+ GCD = gcd(U1, U2),
+ case (B2-B1) rem GCD of
+ 0 ->
+ U = (U1*U2) div GCD,
+ B = findfirst(0, 0, U1, B1, U2, B2),
+ t_bitstr(U, B);
+ _ ->
+ ?none
+ end.
+
+findfirst(N1, N2, U1, B1, U2, B2) ->
+ Val1 = U1*N1+B1,
+ Val2 = U2*N2+B2,
+ if Val1 =:= Val2 ->
+ Val1;
+ Val1 > Val2 ->
+ findfirst(N1, N2+1, U1, B1, U2, B2);
+ Val1 < Val2 ->
+ findfirst(N1+1, N2, U1, B1, U2, B2)
+ end.
+
+%%-----------------------------------------------------------------------------
+%% Substitution of variables
+%%
+
+-type subst_table() :: #{any() => erl_type()}.
+
+-spec t_subst(erl_type(), subst_table()) -> erl_type().
+
+t_subst(T, Map) ->
+ case t_has_var(T) of
+ true -> t_subst_aux(T, Map);
+ false -> T
+ end.
+
+-spec subst_all_vars_to_any(erl_type()) -> erl_type().
+
+subst_all_vars_to_any(T) ->
+ t_subst(T, #{}).
+
+t_subst_aux(?var(Id), Map) ->
+ case maps:find(Id, Map) of
+ error -> ?any;
+ {ok, Type} -> Type
+ end;
+t_subst_aux(?list(Contents, Termination, Size), Map) ->
+ case t_subst_aux(Contents, Map) of
+ ?none -> ?none;
+ NewContents ->
+ %% Be careful here to make the termination collapse if necessary.
+ case t_subst_aux(Termination, Map) of
+ ?nil -> ?list(NewContents, ?nil, Size);
+ ?any -> ?list(NewContents, ?any, Size);
+ Other ->
+ ?list(NewContents2, NewTermination, _) = t_cons(NewContents, Other),
+ ?list(NewContents2, NewTermination, Size)
+ end
+ end;
+t_subst_aux(?function(Domain, Range), Map) ->
+ ?function(t_subst_aux(Domain, Map), t_subst_aux(Range, Map));
+t_subst_aux(?product(Types), Map) ->
+ ?product([t_subst_aux(T, Map) || T <- Types]);
+t_subst_aux(?tuple(?any, ?any, ?any) = T, _Map) ->
+ T;
+t_subst_aux(?tuple(Elements, _Arity, _Tag), Map) ->
+ t_tuple([t_subst_aux(E, Map) || E <- Elements]);
+t_subst_aux(?tuple_set(_) = TS, Map) ->
+ t_sup([t_subst_aux(T, Map) || T <- t_tuple_subtypes(TS)]);
+t_subst_aux(?map(Pairs, DefK, DefV), Map) ->
+ t_map([{K, MNess, t_subst_aux(V, Map)} || {K, MNess, V} <- Pairs],
+ t_subst_aux(DefK, Map), t_subst_aux(DefV, Map));
+t_subst_aux(?opaque(Es), Map) ->
+ List = [Opaque#opaque{args = [t_subst_aux(Arg, Map) || Arg <- Args],
+ struct = t_subst_aux(S, Map)} ||
+ Opaque = #opaque{args = Args, struct = S} <- set_to_list(Es)],
+ ?opaque(ordsets:from_list(List));
+t_subst_aux(?union(List), Map) ->
+ ?union([t_subst_aux(E, Map) || E <- List]);
+t_subst_aux(T, _Map) ->
+ T.
+
+%%-----------------------------------------------------------------------------
+%% Unification
+%%
+
+-type t_unify_ret() :: {erl_type(), [{_, erl_type()}]}.
+
+-spec t_unify(erl_type(), erl_type()) -> t_unify_ret().
+
+t_unify(T1, T2) ->
+ {T, VarMap} = t_unify(T1, T2, #{}),
+ {t_subst(T, VarMap), lists:keysort(1, maps:to_list(VarMap))}.
+
+t_unify(?var(Id) = T, ?var(Id), VarMap) ->
+ {T, VarMap};
+t_unify(?var(Id1) = T, ?var(Id2), VarMap) ->
+ case maps:find(Id1, VarMap) of
+ error ->
+ case maps:find(Id2, VarMap) of
+ error -> {T, VarMap#{Id2 => T}};
+ {ok, Type} -> t_unify(T, Type, VarMap)
+ end;
+ {ok, Type1} ->
+ case maps:find(Id2, VarMap) of
+ error -> {Type1, VarMap#{Id2 => T}};
+ {ok, Type2} -> t_unify(Type1, Type2, VarMap)
+ end
+ end;
+t_unify(?var(Id), Type, VarMap) ->
+ case maps:find(Id, VarMap) of
+ error -> {Type, VarMap#{Id => Type}};
+ {ok, VarType} -> t_unify(VarType, Type, VarMap)
+ end;
+t_unify(Type, ?var(Id), VarMap) ->
+ case maps:find(Id, VarMap) of
+ error -> {Type, VarMap#{Id => Type}};
+ {ok, VarType} -> t_unify(VarType, Type, VarMap)
+ end;
+t_unify(?function(Domain1, Range1), ?function(Domain2, Range2), VarMap) ->
+ {Domain, VarMap1} = t_unify(Domain1, Domain2, VarMap),
+ {Range, VarMap2} = t_unify(Range1, Range2, VarMap1),
+ {?function(Domain, Range), VarMap2};
+t_unify(?list(Contents1, Termination1, Size),
+ ?list(Contents2, Termination2, Size), VarMap) ->
+ {Contents, VarMap1} = t_unify(Contents1, Contents2, VarMap),
+ {Termination, VarMap2} = t_unify(Termination1, Termination2, VarMap1),
+ {?list(Contents, Termination, Size), VarMap2};
+t_unify(?product(Types1), ?product(Types2), VarMap) ->
+ {Types, VarMap1} = unify_lists(Types1, Types2, VarMap),
+ {?product(Types), VarMap1};
+t_unify(?tuple(?any, ?any, ?any) = T, ?tuple(?any, ?any, ?any), VarMap) ->
+ {T, VarMap};
+t_unify(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _), VarMap) when Arity =/= ?any ->
+ {NewElements, VarMap1} = unify_lists(Elements1, Elements2, VarMap),
+ {t_tuple(NewElements), VarMap1};
+t_unify(?tuple_set([{Arity, _}]) = T1,
+ ?tuple(_, Arity, _) = T2, VarMap) when Arity =/= ?any ->
+ unify_tuple_set_and_tuple1(T1, T2, VarMap);
+t_unify(?tuple(_, Arity, _) = T1,
+ ?tuple_set([{Arity, _}]) = T2, VarMap) when Arity =/= ?any ->
+ unify_tuple_set_and_tuple2(T1, T2, VarMap);
+t_unify(?tuple_set(List1) = T1, ?tuple_set(List2) = T2, VarMap) ->
+ try
+ unify_lists(lists:append([T || {_Arity, T} <- List1]),
+ lists:append([T || {_Arity, T} <- List2]), VarMap)
+ of
+ {Tuples, NewVarMap} -> {t_sup(Tuples), NewVarMap}
+ catch _:_ -> throw({mismatch, T1, T2})
+ end;
+t_unify(?map(_, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B, VarMap0) ->
+ {DefK, VarMap1} = t_unify(ADefK, BDefK, VarMap0),
+ {DefV, VarMap2} = t_unify(ADefV, BDefV, VarMap1),
+ {Pairs, VarMap} =
+ map_pairwise_merge_foldr(
+ fun(K, MNess, V1, MNess, V2, {Pairs0, VarMap3}) ->
+ %% We know that the keys unify and do not contain variables, or they
+ %% would not be singletons
+ %% TODO: Should V=?none (known missing keys) be handled special?
+ {V, VarMap4} = t_unify(V1, V2, VarMap3),
+ {[{K,MNess,V}|Pairs0], VarMap4};
+ (K, _, V1, _, V2, {Pairs0, VarMap3}) ->
+ %% One mandatory and one optional; what should be done in this case?
+ {V, VarMap4} = t_unify(V1, V2, VarMap3),
+ {[{K,?mand,V}|Pairs0], VarMap4}
+ end, {[], VarMap2}, A, B),
+ {t_map(Pairs, DefK, DefV), VarMap};
+t_unify(?opaque(_) = T1, ?opaque(_) = T2, VarMap) ->
+ t_unify(t_opaque_structure(T1), t_opaque_structure(T2), VarMap);
+t_unify(T1, ?opaque(_) = T2, VarMap) ->
+ t_unify(T1, t_opaque_structure(T2), VarMap);
+t_unify(?opaque(_) = T1, T2, VarMap) ->
+ t_unify(t_opaque_structure(T1), T2, VarMap);
+t_unify(T, T, VarMap) ->
+ {T, VarMap};
+t_unify(?union(_)=T1, ?union(_)=T2, VarMap) ->
+ {Type1, Type2} = unify_union2(T1, T2),
+ t_unify(Type1, Type2, VarMap);
+t_unify(?union(_)=T1, T2, VarMap) ->
+ t_unify(unify_union1(T1, T1, T2), T2, VarMap);
+t_unify(T1, ?union(_)=T2, VarMap) ->
+ t_unify(T1, unify_union1(T2, T1, T2), VarMap);
+t_unify(T1, T2, _) ->
+ throw({mismatch, T1, T2}).
+
+unify_union2(?union(List1)=T1, ?union(List2)=T2) ->
+ case {unify_union(List1), unify_union(List2)} of
+ {{yes, Type1}, {yes, Type2}} -> {Type1, Type2};
+ {{yes, Type1}, no} -> {Type1, T2};
+ {no, {yes, Type2}} -> {T1, Type2};
+ {no, no} -> throw({mismatch, T1, T2})
+ end.
+
+unify_union1(?union(List), T1, T2) ->
+ case unify_union(List) of
+ {yes, Type} -> Type;
+ no -> throw({mismatch, T1, T2})
+ end.
+
+unify_union(List) ->
+ [A,B,F,I,L,N,T,M,O,Map] = List,
+ if O =:= ?none -> no;
+ true ->
+ S = t_opaque_structure(O),
+ {yes, t_sup([A,B,F,I,L,N,T,M,S,Map])}
+ end.
+
+-spec is_opaque_type(erl_type(), [erl_type()]) -> boolean().
+
+%% An opaque type is a union of types. Returns true iff any of the type
+%% names (Module and Name) of the first argument (the opaque type to
+%% check) occurs in any of the opaque types of the second argument.
+is_opaque_type(?opaque(Elements), Opaques) ->
+ lists:any(fun(Opaque) -> is_opaque_type2(Opaque, Opaques) end, Elements).
+
+is_opaque_type2(#opaque{mod = Mod1, name = Name1, args = Args1}, Opaques) ->
+ F1 = fun(?opaque(Es)) ->
+ F2 = fun(#opaque{mod = Mod, name = Name, args = Args}) ->
+ is_type_name(Mod1, Name1, Args1, Mod, Name, Args)
+ end,
+ lists:any(F2, Es)
+ end,
+ lists:any(F1, Opaques).
+
+is_type_name(Mod, Name, Args1, Mod, Name, Args2) ->
+ length(Args1) =:= length(Args2);
+is_type_name(_Mod1, _Name1, _Args1, _Mod2, _Name2, _Args2) ->
+ false.
+
+%% Two functions since t_unify is not symmetric.
+unify_tuple_set_and_tuple1(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _), VarMap) ->
+ %% Can only work if the single tuple has variables at correct places.
+ %% Collapse the tuple set.
+ {NewElements, VarMap1} =
+ unify_lists(sup_tuple_elements(List), Elements2, VarMap),
+ {t_tuple(NewElements), VarMap1}.
+
+unify_tuple_set_and_tuple2(?tuple(Elements2, Arity, _),
+ ?tuple_set([{Arity, List}]), VarMap) ->
+ %% Can only work if the single tuple has variables at correct places.
+ %% Collapse the tuple set.
+ {NewElements, VarMap1} =
+ unify_lists(Elements2, sup_tuple_elements(List), VarMap),
+ {t_tuple(NewElements), VarMap1}.
+
+unify_lists(L1, L2, VarMap) ->
+ unify_lists(L1, L2, VarMap, []).
+
+unify_lists([T1|Left1], [T2|Left2], VarMap, Acc) ->
+ {NewT, NewVarMap} = t_unify(T1, T2, VarMap),
+ unify_lists(Left1, Left2, NewVarMap, [NewT|Acc]);
+unify_lists([], [], VarMap, Acc) ->
+ {lists:reverse(Acc), VarMap}.
+
+%%t_assign_variables_to_subtype(T1, T2) ->
+%% try
+%% Dict = assign_vars(T1, T2, dict:new()),
+%% {ok, dict:map(fun(_Param, List) -> t_sup(List) end, Dict)}
+%% catch
+%% throw:error -> error
+%% end.
+
+%%assign_vars(_, ?var(_), _Dict) ->
+%% erlang:error("Variable in right hand side of assignment");
+%%assign_vars(?any, _, Dict) ->
+%% Dict;
+%%assign_vars(?var(_) = Var, Type, Dict) ->
+%% store_var(Var, Type, Dict);
+%%assign_vars(?function(Domain1, Range1), ?function(Domain2, Range2), Dict) ->
+%% DomainList =
+%% case Domain2 of
+%% ?any -> [];
+%% ?product(List) -> List
+%% end,
+%% case any_none([Range2|DomainList]) of
+%% true -> throw(error);
+%% false ->
+%% Dict1 = assign_vars(Domain1, Domain2, Dict),
+%% assign_vars(Range1, Range2, Dict1)
+%% end;
+%%assign_vars(?list(_Contents, _Termination, ?any), ?nil, Dict) ->
+%% Dict;
+%%assign_vars(?list(Contents1, Termination1, Size1),
+%% ?list(Contents2, Termination2, Size2), Dict) ->
+%% Dict1 = assign_vars(Contents1, Contents2, Dict),
+%% Dict2 = assign_vars(Termination1, Termination2, Dict1),
+%% case {Size1, Size2} of
+%% {S, S} -> Dict2;
+%% {?any, ?nonempty_qual} -> Dict2;
+%% {_, _} -> throw(error)
+%% end;
+%%assign_vars(?product(Types1), ?product(Types2), Dict) ->
+%% case length(Types1) =:= length(Types2) of
+%% true -> assign_vars_lists(Types1, Types2, Dict);
+%% false -> throw(error)
+%% end;
+%%assign_vars(?tuple(?any, ?any, ?any), ?tuple(?any, ?any, ?any), Dict) ->
+%% Dict;
+%%assign_vars(?tuple(?any, ?any, ?any), ?tuple(_, _, _), Dict) ->
+%% Dict;
+%%assign_vars(?tuple(Elements1, Arity, _),
+%% ?tuple(Elements2, Arity, _), Dict) when Arity =/= ?any ->
+%% assign_vars_lists(Elements1, Elements2, Dict);
+%%assign_vars(?tuple_set(_) = T, ?tuple_set(List2), Dict) ->
+%% %% All Rhs tuples must already be subtypes of Lhs, so we can take
+%% %% each one separatly.
+%% assign_vars_lists([T || _ <- List2], List2, Dict);
+%%assign_vars(?tuple(?any, ?any, ?any), ?tuple_set(_), Dict) ->
+%% Dict;
+%%assign_vars(?tuple(_, Arity, _) = T1, ?tuple_set(List), Dict) ->
+%% case reduce_tuple_tags(List) of
+%% [Tuple = ?tuple(_, Arity, _)] -> assign_vars(T1, Tuple, Dict);
+%% _ -> throw(error)
+%% end;
+%%assign_vars(?tuple_set(List), ?tuple(_, Arity, Tag) = T2, Dict) ->
+%% case [T || ?tuple(_, Arity1, Tag1) = T <- List,
+%% Arity1 =:= Arity, Tag1 =:= Tag] of
+%% [] -> throw(error);
+%% [T1] -> assign_vars(T1, T2, Dict)
+%% end;
+%%assign_vars(?union(U1), T2, Dict) ->
+%% ?union(U2) = force_union(T2),
+%% assign_vars_lists(U1, U2, Dict);
+%%assign_vars(T, T, Dict) ->
+%% Dict;
+%%assign_vars(T1, T2, Dict) ->
+%% case t_is_subtype(T2, T1) of
+%% false -> throw(error);
+%% true -> Dict
+%% end.
+
+%%assign_vars_lists([T1|Left1], [T2|Left2], Dict) ->
+%% assign_vars_lists(Left1, Left2, assign_vars(T1, T2, Dict));
+%%assign_vars_lists([], [], Dict) ->
+%% Dict.
+
+%%store_var(?var(Id), Type, Dict) ->
+%% case dict:find(Id, Dict) of
+%% error -> dict:store(Id, [Type], Dict);
+%% {ok, _VarType0} -> dict:update(Id, fun(X) -> [Type|X] end, Dict)
+%% end.
+
+%%-----------------------------------------------------------------------------
+%% Subtraction.
+%%
+%% Note that the subtraction is an approximation since we do not have
+%% negative types. Also, tuples and products should be handled using
+%% the cartesian product of the elements, but this is not feasible to
+%% do.
+%%
+%% Example: {a|b,c|d}\{a,d} = {a,c}|{a,d}|{b,c}|{b,d} \ {a,d} =
+%% = {a,c}|{b,c}|{b,d} = {a|b,c|d}
+%%
+%% Instead, we can subtract if all elements but one becomes none after
+%% subtracting element-wise.
+%%
+%% Example: {a|b,c|d}\{a|b,d} = {a,c}|{a,d}|{b,c}|{b,d} \ {a,d}|{b,d} =
+%% = {a,c}|{b,c} = {a|b,c}
+
+-spec t_subtract_list(erl_type(), [erl_type()]) -> erl_type().
+
+t_subtract_list(T1, [T2|Left]) ->
+ t_subtract_list(t_subtract(T1, T2), Left);
+t_subtract_list(T, []) ->
+ T.
+
+-spec t_subtract(erl_type(), erl_type()) -> erl_type().
+
+t_subtract(_, ?any) -> ?none;
+t_subtract(T, ?var(_)) -> T;
+t_subtract(?any, _) -> ?any;
+t_subtract(?var(_) = T, _) -> T;
+t_subtract(T, ?unit) -> T;
+t_subtract(?unit, _) -> ?unit;
+t_subtract(?none, _) -> ?none;
+t_subtract(T, ?none) -> T;
+t_subtract(?atom(Set1), ?atom(Set2)) ->
+ case set_subtract(Set1, Set2) of
+ ?none -> ?none;
+ Set -> ?atom(Set)
+ end;
+t_subtract(?bitstr(U1, B1), ?bitstr(U2, B2)) ->
+ subtract_bin(t_bitstr(U1, B1), t_inf(t_bitstr(U1, B1), t_bitstr(U2, B2)));
+t_subtract(?function(_, _) = T1, ?function(_, _) = T2) ->
+ case t_is_subtype(T1, T2) of
+ true -> ?none;
+ false -> T1
+ end;
+t_subtract(?identifier(Set1), ?identifier(Set2)) ->
+ case set_subtract(Set1, Set2) of
+ ?none -> ?none;
+ Set -> ?identifier(Set)
+ end;
+t_subtract(?opaque(_)=T1, ?opaque(_)=T2) ->
+ opaque_subtract(T1, t_opaque_structure(T2));
+t_subtract(?opaque(_)=T1, T2) ->
+ opaque_subtract(T1, T2);
+t_subtract(T1, ?opaque(_)=T2) ->
+ t_subtract(T1, t_opaque_structure(T2));
+t_subtract(?matchstate(Pres1, Slots1), ?matchstate(Pres2, _Slots2)) ->
+ Pres = t_subtract(Pres1, Pres2),
+ case t_is_none(Pres) of
+ true -> ?none;
+ false -> ?matchstate(Pres, Slots1)
+ end;
+t_subtract(?matchstate(Present, Slots), _) ->
+ ?matchstate(Present, Slots);
+t_subtract(?nil, ?nil) ->
+ ?none;
+t_subtract(?nil, ?nonempty_list(_, _)) ->
+ ?nil;
+t_subtract(?nil, ?list(_, _, _)) ->
+ ?none;
+t_subtract(?list(Contents, Termination, _Size) = T, ?nil) ->
+ case Termination =:= ?nil of
+ true -> ?nonempty_list(Contents, Termination);
+ false -> T
+ end;
+t_subtract(?list(Contents1, Termination1, Size1) = T,
+ ?list(Contents2, Termination2, Size2)) ->
+ case t_is_subtype(Contents1, Contents2) of
+ true ->
+ case t_is_subtype(Termination1, Termination2) of
+ true ->
+ case {Size1, Size2} of
+ {?nonempty_qual, ?unknown_qual} -> ?none;
+ {?unknown_qual, ?nonempty_qual} -> ?nil;
+ {S, S} -> ?none
+ end;
+ false ->
+ %% If the termination is not covered by the subtracted type
+ %% we cannot really say anything about the result.
+ T
+ end;
+ false ->
+ %% All contents must be covered if there is going to be any
+ %% change to the list.
+ T
+ end;
+t_subtract(?float, ?float) -> ?none;
+t_subtract(?number(_, _) = T1, ?float) -> t_inf(T1, t_integer());
+t_subtract(?float, ?number(_Set, Tag)) ->
+ case Tag of
+ ?unknown_qual -> ?none;
+ _ -> ?float
+ end;
+t_subtract(?number(_, _), ?number(?any, ?unknown_qual)) -> ?none;
+t_subtract(?number(_, _) = T1, ?integer(?any)) -> t_inf(?float, T1);
+t_subtract(?int_set(Set1), ?int_set(Set2)) ->
+ case set_subtract(Set1, Set2) of
+ ?none -> ?none;
+ Set -> ?int_set(Set)
+ end;
+t_subtract(?int_range(From1, To1) = T1, ?int_range(_, _) = T2) ->
+ case t_inf(T1, T2) of
+ ?none -> T1;
+ ?int_range(From1, To1) -> ?none;
+ ?int_range(neg_inf, To) -> t_from_range(To + 1, To1);
+ ?int_range(From, pos_inf) -> t_from_range(From1, From - 1);
+ ?int_range(From, To) -> t_sup(t_from_range(From1, From - 1),
+ t_from_range(To + 1, To))
+ end;
+t_subtract(?int_range(From, To) = T1, ?int_set(Set)) ->
+ NewFrom = case set_is_element(From, Set) of
+ true -> From + 1;
+ false -> From
+ end,
+ NewTo = case set_is_element(To, Set) of
+ true -> To - 1;
+ false -> To
+ end,
+ if (NewFrom =:= From) and (NewTo =:= To) -> T1;
+ true -> t_from_range(NewFrom, NewTo)
+ end;
+t_subtract(?int_set(Set), ?int_range(From, To)) ->
+ case set_filter(fun(X) -> not ((X =< From) orelse (X >= To)) end, Set) of
+ ?none -> ?none;
+ NewSet -> ?int_set(NewSet)
+ end;
+t_subtract(?integer(?any) = T1, ?integer(_)) -> T1;
+t_subtract(?number(_, _) = T1, ?number(_, _)) -> T1;
+t_subtract(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> ?none;
+t_subtract(?tuple_set(_), ?tuple(?any, ?any, ?any)) -> ?none;
+t_subtract(?tuple(?any, ?any, ?any) = T1, ?tuple_set(_)) -> T1;
+t_subtract(?tuple(Elements1, Arity1, _Tag1) = T1,
+ ?tuple(Elements2, Arity2, _Tag2)) ->
+ if Arity1 =/= Arity2 -> T1;
+ Arity1 =:= Arity2 ->
+ NewElements = t_subtract_lists(Elements1, Elements2),
+ case [E || E <- NewElements, E =/= ?none] of
+ [] -> ?none;
+ [_] -> t_tuple(replace_nontrivial_element(Elements1, NewElements));
+ _ -> T1
+ end
+ end;
+t_subtract(?tuple_set(List1) = T1, ?tuple(_, Arity, _) = T2) ->
+ case orddict:find(Arity, List1) of
+ error -> T1;
+ {ok, List2} ->
+ TuplesLeft0 = [Tuple || {_Arity, Tuple} <- orddict:erase(Arity, List1)],
+ TuplesLeft1 = lists:append(TuplesLeft0),
+ t_sup([t_subtract(L, T2) || L <- List2] ++ TuplesLeft1)
+ end;
+t_subtract(?tuple(_, Arity, _) = T1, ?tuple_set(List1)) ->
+ case orddict:find(Arity, List1) of
+ error -> T1;
+ {ok, List2} -> t_inf([t_subtract(T1, L) || L <- List2])
+ end;
+t_subtract(?tuple_set(_) = T1, ?tuple_set(_) = T2) ->
+ t_sup([t_subtract(T, T2) || T <- t_tuple_subtypes(T1)]);
+t_subtract(?product(Elements1) = T1, ?product(Elements2)) ->
+ Arity1 = length(Elements1),
+ Arity2 = length(Elements2),
+ if Arity1 =/= Arity2 -> T1;
+ Arity1 =:= Arity2 ->
+ NewElements = t_subtract_lists(Elements1, Elements2),
+ case [E || E <- NewElements, E =/= ?none] of
+ [] -> ?none;
+ [_] -> t_product(replace_nontrivial_element(Elements1, NewElements));
+ _ -> T1
+ end
+ end;
+t_subtract(?map(APairs, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B) ->
+ case t_is_subtype(ADefK, BDefK) andalso t_is_subtype(ADefV, BDefV) of
+ false -> A;
+ true ->
+ %% We fold over the maps to produce a list of constraints, where
+ %% constraints are additional key-value pairs to put in Pairs. Only one
+ %% constraint need to be applied to produce a type that excludes the
+ %% right-hand-side type, so if more than one constraint is produced, we
+ %% just return the left-hand-side argument.
+ %%
+ %% Each case of the fold may either conclude that
+ %% * The arguments constrain A at least as much as B, i.e. that A so far
+ %% is a subtype of B. In that case they return false
+ %% * That for the particular arguments, A being a subtype of B does not
+ %% hold, but the infinimum of A and B is nonempty, and by narrowing a
+ %% pair in A, we can create a type that excludes some elements in the
+ %% infinumum. In that case, they will return that pair.
+ %% * That for the particular arguments, A being a subtype of B does not
+ %% hold, and either the infinumum of A and B is empty, or it is not
+ %% possible with the current representation to create a type that
+ %% excludes elements from B without also excluding elements that are
+ %% only in A. In that case, it will return the pair from A unchanged.
+ case
+ map_pairwise_merge(
+ %% If V1 is a subtype of V2, the case that K does not exist in A
+ %% remain.
+ fun(K, ?opt, V1, ?mand, V2) -> {K, ?opt, t_subtract(V1, V2)};
+ (K, _, V1, _, V2) ->
+ %% If we subtract an optional key, that leaves a mandatory key
+ case t_subtract(V1, V2) of
+ ?none -> false;
+ Partial -> {K, ?mand, Partial}
+ end
+ end, A, B)
+ of
+ %% We produce a list of keys that are constrained. As only one of
+ %% these should apply at a time, we can't represent the difference if
+ %% more than one constraint is produced. If we applied all of them,
+ %% that would make an underapproximation, which we must not do.
+ [] -> ?none; %% A is a subtype of B
+ [E] -> t_map(mapdict_store(E, APairs), ADefK, ADefV);
+ _ -> A
+ end
+ end;
+t_subtract(?product(P1), _) ->
+ ?product(P1);
+t_subtract(T, ?product(_)) ->
+ T;
+t_subtract(?union(U1), ?union(U2)) ->
+ subtract_union(U1, U2);
+t_subtract(T1, T2) ->
+ ?union(U1) = force_union(T1),
+ ?union(U2) = force_union(T2),
+ subtract_union(U1, U2).
+
+-spec opaque_subtract(erl_type(), erl_type()) -> erl_type().
+
+opaque_subtract(?opaque(Set1), T2) ->
+ List = [T1#opaque{struct = Sub} ||
+ #opaque{struct = S1}=T1 <- set_to_list(Set1),
+ not t_is_none(Sub = t_subtract(S1, T2))],
+ case List of
+ [] -> ?none;
+ _ -> ?opaque(ordsets:from_list(List))
+ end.
+
+-spec t_subtract_lists([erl_type()], [erl_type()]) -> [erl_type()].
+
+t_subtract_lists(L1, L2) ->
+ t_subtract_lists(L1, L2, []).
+
+-spec t_subtract_lists([erl_type()], [erl_type()], [erl_type()]) -> [erl_type()].
+
+t_subtract_lists([T1|Left1], [T2|Left2], Acc) ->
+ t_subtract_lists(Left1, Left2, [t_subtract(T1, T2)|Acc]);
+t_subtract_lists([], [], Acc) ->
+ lists:reverse(Acc).
+
+-spec subtract_union([erl_type(),...], [erl_type(),...]) -> erl_type().
+
+subtract_union(U1, U2) ->
+ [A1,B1,F1,I1,L1,N1,T1,M1,O1,Map1] = U1,
+ [A2,B2,F2,I2,L2,N2,T2,M2,O2,Map2] = U2,
+ List1 = [A1,B1,F1,I1,L1,N1,T1,M1,?none,Map1],
+ List2 = [A2,B2,F2,I2,L2,N2,T2,M2,?none,Map2],
+ Sub1 = subtract_union(List1, List2, 0, []),
+ O = if O1 =:= ?none -> O1;
+ true -> t_subtract(O1, ?union(U2))
+ end,
+ Sub2 = if O2 =:= ?none -> Sub1;
+ true -> t_subtract(Sub1, t_opaque_structure(O2))
+ end,
+ t_sup(O, Sub2).
+
+-spec subtract_union([erl_type()], [erl_type()], non_neg_integer(), [erl_type()]) -> erl_type().
+
+subtract_union([T1|Left1], [T2|Left2], N, Acc) ->
+ case t_subtract(T1, T2) of
+ ?none -> subtract_union(Left1, Left2, N, [?none|Acc]);
+ T -> subtract_union(Left1, Left2, N+1, [T|Acc])
+ end;
+subtract_union([], [], 0, _Acc) ->
+ ?none;
+subtract_union([], [], 1, Acc) ->
+ [T] = [X || X <- Acc, X =/= ?none],
+ T;
+subtract_union([], [], N, Acc) when is_integer(N), N > 1 ->
+ ?union(lists:reverse(Acc)).
+
+replace_nontrivial_element(El1, El2) ->
+ replace_nontrivial_element(El1, El2, []).
+
+replace_nontrivial_element([T1|Left1], [?none|Left2], Acc) ->
+ replace_nontrivial_element(Left1, Left2, [T1|Acc]);
+replace_nontrivial_element([_|Left1], [T2|_], Acc) ->
+ lists:reverse(Acc) ++ [T2|Left1].
+
+subtract_bin(?bitstr(U1, B1), ?bitstr(U1, B1)) ->
+ ?none;
+subtract_bin(?bitstr(U1, B1), ?none) ->
+ t_bitstr(U1, B1);
+subtract_bin(?bitstr(U1, B1), ?bitstr(0, B1)) ->
+ t_bitstr(U1, B1+U1);
+subtract_bin(?bitstr(U1, B1), ?bitstr(U1, B2)) ->
+ if (B1+U1) =/= B2 -> t_bitstr(0, B1);
+ true -> t_bitstr(U1, B1)
+ end;
+subtract_bin(?bitstr(U1, B1), ?bitstr(U2, B2)) ->
+ if (2 * U1) =:= U2 ->
+ if B1 =:= B2 ->
+ t_bitstr(U2, B1+U1);
+ (B1 + U1) =:= B2 ->
+ t_bitstr(U2, B1);
+ true ->
+ t_bitstr(U1, B1)
+ end;
+ true ->
+ t_bitstr(U1, B1)
+ end.
+
+%%-----------------------------------------------------------------------------
+%% Relations
+%%
+
+-spec t_is_equal(erl_type(), erl_type()) -> boolean().
+
+t_is_equal(T, T) -> true;
+t_is_equal(_, _) -> false.
+
+-spec t_is_subtype(erl_type(), erl_type()) -> boolean().
+
+t_is_subtype(T1, T2) ->
+ Inf = t_inf(T1, T2),
+ subtype_is_equal(T1, Inf).
+
+%% The subtype relation has to behave correctly irrespective of opaque
+%% types.
+subtype_is_equal(T, T) -> true;
+subtype_is_equal(T1, T2) ->
+ t_is_equal(case t_contains_opaque(T1) of
+ true -> t_unopaque(T1);
+ false -> T1
+ end,
+ case t_contains_opaque(T2) of
+ true -> t_unopaque(T2);
+ false -> T2
+ end).
+
+-spec t_is_instance(erl_type(), erl_type()) -> boolean().
+
+%% XXX. To be removed.
+t_is_instance(ConcreteType, Type) ->
+ t_is_subtype(ConcreteType, t_unopaque(Type)).
+
+-spec t_do_overlap(erl_type(), erl_type()) -> boolean().
+
+t_do_overlap(TypeA, TypeB) ->
+ not (t_is_none_or_unit(t_inf(TypeA, TypeB))).
+
+-spec t_unopaque(erl_type()) -> erl_type().
+
+t_unopaque(T) ->
+ t_unopaque(T, 'universe').
+
+-spec t_unopaque(erl_type(), opaques()) -> erl_type().
+
+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
+ end;
+t_unopaque(?list(ElemT, Termination, Sz), Opaques) ->
+ ?list(t_unopaque(ElemT, Opaques), t_unopaque(Termination, Opaques), Sz);
+t_unopaque(?tuple(?any, _, _) = T, _) -> T;
+t_unopaque(?tuple(ArgTs, Sz, Tag), Opaques) when is_list(ArgTs) ->
+ NewArgTs = [t_unopaque(A, Opaques) || A <- ArgTs],
+ ?tuple(NewArgTs, Sz, Tag);
+t_unopaque(?tuple_set(Set), Opaques) ->
+ NewSet = [{Sz, [t_unopaque(T, Opaques) || T <- Tuples]}
+ || {Sz, Tuples} <- Set],
+ ?tuple_set(NewSet);
+t_unopaque(?product(Types), Opaques) ->
+ ?product([t_unopaque(T, Opaques) || T <- Types]);
+t_unopaque(?function(Domain, Range), Opaques) ->
+ ?function(t_unopaque(Domain, Opaques), t_unopaque(Range, Opaques));
+t_unopaque(?union([A,B,F,I,L,N,T,M,O,Map]), Opaques) ->
+ UL = t_unopaque(L, Opaques),
+ UT = t_unopaque(T, Opaques),
+ UF = t_unopaque(F, Opaques),
+ UM = t_unopaque(M, 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,UM,OF,UMap])|UO]);
+t_unopaque(?map(Pairs,DefK,DefV), Opaques) ->
+ t_map([{K, MNess, t_unopaque(V, Opaques)} || {K, MNess, V} <- Pairs],
+ t_unopaque(DefK, Opaques),
+ t_unopaque(DefV, Opaques));
+t_unopaque(T, _) ->
+ T.
+
+%%-----------------------------------------------------------------------------
+%% K-depth abstraction.
+%%
+%% t_limit/2 is the exported function, which checks the type of the
+%% second argument and calls the module local t_limit_k/2 function.
+%%
+
+-spec t_limit(erl_type(), integer()) -> erl_type().
+
+t_limit(Term, K) when is_integer(K) ->
+ t_limit_k(Term, K).
+
+t_limit_k(_, K) when K =< 0 -> ?any;
+t_limit_k(?tuple(?any, ?any, ?any) = T, _K) -> T;
+t_limit_k(?tuple(Elements, Arity, _), K) ->
+ if K =:= 1 -> t_tuple(Arity);
+ true -> t_tuple([t_limit_k(E, K-1) || E <- Elements])
+ end;
+t_limit_k(?tuple_set(_) = T, K) ->
+ t_sup([t_limit_k(Tuple, K) || Tuple <- t_tuple_subtypes(T)]);
+t_limit_k(?list(Elements, Termination, Size), K) ->
+ NewTermination =
+ if K =:= 1 ->
+ %% We do not want to lose the termination information.
+ t_limit_k(Termination, K);
+ true -> t_limit_k(Termination, K - 1)
+ end,
+ NewElements = t_limit_k(Elements, K - 1),
+ TmpList = t_cons(NewElements, NewTermination),
+ case Size of
+ ?nonempty_qual -> TmpList;
+ ?unknown_qual ->
+ ?list(NewElements1, NewTermination1, _) = TmpList,
+ ?list(NewElements1, NewTermination1, ?unknown_qual)
+ end;
+t_limit_k(?function(Domain, Range), K) ->
+ %% The domain is either a product or any() so we do not decrease the K.
+ ?function(t_limit_k(Domain, K), t_limit_k(Range, K-1));
+t_limit_k(?product(Elements), K) ->
+ ?product([t_limit_k(X, K - 1) || X <- Elements]);
+t_limit_k(?union(Elements), K) ->
+ ?union([t_limit_k(X, K) || X <- Elements]);
+t_limit_k(?opaque(Es), K) ->
+ List = [begin
+ NewS = t_limit_k(S, K),
+ Opaque#opaque{struct = NewS}
+ end || #opaque{struct = S} = Opaque <- set_to_list(Es)],
+ ?opaque(ordsets:from_list(List));
+t_limit_k(?map(Pairs0, DefK0, DefV0), K) ->
+ Fun = fun({EK, MNess, EV}, {Exact, DefK1, DefV1}) ->
+ LV = t_limit_k(EV, K - 1),
+ case t_limit_k(EK, K - 1) of
+ EK -> {[{EK,MNess,LV}|Exact], DefK1, DefV1};
+ LK -> {Exact, t_sup(LK, DefK1), t_sup(LV, DefV1)}
+ end
+ end,
+ {Pairs, DefK2, DefV2} = lists:foldr(Fun, {[], DefK0, DefV0}, Pairs0),
+ t_map(Pairs, t_limit_k(DefK2, K - 1), t_limit_k(DefV2, K - 1));
+t_limit_k(T, _K) -> T.
+
+%%============================================================================
+%%
+%% Abstract records. Used for comparing contracts.
+%%
+%%============================================================================
+
+-spec t_abstract_records(erl_type(), type_table()) -> erl_type().
+
+t_abstract_records(?list(Contents, Termination, Size), RecDict) ->
+ case t_abstract_records(Contents, RecDict) of
+ ?none -> ?none;
+ NewContents ->
+ %% Be careful here to make the termination collapse if necessary.
+ case t_abstract_records(Termination, RecDict) of
+ ?nil -> ?list(NewContents, ?nil, Size);
+ ?any -> ?list(NewContents, ?any, Size);
+ Other ->
+ ?list(NewContents2, NewTermination, _) = t_cons(NewContents, Other),
+ ?list(NewContents2, NewTermination, Size)
+ end
+ end;
+t_abstract_records(?function(Domain, Range), RecDict) ->
+ ?function(t_abstract_records(Domain, RecDict),
+ t_abstract_records(Range, RecDict));
+t_abstract_records(?product(Types), RecDict) ->
+ ?product([t_abstract_records(T, RecDict) || T <- Types]);
+t_abstract_records(?union(Types), RecDict) ->
+ t_sup([t_abstract_records(T, RecDict) || T <- Types]);
+t_abstract_records(?tuple(?any, ?any, ?any) = T, _RecDict) ->
+ T;
+t_abstract_records(?tuple(Elements, Arity, ?atom(_) = Tag), RecDict) ->
+ [TagAtom] = atom_vals(Tag),
+ case lookup_record(TagAtom, Arity - 1, RecDict) of
+ error -> t_tuple([t_abstract_records(E, RecDict) || E <- Elements]);
+ {ok, Fields} -> t_tuple([Tag|[T || {_Name, _Abstr, T} <- Fields]])
+ end;
+t_abstract_records(?tuple(Elements, _Arity, _Tag), RecDict) ->
+ t_tuple([t_abstract_records(E, RecDict) || E <- Elements]);
+t_abstract_records(?tuple_set(_) = Tuples, RecDict) ->
+ t_sup([t_abstract_records(T, RecDict) || T <- t_tuple_subtypes(Tuples)]);
+t_abstract_records(?opaque(_)=Type, RecDict) ->
+ t_abstract_records(t_opaque_structure(Type), RecDict);
+t_abstract_records(T, _RecDict) ->
+ T.
+
+%% Map over types. Depth first. Used by the contract checker. ?list is
+%% not fully implemented so take care when changing the type in Termination.
+
+-spec t_map(fun((erl_type()) -> erl_type()), erl_type()) -> erl_type().
+
+t_map(Fun, ?list(Contents, Termination, Size)) ->
+ Fun(?list(t_map(Fun, Contents), t_map(Fun, Termination), Size));
+t_map(Fun, ?function(Domain, Range)) ->
+ Fun(?function(t_map(Fun, Domain), t_map(Fun, Range)));
+t_map(Fun, ?product(Types)) ->
+ Fun(?product([t_map(Fun, T) || T <- Types]));
+t_map(Fun, ?union(Types)) ->
+ Fun(t_sup([t_map(Fun, T) || T <- Types]));
+t_map(Fun, ?tuple(?any, ?any, ?any) = T) ->
+ Fun(T);
+t_map(Fun, ?tuple(Elements, _Arity, _Tag)) ->
+ Fun(t_tuple([t_map(Fun, E) || E <- Elements]));
+t_map(Fun, ?tuple_set(_) = Tuples) ->
+ Fun(t_sup([t_map(Fun, T) || T <- t_tuple_subtypes(Tuples)]));
+t_map(Fun, ?opaque(Set)) ->
+ L = [Opaque#opaque{struct = NewS} ||
+ #opaque{struct = S} = Opaque <- set_to_list(Set),
+ not t_is_none(NewS = t_map(Fun, S))],
+ Fun(case L of
+ [] -> ?none;
+ _ -> ?opaque(ordsets:from_list(L))
+ end);
+t_map(Fun, ?map(Pairs,DefK,DefV)) ->
+ %% TODO:
+ Fun(t_map(Pairs, Fun(DefK), Fun(DefV)));
+t_map(Fun, T) ->
+ Fun(T).
+
+%%=============================================================================
+%%
+%% Prettyprinter
+%%
+%%=============================================================================
+
+-spec t_to_string(erl_type()) -> string().
+
+t_to_string(T) ->
+ t_to_string(T, dict:new()).
+
+-spec t_to_string(erl_type(), type_table()) -> string().
+
+t_to_string(?any, _RecDict) ->
+ "any()";
+t_to_string(?none, _RecDict) ->
+ "none()";
+t_to_string(?unit, _RecDict) ->
+ "no_return()";
+t_to_string(?atom(?any), _RecDict) ->
+ "atom()";
+t_to_string(?atom(Set), _RecDict) ->
+ case set_size(Set) of
+ 2 ->
+ case set_is_element(true, Set) andalso set_is_element(false, Set) of
+ true -> "boolean()";
+ false -> set_to_string(Set)
+ end;
+ _ ->
+ set_to_string(Set)
+ end;
+t_to_string(?bitstr(0, 0), _RecDict) ->
+ "<<>>";
+t_to_string(?bitstr(8, 0), _RecDict) ->
+ "binary()";
+t_to_string(?bitstr(1, 0), _RecDict) ->
+ "bitstring()";
+t_to_string(?bitstr(0, B), _RecDict) ->
+ flat_format("<<_:~w>>", [B]);
+t_to_string(?bitstr(U, 0), _RecDict) ->
+ flat_format("<<_:_*~w>>", [U]);
+t_to_string(?bitstr(U, B), _RecDict) ->
+ flat_format("<<_:~w,_:_*~w>>", [B, U]);
+t_to_string(?function(?any, ?any), _RecDict) ->
+ "fun()";
+t_to_string(?function(?any, Range), RecDict) ->
+ "fun((...) -> " ++ t_to_string(Range, RecDict) ++ ")";
+t_to_string(?function(?product(ArgList), Range), RecDict) ->
+ "fun((" ++ comma_sequence(ArgList, RecDict) ++ ") -> "
+ ++ t_to_string(Range, RecDict) ++ ")";
+t_to_string(?identifier(Set), _RecDict) ->
+ case Set of
+ ?any -> "identifier()";
+ _ ->
+ string:join([flat_format("~w()", [T]) || T <- set_to_list(Set)], " | ")
+ end;
+t_to_string(?opaque(Set), RecDict) ->
+ string:join([opaque_type(Mod, Name, Args, S, RecDict) ||
+ #opaque{mod = Mod, name = Name, struct = S, args = Args}
+ <- set_to_list(Set)],
+ " | ");
+t_to_string(?matchstate(Pres, Slots), RecDict) ->
+ flat_format("ms(~s,~s)", [t_to_string(Pres, RecDict),
+ t_to_string(Slots,RecDict)]);
+t_to_string(?nil, _RecDict) ->
+ "[]";
+t_to_string(?nonempty_list(Contents, Termination), RecDict) ->
+ ContentString = t_to_string(Contents, RecDict),
+ case Termination of
+ ?nil ->
+ case Contents of
+ ?char -> "nonempty_string()";
+ _ -> "["++ContentString++",...]"
+ end;
+ ?any ->
+ %% Just a safety check.
+ case Contents =:= ?any of
+ true -> ok;
+ false ->
+ %% XXX. See comment below.
+ %% erlang:error({illegal_list, ?nonempty_list(Contents, Termination)})
+ ok
+ end,
+ "nonempty_maybe_improper_list()";
+ _ ->
+ case t_is_subtype(t_nil(), Termination) of
+ true ->
+ "nonempty_maybe_improper_list("++ContentString++","
+ ++t_to_string(Termination, RecDict)++")";
+ false ->
+ "nonempty_improper_list("++ContentString++","
+ ++t_to_string(Termination, RecDict)++")"
+ end
+ end;
+t_to_string(?list(Contents, Termination, ?unknown_qual), RecDict) ->
+ ContentString = t_to_string(Contents, RecDict),
+ case Termination of
+ ?nil ->
+ case Contents of
+ ?char -> "string()";
+ _ -> "["++ContentString++"]"
+ end;
+ ?any ->
+ %% Just a safety check.
+ %% XXX. Types such as "maybe_improper_list(integer(), any())"
+ %% are OK, but cannot be printed!?
+ case Contents =:= ?any of
+ true -> ok;
+ false ->
+ ok
+ %% L = ?list(Contents, Termination, ?unknown_qual),
+ %% erlang:error({illegal_list, L})
+ end,
+ "maybe_improper_list()";
+ _ ->
+ case t_is_subtype(t_nil(), Termination) of
+ true ->
+ "maybe_improper_list("++ContentString++","
+ ++t_to_string(Termination, RecDict)++")";
+ false ->
+ "improper_list("++ContentString++","
+ ++t_to_string(Termination, RecDict)++")"
+ end
+ end;
+t_to_string(?int_set(Set), _RecDict) ->
+ set_to_string(Set);
+t_to_string(?byte, _RecDict) -> "byte()";
+t_to_string(?char, _RecDict) -> "char()";
+t_to_string(?integer_pos, _RecDict) -> "pos_integer()";
+t_to_string(?integer_non_neg, _RecDict) -> "non_neg_integer()";
+t_to_string(?integer_neg, _RecDict) -> "neg_integer()";
+t_to_string(?int_range(From, To), _RecDict) ->
+ flat_format("~w..~w", [From, To]);
+t_to_string(?integer(?any), _RecDict) -> "integer()";
+t_to_string(?float, _RecDict) -> "float()";
+t_to_string(?number(?any, ?unknown_qual), _RecDict) -> "number()";
+t_to_string(?product(List), RecDict) ->
+ "<" ++ comma_sequence(List, RecDict) ++ ">";
+t_to_string(?map([],?any,?any), _RecDict) -> "map()";
+t_to_string(?map(Pairs0,DefK,DefV), RecDict) ->
+ {Pairs, ExtraEl} =
+ case {DefK, DefV} of
+ {?none, ?none} -> {Pairs0, []};
+ _ -> {Pairs0 ++ [{DefK,?opt,DefV}], []}
+ end,
+ Tos = fun(T) -> case T of
+ ?any -> "_";
+ _ -> t_to_string(T, RecDict)
+ end end,
+ StrMand = [{Tos(K),Tos(V)}||{K,?mand,V}<-Pairs],
+ StrOpt = [{Tos(K),Tos(V)}||{K,?opt,V}<-Pairs],
+ "#{" ++ string:join([K ++ ":=" ++ V||{K,V}<-StrMand]
+ ++ [K ++ "=>" ++ V||{K,V}<-StrOpt]
+ ++ ExtraEl, ", ") ++ "}";
+t_to_string(?tuple(?any, ?any, ?any), _RecDict) -> "tuple()";
+t_to_string(?tuple(Elements, _Arity, ?any), RecDict) ->
+ "{" ++ comma_sequence(Elements, RecDict) ++ "}";
+t_to_string(?tuple(Elements, Arity, Tag), RecDict) ->
+ [TagAtom] = atom_vals(Tag),
+ case lookup_record(TagAtom, Arity-1, RecDict) of
+ error -> "{" ++ comma_sequence(Elements, RecDict) ++ "}";
+ {ok, FieldNames} ->
+ record_to_string(TagAtom, Elements, FieldNames, RecDict)
+ end;
+t_to_string(?tuple_set(_) = T, RecDict) ->
+ union_sequence(t_tuple_subtypes(T), RecDict);
+t_to_string(?union(Types), RecDict) ->
+ union_sequence([T || T <- Types, T =/= ?none], RecDict);
+t_to_string(?var(Id), _RecDict) when is_atom(Id) ->
+ flat_format("~s", [atom_to_list(Id)]);
+t_to_string(?var(Id), _RecDict) when is_integer(Id) ->
+ flat_format("var(~w)", [Id]).
+
+
+record_to_string(Tag, [_|Fields], FieldNames, RecDict) ->
+ FieldStrings = record_fields_to_string(Fields, FieldNames, RecDict, []),
+ "#" ++ atom_to_string(Tag) ++ "{" ++ string:join(FieldStrings, ",") ++ "}".
+
+record_fields_to_string([F|Fs], [{FName, _Abstr, DefType}|FDefs],
+ RecDict, Acc) ->
+ NewAcc =
+ case
+ t_is_equal(F, t_any()) orelse
+ (t_is_any_atom('undefined', F) andalso
+ not t_is_none(t_inf(F, DefType)))
+ of
+ true -> Acc;
+ false ->
+ StrFV = atom_to_string(FName) ++ "::" ++ t_to_string(F, RecDict),
+ [StrFV|Acc]
+ end,
+ record_fields_to_string(Fs, FDefs, RecDict, NewAcc);
+record_fields_to_string([], [], _RecDict, Acc) ->
+ lists:reverse(Acc).
+
+-spec record_field_diffs_to_string(erl_type(), type_table()) -> string().
+
+record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
+ [TagAtom] = atom_vals(Tag),
+ {ok, FieldNames} = lookup_record(TagAtom, Arity-1, RecDict),
+ %% io:format("RecCElems = ~p\nRecTypes = ~p\n", [Fs, FieldNames]),
+ FieldDiffs = field_diffs(Fs, FieldNames, RecDict, []),
+ string:join(FieldDiffs, " and ").
+
+field_diffs([F|Fs], [{FName, _Abstr, DefType}|FDefs], RecDict, Acc) ->
+ %% Don't care about opacity for now.
+ NewAcc =
+ case not t_is_none(t_inf(F, DefType)) of
+ true -> Acc;
+ false ->
+ Str = atom_to_string(FName) ++ "::" ++ t_to_string(DefType, RecDict),
+ [Str|Acc]
+ end,
+ field_diffs(Fs, FDefs, RecDict, NewAcc);
+field_diffs([], [], _, Acc) ->
+ lists:reverse(Acc).
+
+comma_sequence(Types, RecDict) ->
+ List = [case T =:= ?any of
+ true -> "_";
+ false -> t_to_string(T, RecDict)
+ end || T <- Types],
+ string:join(List, ",").
+
+union_sequence(Types, RecDict) ->
+ List = [t_to_string(T, RecDict) || T <- Types],
+ string:join(List, " | ").
+
+-ifdef(DEBUG).
+opaque_type(Mod, Name, _Args, S, RecDict) ->
+ ArgsString = comma_sequence(_Args, RecDict),
+ String = t_to_string(S, RecDict),
+ opaque_name(Mod, Name, ArgsString) ++ "[" ++ String ++ "]".
+-else.
+opaque_type(Mod, Name, Args, _S, RecDict) ->
+ ArgsString = comma_sequence(Args, RecDict),
+ opaque_name(Mod, Name, ArgsString).
+-endif.
+
+opaque_name(Mod, Name, Extra) ->
+ S = mod_name(Mod, Name),
+ flat_format("~s(~s)", [S, Extra]).
+
+mod_name(Mod, Name) ->
+ flat_format("~w:~w", [Mod, Name]).
+
+%%=============================================================================
+%%
+%% Build a type from parse forms.
+%%
+%%=============================================================================
+
+-type type_names() :: [type_key() | record_key()].
+
+-type mta() :: {module(), atom(), arity()}.
+-type mra() :: {module(), atom(), arity()}.
+-type site() :: {'type', mta()} | {'spec', mfa()} | {'record', mra()}.
+-type cache_key() :: {module(), atom(), expand_depth(),
+ [erl_type()], type_names()}.
+-opaque cache() :: #{cache_key() => {erl_type(), expand_limit()}}.
+
+-spec t_from_form(parse_form(), sets:set(mfa()), site(), mod_records(),
+ var_table(), cache()) -> {erl_type(), cache()}.
+
+t_from_form(Form, ExpTypes, Site, RecDict, VarTab, Cache) ->
+ t_from_form1(Form, ExpTypes, Site, RecDict, VarTab, Cache).
+
+%% Replace external types with with none().
+-spec t_from_form_without_remote(parse_form(), site(), type_table()) ->
+ {erl_type(), cache()}.
+
+t_from_form_without_remote(Form, Site, TypeTable) ->
+ Module = site_module(Site),
+ RecDict = dict:from_list([{Module, TypeTable}]),
+ ExpTypes = replace_by_none,
+ VarTab = var_table__new(),
+ Cache = cache__new(),
+ t_from_form1(Form, ExpTypes, Site, RecDict, VarTab, Cache).
+
+%% REC_TYPE_LIMIT is used for limiting the depth of recursive types.
+%% EXPAND_LIMIT is used for limiting the size of types by
+%% limiting the number of elements of lists within one type form.
+%% EXPAND_DEPTH is used in conjunction with EXPAND_LIMIT to make the
+%% types balanced (unions will otherwise collapse to any()) by limiting
+%% the depth the same way as t_limit/2 does.
+
+-type expand_limit() :: integer().
+
+-type expand_depth() :: integer().
+
+-record(from_form, {site :: site(),
+ xtypes :: sets:set(mfa()) | 'replace_by_none',
+ mrecs :: mod_records(),
+ vtab :: var_table(),
+ tnames :: type_names()}).
+
+-spec t_from_form1(parse_form(), sets:set(mfa()) | 'replace_by_none',
+ site(), mod_records(), var_table(), cache()) ->
+ {erl_type(), cache()}.
+
+t_from_form1(Form, ET, Site, MR, V, C) ->
+ TypeNames = initial_typenames(Site),
+ State = #from_form{site = Site,
+ xtypes = ET,
+ mrecs = MR,
+ vtab = V,
+ tnames = TypeNames},
+ L = ?EXPAND_LIMIT,
+ {T1, L1, C1} = from_form(Form, State, ?EXPAND_DEPTH, L, C),
+ if
+ L1 =< 0 ->
+ from_form_loop(Form, State, 1, L, C1);
+ true ->
+ {T1, C1}
+ end.
+
+initial_typenames({type, _MTA}=Site) -> [Site];
+initial_typenames({spec, _MFA}) -> [];
+initial_typenames({record, _MRA}) -> [].
+
+from_form_loop(Form, State, D, Limit, C) ->
+ {T1, L1, C1} = from_form(Form, State, D, Limit, C),
+ Delta = Limit - L1,
+ if
+ %% Save some time by assuming next depth will exceed the limit.
+ Delta * 8 > Limit ->
+ {T1, C1};
+ true ->
+ D1 = D + 1,
+ from_form_loop(Form, State, D1, Limit, C1)
+ end.
+
+-spec from_form(parse_form(),
+ #from_form{},
+ expand_depth(),
+ expand_limit(),
+ cache()) -> {erl_type(), expand_limit(), cache()}.
+
+%% If there is something wrong with parse_form()
+%% throw({error, io_lib:chars()} is called;
+%% for unknown remote types
+%% self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}
+%% is called, unless 'replace_by_none' is given.
+%%
+%% It is assumed that site_module(S) can be found in MR.
+
+from_form(_, _S, D, L, C) when D =< 0 ; L =< 0 ->
+ {t_any(), L, C};
+from_form({var, _L, '_'}, _S, _D, L, C) ->
+ {t_any(), L, C};
+from_form({var, _L, Name}, S, _D, L, C) ->
+ V = S#from_form.vtab,
+ case maps:find(Name, V) of
+ error -> {t_var(Name), L, C};
+ {ok, Val} -> {Val, L, C}
+ end;
+from_form({ann_type, _L, [_Var, Type]}, S, D, L, C) ->
+ from_form(Type, S, D, L, C);
+from_form({paren_type, _L, [Type]}, S, D, L, C) ->
+ from_form(Type, S, D, L, C);
+from_form({remote_type, _L, [{atom, _, Module}, {atom, _, Type}, Args]},
+ S, D, L, C) ->
+ remote_from_form(Module, Type, Args, S, D, L, C);
+from_form({atom, _L, Atom}, _S, _D, L, C) ->
+ {t_atom(Atom), L, C};
+from_form({integer, _L, Int}, _S, _D, L, C) ->
+ {t_integer(Int), L, C};
+from_form({op, _L, _Op, _Arg} = Op, _S, _D, L, C) ->
+ case erl_eval:partial_eval(Op) of
+ {integer, _, Val} ->
+ {t_integer(Val), L, C};
+ _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])})
+ end;
+from_form({op, _L, _Op, _Arg1, _Arg2} = Op, _S, _D, L, C) ->
+ case erl_eval:partial_eval(Op) of
+ {integer, _, Val} ->
+ {t_integer(Val), L, C};
+ _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])})
+ end;
+from_form({type, _L, any, []}, _S, _D, L, C) ->
+ {t_any(), L, C};
+from_form({type, _L, arity, []}, _S, _D, L, C) ->
+ {t_arity(), L, C};
+from_form({type, _L, atom, []}, _S, _D, L, C) ->
+ {t_atom(), L, C};
+from_form({type, _L, binary, []}, _S, _D, L, C) ->
+ {t_binary(), L, C};
+from_form({type, _L, binary, [Base, Unit]} = Type, _S, _D, L, C) ->
+ case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of
+ {{integer, _, B}, {integer, _, U}} when B >= 0, U >= 0 ->
+ {t_bitstr(U, B), L, C};
+ _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])})
+ end;
+from_form({type, _L, bitstring, []}, _S, _D, L, C) ->
+ {t_bitstr(), L, C};
+from_form({type, _L, bool, []}, _S, _D, L, C) ->
+ {t_boolean(), L, C}; % XXX: Temporarily
+from_form({type, _L, boolean, []}, _S, _D, L, C) ->
+ {t_boolean(), L, C};
+from_form({type, _L, byte, []}, _S, _D, L, C) ->
+ {t_byte(), L, C};
+from_form({type, _L, char, []}, _S, _D, L, C) ->
+ {t_char(), L, C};
+from_form({type, _L, float, []}, _S, _D, L, C) ->
+ {t_float(), L, C};
+from_form({type, _L, function, []}, _S, _D, L, C) ->
+ {t_fun(), L, C};
+from_form({type, _L, 'fun', []}, _S, _D, L, C) ->
+ {t_fun(), L, C};
+from_form({type, _L, 'fun', [{type, _, any}, Range]}, S, D, L, C) ->
+ {T, L1, C1} = from_form(Range, S, D - 1, L - 1, C),
+ {t_fun(T), L1, C1};
+from_form({type, _L, 'fun', [{type, _, product, Domain}, Range]},
+ S, D, L, C) ->
+ {Dom1, L1, C1} = list_from_form(Domain, S, D, L, C),
+ {Ran1, L2, C2} = from_form(Range, S, D, L1, C1),
+ {t_fun(Dom1, Ran1), L2, C2};
+from_form({type, _L, identifier, []}, _S, _D, L, C) ->
+ {t_identifier(), L, C};
+from_form({type, _L, integer, []}, _S, _D, L, C) ->
+ {t_integer(), L, C};
+from_form({type, _L, iodata, []}, _S, _D, L, C) ->
+ {t_iodata(), L, C};
+from_form({type, _L, iolist, []}, _S, _D, L, C) ->
+ {t_iolist(), L, C};
+from_form({type, _L, list, []}, _S, _D, L, C) ->
+ {t_list(), L, C};
+from_form({type, _L, list, [Type]}, S, D, L, C) ->
+ {T, L1, C1} = from_form(Type, S, D - 1, L - 1, C),
+ {t_list(T), L1, C1};
+from_form({type, _L, map, any}, S, D, L, C) ->
+ builtin_type(map, t_map(), S, D, L, C);
+from_form({type, _L, map, List}, S, D0, L, C) ->
+ {Pairs1, L5, C5} =
+ fun PairsFromForm(_, L1, C1) when L1 =< 0 -> {[{?any,?opt,?any}], L1, C1};
+ PairsFromForm([], L1, C1) -> {[], L1, C1};
+ PairsFromForm([{type, _, Oper, [KF, VF]}|T], L1, C1) ->
+ D = D0 - 1,
+ {Key, L2, C2} = from_form(KF, S, D, L1, C1),
+ {Val, L3, C3} = from_form(VF, S, D, L2, C2),
+ {Pairs0, L4, C4} = PairsFromForm(T, L3 - 1, C3),
+ case Oper of
+ map_field_assoc -> {[{Key,?opt, Val}|Pairs0], L4, C4};
+ map_field_exact -> {[{Key,?mand,Val}|Pairs0], L4, C4}
+ end
+ end(List, L, C),
+ try
+ {Pairs, DefK, DefV} = map_from_form(Pairs1, [], [], [], ?none, ?none),
+ {t_map(Pairs, DefK, DefV), L5, C5}
+ catch none -> {t_none(), L5, C5}
+ end;
+from_form({type, _L, mfa, []}, _S, _D, L, C) ->
+ {t_mfa(), L, C};
+from_form({type, _L, module, []}, _S, _D, L, C) ->
+ {t_module(), L, C};
+from_form({type, _L, nil, []}, _S, _D, L, C) ->
+ {t_nil(), L, C};
+from_form({type, _L, neg_integer, []}, _S, _D, L, C) ->
+ {t_neg_integer(), L, C};
+from_form({type, _L, non_neg_integer, []}, _S, _D, L, C) ->
+ {t_non_neg_integer(), L, C};
+from_form({type, _L, no_return, []}, _S, _D, L, C) ->
+ {t_unit(), L, C};
+from_form({type, _L, node, []}, _S, _D, L, C) ->
+ {t_node(), L, C};
+from_form({type, _L, none, []}, _S, _D, L, C) ->
+ {t_none(), L, C};
+from_form({type, _L, nonempty_list, []}, _S, _D, L, C) ->
+ {t_nonempty_list(), L, C};
+from_form({type, _L, nonempty_list, [Type]}, S, D, L, C) ->
+ {T, L1, C1} = from_form(Type, S, D, L - 1, C),
+ {t_nonempty_list(T), L1, C1};
+from_form({type, _L, nonempty_improper_list, [Cont, Term]}, S, D, L, C) ->
+ {T1, L1, C1} = from_form(Cont, S, D, L - 1, C),
+ {T2, L2, C2} = from_form(Term, S, D, L1, C1),
+ {t_cons(T1, T2), L2, C2};
+from_form({type, _L, nonempty_maybe_improper_list, []}, _S, _D, L, C) ->
+ {t_cons(?any, ?any), L, C};
+from_form({type, _L, nonempty_maybe_improper_list, [Cont, Term]},
+ S, D, L, C) ->
+ {T1, L1, C1} = from_form(Cont, S, D, L - 1, C),
+ {T2, L2, C2} = from_form(Term, S, D, L1, C1),
+ {t_cons(T1, T2), L2, C2};
+from_form({type, _L, nonempty_string, []}, _S, _D, L, C) ->
+ {t_nonempty_string(), L, C};
+from_form({type, _L, number, []}, _S, _D, L, C) ->
+ {t_number(), L, C};
+from_form({type, _L, pid, []}, _S, _D, L, C) ->
+ {t_pid(), L, C};
+from_form({type, _L, port, []}, _S, _D, L, C) ->
+ {t_port(), L, C};
+from_form({type, _L, pos_integer, []}, _S, _D, L, C) ->
+ {t_pos_integer(), L, C};
+from_form({type, _L, maybe_improper_list, []}, _S, _D, L, C) ->
+ {t_maybe_improper_list(), L, C};
+from_form({type, _L, maybe_improper_list, [Content, Termination]},
+ S, D, L, C) ->
+ {T1, L1, C1} = from_form(Content, S, D, L - 1, C),
+ {T2, L2, C2} = from_form(Termination, S, D, L1, C1),
+ {t_maybe_improper_list(T1, T2), L2, C2};
+from_form({type, _L, product, Elements}, S, D, L, C) ->
+ {Lst, L1, C1} = list_from_form(Elements, S, D - 1, L, C),
+ {t_product(Lst), L1, C1};
+from_form({type, _L, range, [From, To]} = Type, _S, _D, L, C) ->
+ case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of
+ {{integer, _, FromVal}, {integer, _, ToVal}} ->
+ {t_from_range(FromVal, ToVal), L, C};
+ _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])})
+ end;
+from_form({type, _L, record, [Name|Fields]}, S, D, L, C) ->
+ record_from_form(Name, Fields, S, D, L, C);
+from_form({type, _L, reference, []}, _S, _D, L, C) ->
+ {t_reference(), L, C};
+from_form({type, _L, string, []}, _S, _D, L, C) ->
+ {t_string(), L, C};
+from_form({type, _L, term, []}, _S, _D, L, C) ->
+ {t_any(), L, C};
+from_form({type, _L, timeout, []}, _S, _D, L, C) ->
+ {t_timeout(), L, C};
+from_form({type, _L, tuple, any}, _S, _D, L, C) ->
+ {t_tuple(), L, C};
+from_form({type, _L, tuple, Args}, S, D, L, C) ->
+ {Lst, L1, C1} = list_from_form(Args, S, D - 1, L, C),
+ {t_tuple(Lst), L1, C1};
+from_form({type, _L, union, Args}, S, D, L, C) ->
+ {Lst, L1, C1} = list_from_form(Args, S, D, L, C),
+ {t_sup(Lst), L1, C1};
+from_form({user_type, _L, Name, Args}, S, D, L, C) ->
+ type_from_form(Name, Args, S, D, L, C);
+from_form({type, _L, Name, Args}, S, D, L, C) ->
+ %% Compatibility: modules compiled before Erlang/OTP 18.0.
+ type_from_form(Name, Args, S, D, L, C);
+from_form({opaque, _L, Name, {Mod, Args, Rep}}, _S, _D, L, C) ->
+ %% XXX. To be removed.
+ {t_opaque(Mod, Name, Args, Rep), L, C}.
+
+builtin_type(Name, Type, S, D, L, C) ->
+ #from_form{site = Site, mrecs = MR} = S,
+ M = site_module(Site),
+ case dict:find(M, MR) of
+ {ok, R} ->
+ case lookup_type(Name, 0, R) of
+ {_, {{_M, _FL, _F, _A}, _T}} ->
+ type_from_form(Name, [], S, D, L, C);
+ error ->
+ {Type, L, C}
+ end;
+ error ->
+ {Type, L, C}
+ end.
+
+type_from_form(Name, Args, S, D, L, C) ->
+ #from_form{site = Site, mrecs = MR, tnames = TypeNames} = S,
+ ArgsLen = length(Args),
+ Module = site_module(Site),
+ TypeName = {type, {Module, Name, ArgsLen}},
+ case can_unfold_more(TypeName, TypeNames) of
+ true ->
+ {ok, R} = dict:find(Module, MR),
+ type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames,
+ S, D, L, C);
+ false ->
+ {t_any(), L, C}
+ end.
+
+type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) ->
+ case lookup_type(Name, ArgsLen, R) of
+ {Tag, {{Module, _FileName, Form, ArgNames}, Type}} ->
+ NewTypeNames = [TypeName|TypeNames],
+ S1 = S#from_form{tnames = NewTypeNames},
+ {ArgTypes, L1, C1} = list_from_form(Args, S1, D, L, C),
+ CKey = cache_key(Module, Name, ArgTypes, TypeNames, D),
+ case cache_find(CKey, C) of
+ {CachedType, DeltaL} ->
+ {CachedType, L1 - DeltaL, C};
+ error ->
+ List = lists:zip(ArgNames, ArgTypes),
+ TmpV = maps:from_list(List),
+ S2 = S1#from_form{site = TypeName, vtab = TmpV},
+ Fun = fun(DD, LL) -> from_form(Form, S2, DD, LL, C1) end,
+ {NewType, L3, C3} =
+ case Tag of
+ type ->
+ recur_limit(Fun, D, L1, TypeName, TypeNames);
+ opaque ->
+ {Rep, L2, C2} = recur_limit(Fun, D, L1, TypeName, TypeNames),
+ Rep1 = choose_opaque_type(Rep, Type),
+ Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of
+ true -> Rep1;
+ false ->
+ ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
+ t_opaque(Module, Name, ArgTypes2, Rep1)
+ end,
+ {Rep2, L2, C2}
+ end,
+ C4 = cache_put(CKey, NewType, L1 - L3, C3),
+ {NewType, L3, C4}
+ end;
+ error ->
+ Msg = io_lib:format("Unable to find type ~w/~w\n",
+ [Name, ArgsLen]),
+ throw({error, Msg})
+ end.
+
+remote_from_form(RemMod, Name, Args, S, D, L, C) ->
+ #from_form{xtypes = ET, mrecs = MR, tnames = TypeNames} = S,
+ if
+ ET =:= replace_by_none ->
+ {t_none(), L, C};
+ true ->
+ ArgsLen = length(Args),
+ MFA = {RemMod, Name, ArgsLen},
+ case dict:find(RemMod, MR) of
+ error ->
+ self() ! {self(), ext_types, MFA},
+ {t_any(), L, C};
+ {ok, RemDict} ->
+ case sets:is_element(MFA, ET) of
+ true ->
+ RemType = {type, MFA},
+ case can_unfold_more(RemType, TypeNames) of
+ true ->
+ remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict,
+ RemType, TypeNames, S, D, L, C);
+ false ->
+ {t_any(), L, C}
+ end;
+ false ->
+ self() ! {self(), ext_types, {RemMod, Name, ArgsLen}},
+ {t_any(), L, C}
+ end
+ end
+ end.
+
+remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames,
+ S, D, L, C) ->
+ case lookup_type(Name, ArgsLen, RemDict) of
+ {Tag, {{Mod, _FileLine, Form, ArgNames}, Type}} ->
+ NewTypeNames = [RemType|TypeNames],
+ S1 = S#from_form{tnames = NewTypeNames},
+ {ArgTypes, L1, C1} = list_from_form(Args, S1, D, L, C),
+ CKey = cache_key(RemMod, Name, ArgTypes, TypeNames, D),
+ %% case error of
+ case cache_find(CKey, C) of
+ {CachedType, DeltaL} ->
+ {CachedType, L - DeltaL, C};
+ error ->
+ List = lists:zip(ArgNames, ArgTypes),
+ TmpVarTab = maps:from_list(List),
+ S2 = S1#from_form{site = RemType, vtab = TmpVarTab},
+ Fun = fun(DD, LL) -> from_form(Form, S2, DD, LL, C1) end,
+ {NewType, L3, C3} =
+ case Tag of
+ type ->
+ recur_limit(Fun, D, L1, RemType, TypeNames);
+ opaque ->
+ {NewRep, L2, C2} = recur_limit(Fun, D, L1, RemType, TypeNames),
+ NewRep1 = choose_opaque_type(NewRep, Type),
+ NewRep2 =
+ case cannot_have_opaque(NewRep1, RemType, TypeNames) of
+ true -> NewRep1;
+ false ->
+ ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
+ t_opaque(Mod, Name, ArgTypes2, NewRep1)
+ end,
+ {NewRep2, L2, C2}
+ end,
+ C4 = cache_put(CKey, NewType, L1 - L3, C3),
+ {NewType, L3, C4}
+ end;
+ error ->
+ Msg = io_lib:format("Unable to find remote type ~w:~w()\n",
+ [RemMod, Name]),
+ throw({error, Msg})
+ end.
+
+subst_all_vars_to_any_list(Types) ->
+ [subst_all_vars_to_any(Type) || Type <- Types].
+
+%% Opaque types (both local and remote) are problematic when it comes
+%% to the limits (TypeNames, D, and L). The reason is that if any() is
+%% substituted for a more specialized subtype of an opaque type, the
+%% property stated along with decorate_with_opaque() (the type has to
+%% be a subtype of the declared type) no longer holds.
+%%
+%% The less than perfect remedy: if the opaque type created from a
+%% form is not a subset of the declared type, the declared type is
+%% used instead, effectively bypassing the limits, and potentially
+%% resulting in huge types.
+choose_opaque_type(Type, DeclType) ->
+ case
+ t_is_subtype(subst_all_vars_to_any(Type),
+ subst_all_vars_to_any(DeclType))
+ of
+ true -> Type;
+ false -> DeclType
+ end.
+
+record_from_form({atom, _, Name}, ModFields, S, D0, L0, C) ->
+ #from_form{site = Site, mrecs = MR, tnames = TypeNames} = S,
+ RecordType = {record, Name},
+ case can_unfold_more(RecordType, TypeNames) of
+ true ->
+ M = site_module(Site),
+ {ok, R} = dict:find(M, MR),
+ case lookup_record(Name, R) of
+ {ok, DeclFields} ->
+ NewTypeNames = [RecordType|TypeNames],
+ Site1 = {record, {M, Name, length(DeclFields)}},
+ S1 = S#from_form{site = Site1, tnames = NewTypeNames},
+ Fun = fun(D, L) ->
+ {GetModRec, L1, C1} =
+ get_mod_record(ModFields, DeclFields, S1, D, L, C),
+ case GetModRec of
+ {error, FieldName} ->
+ throw({error,
+ io_lib:format("Illegal declaration of #~w{~w}\n",
+ [Name, FieldName])});
+ {ok, NewFields} ->
+ S2 = S1#from_form{vtab = var_table__new()},
+ {NewFields1, L2, C2} =
+ fields_from_form(NewFields, S2, D, L1, C1),
+ Rec = t_tuple(
+ [t_atom(Name)|[Type
+ || {_FieldName, Type} <- NewFields1]]),
+ {Rec, L2, C2}
+ end
+ end,
+ recur_limit(Fun, D0, L0, RecordType, TypeNames);
+ error ->
+ throw({error, io_lib:format("Unknown record #~w{}\n", [Name])})
+ end;
+ false ->
+ {t_any(), L0, C}
+ end.
+
+get_mod_record([], DeclFields, _S, _D, L, C) ->
+ {{ok, DeclFields}, L, C};
+get_mod_record(ModFields, DeclFields, S, D, L, C) ->
+ DeclFieldsDict = lists:keysort(1, DeclFields),
+ {ModFieldsDict, L1, C1} = build_field_dict(ModFields, S, D, L, C),
+ case get_mod_record_types(DeclFieldsDict, ModFieldsDict, []) of
+ {error, _FieldName} = Error -> {Error, L1, C1};
+ {ok, FinalKeyDict} ->
+ Fields = [lists:keyfind(FieldName, 1, FinalKeyDict)
+ || {FieldName, _, _} <- DeclFields],
+ {{ok, Fields}, L1, C1}
+ end.
+
+build_field_dict(FieldTypes, S, D, L, C) ->
+ build_field_dict(FieldTypes, S, D, L, C, []).
+
+build_field_dict([{type, _, field_type, [{atom, _, Name}, Type]}|Left],
+ S, D, L, C, Acc) ->
+ {T, L1, C1} = from_form(Type, S, D, L - 1, C),
+ NewAcc = [{Name, Type, T}|Acc],
+ build_field_dict(Left, S, D, L1, C1, NewAcc);
+build_field_dict([], _S, _D, L, C, Acc) ->
+ {lists:keysort(1, Acc), L, C}.
+
+get_mod_record_types([{FieldName, _Abstr, _DeclType}|Left1],
+ [{FieldName, TypeForm, ModType}|Left2],
+ Acc) ->
+ get_mod_record_types(Left1, Left2, [{FieldName, TypeForm, ModType}|Acc]);
+get_mod_record_types([{FieldName1, _Abstr, _DeclType} = DT|Left1],
+ [{FieldName2, _FormType, _ModType}|_] = List2,
+ Acc) when FieldName1 < FieldName2 ->
+ get_mod_record_types(Left1, List2, [DT|Acc]);
+get_mod_record_types(Left1, [], Acc) ->
+ {ok, lists:keysort(1, Left1++Acc)};
+get_mod_record_types(_, [{FieldName2, _FormType, _ModType}|_], _Acc) ->
+ {error, FieldName2}.
+
+%% It is important to create a limited version of the record type
+%% since nested record types can otherwise easily result in huge
+%% terms.
+fields_from_form([], _S, _D, L, C) ->
+ {[], L, C};
+fields_from_form([{Name, Abstr, _Type}|Tail], S, D, L, C) ->
+ {T, L1, C1} = from_form(Abstr, S, D, L, C),
+ {F, L2, C2} = fields_from_form(Tail, S, D, L1, C1),
+ {[{Name, T}|F], L2, C2}.
+
+list_from_form([], _S, _D, L, C) ->
+ {[], L, C};
+list_from_form([H|Tail], S, D, L, C) ->
+ {H1, L1, C1} = from_form(H, S, D, L - 1, C),
+ {T1, L2, C2} = list_from_form(Tail, S, D, L1, C1),
+ {[H1|T1], L2, C2}.
+
+%% Sorts, combines non-singleton pairs, and applies precendence and
+%% mandatoriness rules.
+map_from_form([], ShdwPs, MKs, Pairs, DefK, DefV) ->
+ verify_possible(MKs, ShdwPs),
+ {promote_to_mand(MKs, Pairs), DefK, DefV};
+map_from_form([{SKey,MNess,Val}|SPairs], ShdwPs0, MKs0, Pairs0, DefK0, DefV0) ->
+ Key = lists:foldl(fun({K,_},S)->t_subtract(S,K)end, SKey, ShdwPs0),
+ ShdwPs = case Key of ?none -> ShdwPs0; _ -> [{Key,Val}|ShdwPs0] end,
+ MKs = case MNess of ?mand -> [SKey|MKs0]; ?opt -> MKs0 end,
+ if MNess =:= ?mand, SKey =:= ?none -> throw(none);
+ true -> ok
+ end,
+ {Pairs, DefK, DefV} =
+ case is_singleton_type(Key) of
+ true ->
+ MNess1 = case Val =:= ?none of true -> ?opt; false -> MNess end,
+ {mapdict_insert({Key,MNess1,Val}, Pairs0), DefK0, DefV0};
+ false ->
+ case Key =:= ?none orelse Val =:= ?none of
+ true -> {Pairs0, DefK0, DefV0};
+ false -> {Pairs0, t_sup(DefK0, Key), t_sup(DefV0, Val)}
+ end
+ end,
+ map_from_form(SPairs, ShdwPs, MKs, Pairs, DefK, DefV).
+
+%% Verifies that all mandatory keys are possible, throws 'none' otherwise
+verify_possible(MKs, ShdwPs) ->
+ lists:foreach(fun(M) -> verify_possible_1(M, ShdwPs) end, MKs).
+
+verify_possible_1(M, ShdwPs) ->
+ case lists:any(fun({K,_}) -> t_inf(M, K) =/= ?none end, ShdwPs) of
+ true -> ok;
+ false -> throw(none)
+ end.
+
+-spec promote_to_mand([erl_type()], t_map_dict()) -> t_map_dict().
+
+promote_to_mand(_, []) -> [];
+promote_to_mand(MKs, [E={K,_,V}|T]) ->
+ [case lists:any(fun(M) -> t_is_equal(K,M) end, MKs) of
+ true -> {K, ?mand, V};
+ false -> E
+ end|promote_to_mand(MKs, T)].
+
+-define(RECUR_EXPAND_LIMIT, 10).
+-define(RECUR_EXPAND_DEPTH, 2).
+
+%% If more of the limited resources is spent on the non-recursive
+%% forms, more warnings are found. And the analysis is also a bit
+%% faster.
+%%
+%% Setting REC_TYPE_LIMIT to 1 would work also work well.
+
+recur_limit(Fun, D, L, _, _) when L =< ?RECUR_EXPAND_DEPTH,
+ D =< ?RECUR_EXPAND_LIMIT ->
+ Fun(D, L);
+recur_limit(Fun, D, L, TypeName, TypeNames) ->
+ case is_recursive(TypeName, TypeNames) of
+ true ->
+ {T, L1, C1} = Fun(?RECUR_EXPAND_DEPTH, ?RECUR_EXPAND_LIMIT),
+ {T, L - L1, C1};
+ false ->
+ Fun(D, L)
+ end.
+
+-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(),
+ mod_records(), var_table(), cache()) -> cache().
+
+t_check_record_fields(Form, ExpTypes, Site, RecDict, VarTable, Cache) ->
+ State = #from_form{site = Site,
+ xtypes = ExpTypes,
+ mrecs = RecDict,
+ vtab = VarTable,
+ tnames = []},
+ check_record_fields(Form, State, Cache).
+
+-spec check_record_fields(parse_form(), #from_form{}, cache()) -> cache().
+
+%% If there is something wrong with parse_form()
+%% throw({error, io_lib:chars()} is called.
+
+check_record_fields({var, _L, _}, _S, C) -> C;
+check_record_fields({ann_type, _L, [_Var, Type]}, S, C) ->
+ check_record_fields(Type, S, C);
+check_record_fields({paren_type, _L, [Type]}, S, C) ->
+ check_record_fields(Type, S, C);
+check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
+ S, C) ->
+ list_check_record_fields(Args, S, C);
+check_record_fields({atom, _L, _}, _S, C) -> C;
+check_record_fields({integer, _L, _}, _S, C) -> C;
+check_record_fields({op, _L, _Op, _Arg}, _S, C) -> C;
+check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _S, C) -> C;
+check_record_fields({type, _L, tuple, any}, _S, C) -> C;
+check_record_fields({type, _L, map, any}, _S, C) -> C;
+check_record_fields({type, _L, binary, [_Base, _Unit]}, _S, C) -> C;
+check_record_fields({type, _L, 'fun', [{type, _, any}, Range]}, S, C) ->
+ check_record_fields(Range, S, C);
+check_record_fields({type, _L, range, [_From, _To]}, _S, C) -> C;
+check_record_fields({type, _L, record, [Name|Fields]}, S, C) ->
+ check_record(Name, Fields, S, C);
+check_record_fields({type, _L, _, Args}, S, C) ->
+ list_check_record_fields(Args, S, C);
+check_record_fields({user_type, _L, _Name, Args}, S, C) ->
+ list_check_record_fields(Args, S, C).
+
+check_record({atom, _, Name}, ModFields, S, C) ->
+ #from_form{site = Site, mrecs = MR} = S,
+ M = site_module(Site),
+ {ok, R} = dict:find(M, MR),
+ {ok, DeclFields} = lookup_record(Name, R),
+ case check_fields(Name, ModFields, DeclFields, S, C) of
+ {error, FieldName} ->
+ throw({error, io_lib:format("Illegal declaration of #~w{~w}\n",
+ [Name, FieldName])});
+ C1 -> C1
+ end.
+
+check_fields(RecName, [{type, _, field_type, [{atom, _, Name}, Abstr]}|Left],
+ DeclFields, S, C) ->
+ #from_form{site = Site0, xtypes = ET, mrecs = MR, vtab = V} = S,
+ M = site_module(Site0),
+ Site = {record, {M, RecName, length(DeclFields)}},
+ {Type, C1} = t_from_form(Abstr, ET, Site, MR, V, C),
+ {Name, _, DeclType} = lists:keyfind(Name, 1, DeclFields),
+ TypeNoVars = subst_all_vars_to_any(Type),
+ case t_is_subtype(TypeNoVars, DeclType) of
+ false -> {error, Name};
+ true -> check_fields(RecName, Left, DeclFields, S, C1)
+ end;
+check_fields(_RecName, [], _Decl, _S, C) ->
+ C.
+
+list_check_record_fields([], _S, C) ->
+ C;
+list_check_record_fields([H|Tail], S, C) ->
+ C1 = check_record_fields(H, S, C),
+ list_check_record_fields(Tail, S, C1).
+
+site_module({_, {Module, _, _}}) ->
+ Module.
+
+-spec cache__new() -> cache().
+
+cache__new() ->
+ maps:new().
+
+-spec cache_key(module(), atom(), [erl_type()],
+ type_names(), expand_depth()) -> cache_key().
+
+%% If TypeNames is left out from the key, the cache is smaller, and
+%% the form-to-type translation is faster. But it would be a shame if,
+%% for example, any() is used, where a more complex type should be
+%% used. There is also a slight risk of creating unnecessarily big
+%% types.
+
+cache_key(Module, Name, ArgTypes, TypeNames, D) ->
+ {Module, Name, D, ArgTypes, TypeNames}.
+
+-spec cache_find(cache_key(), cache()) ->
+ {erl_type(), expand_limit()} | 'error'.
+
+cache_find(Key, Cache) ->
+ case maps:find(Key, Cache) of
+ {ok, Value} ->
+ Value;
+ error ->
+ error
+ end.
+
+-spec cache_put(cache_key(), erl_type(), expand_limit(), cache()) -> cache().
+
+cache_put(_Key, _Type, DeltaL, Cache) when DeltaL < 0 ->
+ %% The type is truncated; do not reuse it.
+ Cache;
+cache_put(Key, Type, DeltaL, Cache) ->
+ maps:put(Key, {Type, DeltaL}, Cache).
+
+-spec t_var_names([erl_type()]) -> [atom()].
+
+t_var_names([{var, _, Name}|L]) when L =/= '_' ->
+ [Name|t_var_names(L)];
+t_var_names([]) ->
+ [].
+
+-spec t_form_to_string(parse_form()) -> string().
+
+t_form_to_string({var, _L, '_'}) -> "_";
+t_form_to_string({var, _L, Name}) -> atom_to_list(Name);
+t_form_to_string({atom, _L, Atom}) ->
+ io_lib:write_string(atom_to_list(Atom), $'); % To quote or not to quote... '
+t_form_to_string({integer, _L, Int}) -> integer_to_list(Int);
+t_form_to_string({op, _L, _Op, _Arg} = Op) ->
+ case erl_eval:partial_eval(Op) of
+ {integer, _, _} = Int -> t_form_to_string(Int);
+ _ -> io_lib:format("Badly formed type ~w", [Op])
+ end;
+t_form_to_string({op, _L, _Op, _Arg1, _Arg2} = Op) ->
+ case erl_eval:partial_eval(Op) of
+ {integer, _, _} = Int -> t_form_to_string(Int);
+ _ -> io_lib:format("Badly formed type ~w", [Op])
+ end;
+t_form_to_string({ann_type, _L, [Var, Type]}) ->
+ t_form_to_string(Var) ++ "::" ++ t_form_to_string(Type);
+t_form_to_string({paren_type, _L, [Type]}) ->
+ flat_format("(~s)", [t_form_to_string(Type)]);
+t_form_to_string({remote_type, _L, [{atom, _, Mod}, {atom, _, Name}, Args]}) ->
+ ArgString = "(" ++ string:join(t_form_to_string_list(Args), ",") ++ ")",
+ flat_format("~w:~w", [Mod, Name]) ++ ArgString;
+t_form_to_string({type, _L, arity, []}) -> "arity()";
+t_form_to_string({type, _L, binary, []}) -> "binary()";
+t_form_to_string({type, _L, binary, [Base, Unit]} = Type) ->
+ case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of
+ {{integer, _, B}, {integer, _, U}} ->
+ %% the following mirrors the clauses of t_to_string/2
+ case {U, B} of
+ {0, 0} -> "<<>>";
+ {8, 0} -> "binary()";
+ {1, 0} -> "bitstring()";
+ {0, B} -> flat_format("<<_:~w>>", [B]);
+ {U, 0} -> flat_format("<<_:_*~w>>", [U]);
+ {U, B} -> flat_format("<<_:~w,_:_*~w>>", [B, U])
+ end;
+ _ -> io_lib:format("Badly formed bitstr type ~w", [Type])
+ end;
+t_form_to_string({type, _L, bitstring, []}) -> "bitstring()";
+t_form_to_string({type, _L, 'fun', []}) -> "fun()";
+t_form_to_string({type, _L, 'fun', [{type, _, any}, Range]}) ->
+ "fun(...) -> " ++ t_form_to_string(Range);
+t_form_to_string({type, _L, 'fun', [{type, _, product, Domain}, Range]}) ->
+ "fun((" ++ string:join(t_form_to_string_list(Domain), ",") ++ ") -> "
+ ++ t_form_to_string(Range) ++ ")";
+t_form_to_string({type, _L, iodata, []}) -> "iodata()";
+t_form_to_string({type, _L, iolist, []}) -> "iolist()";
+t_form_to_string({type, _L, list, [Type]}) ->
+ "[" ++ t_form_to_string(Type) ++ "]";
+t_form_to_string({type, _L, map, any}) -> "map()";
+t_form_to_string({type, _L, map, Args}) ->
+ "#{" ++ string:join(t_form_to_string_list(Args), ",") ++ "}";
+t_form_to_string({type, _L, map_field_assoc, [Key, Val]}) ->
+ t_form_to_string(Key) ++ "=>" ++ t_form_to_string(Val);
+t_form_to_string({type, _L, map_field_exact, [Key, Val]}) ->
+ t_form_to_string(Key) ++ ":=" ++ t_form_to_string(Val);
+t_form_to_string({type, _L, mfa, []}) -> "mfa()";
+t_form_to_string({type, _L, module, []}) -> "module()";
+t_form_to_string({type, _L, node, []}) -> "node()";
+t_form_to_string({type, _L, nonempty_list, [Type]}) ->
+ "[" ++ t_form_to_string(Type) ++ ",...]";
+t_form_to_string({type, _L, nonempty_string, []}) -> "nonempty_string()";
+t_form_to_string({type, _L, product, Elements}) ->
+ "<" ++ string:join(t_form_to_string_list(Elements), ",") ++ ">";
+t_form_to_string({type, _L, range, [From, To]} = Type) ->
+ case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of
+ {{integer, _, FromVal}, {integer, _, ToVal}} ->
+ flat_format("~w..~w", [FromVal, ToVal]);
+ _ -> flat_format("Badly formed type ~w",[Type])
+ end;
+t_form_to_string({type, _L, record, [{atom, _, Name}]}) ->
+ flat_format("#~w{}", [Name]);
+t_form_to_string({type, _L, record, [{atom, _, Name}|Fields]}) ->
+ FieldString = string:join(t_form_to_string_list(Fields), ","),
+ flat_format("#~w{~s}", [Name, FieldString]);
+t_form_to_string({type, _L, field_type, [{atom, _, Name}, Type]}) ->
+ flat_format("~w::~s", [Name, t_form_to_string(Type)]);
+t_form_to_string({type, _L, term, []}) -> "term()";
+t_form_to_string({type, _L, timeout, []}) -> "timeout()";
+t_form_to_string({type, _L, tuple, any}) -> "tuple()";
+t_form_to_string({type, _L, tuple, Args}) ->
+ "{" ++ string:join(t_form_to_string_list(Args), ",") ++ "}";
+t_form_to_string({type, _L, union, Args}) ->
+ string:join(t_form_to_string_list(Args), " | ");
+t_form_to_string({type, _L, Name, []} = T) ->
+ try
+ M = mod,
+ D0 = dict:new(),
+ MR = dict:from_list([{M, D0}]),
+ Site = {type, {M,Name,0}},
+ V = var_table__new(),
+ C = cache__new(),
+ State = #from_form{site = Site,
+ xtypes = sets:new(),
+ mrecs = MR,
+ vtab = V,
+ tnames = []},
+ {T1, _, _} = from_form(T, State, _Deep=1000, _ALot=1000000, C),
+ t_to_string(T1)
+ catch throw:{error, _} -> atom_to_string(Name) ++ "()"
+ end;
+t_form_to_string({user_type, _L, Name, List}) ->
+ flat_format("~w(~s)",
+ [Name, string:join(t_form_to_string_list(List), ",")]);
+t_form_to_string({type, L, Name, List}) ->
+ %% Compatibility: modules compiled before Erlang/OTP 18.0.
+ t_form_to_string({user_type, L, Name, List}).
+
+t_form_to_string_list(List) ->
+ t_form_to_string_list(List, []).
+
+t_form_to_string_list([H|T], Acc) ->
+ t_form_to_string_list(T, [t_form_to_string(H)|Acc]);
+t_form_to_string_list([], Acc) ->
+ lists:reverse(Acc).
+
+-spec atom_to_string(atom()) -> string().
+
+atom_to_string(Atom) ->
+ flat_format("~w", [Atom]).
+
+%%=============================================================================
+%%
+%% Utilities
+%%
+%%=============================================================================
+
+-spec any_none([erl_type()]) -> boolean().
+
+any_none([?none|_Left]) -> true;
+any_none([_|Left]) -> any_none(Left);
+any_none([]) -> false.
+
+-spec any_none_or_unit([erl_type()]) -> boolean().
+
+any_none_or_unit([?none|_]) -> true;
+any_none_or_unit([?unit|_]) -> true;
+any_none_or_unit([_|Left]) -> any_none_or_unit(Left);
+any_none_or_unit([]) -> false.
+
+-spec is_erl_type(any()) -> boolean().
+
+is_erl_type(?any) -> true;
+is_erl_type(?none) -> true;
+is_erl_type(?unit) -> true;
+is_erl_type(#c{}) -> true;
+is_erl_type(_) -> false.
+
+-spec lookup_record(atom(), type_table()) ->
+ 'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
+
+lookup_record(Tag, RecDict) when is_atom(Tag) ->
+ case dict:find({record, Tag}, RecDict) of
+ {ok, {_FileLine, [{_Arity, Fields}]}} ->
+ {ok, Fields};
+ {ok, {_FileLine, List}} when is_list(List) ->
+ %% This will have to do, since we do not know which record we
+ %% are looking for.
+ error;
+ error ->
+ error
+ end.
+
+-spec lookup_record(atom(), arity(), type_table()) ->
+ 'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
+
+lookup_record(Tag, Arity, RecDict) when is_atom(Tag) ->
+ case dict:find({record, Tag}, RecDict) of
+ {ok, {_FileLine, [{Arity, Fields}]}} -> {ok, Fields};
+ {ok, {_FileLine, OrdDict}} -> orddict:find(Arity, OrdDict);
+ error -> error
+ end.
+
+-spec lookup_type(_, _, _) -> {'type' | 'opaque', type_value()} | 'error'.
+lookup_type(Name, Arity, RecDict) ->
+ case dict:find({type, Name, Arity}, RecDict) of
+ error ->
+ case dict:find({opaque, Name, Arity}, RecDict) of
+ error -> error;
+ {ok, Found} -> {opaque, Found}
+ end;
+ {ok, Found} -> {type, Found}
+ end.
+
+-spec type_is_defined('type' | 'opaque', atom(), arity(), type_table()) ->
+ boolean().
+
+type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
+ dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+
+cannot_have_opaque(Type, TypeName, TypeNames) ->
+ t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
+
+is_recursive(TypeName, TypeNames) ->
+ lists:member(TypeName, TypeNames).
+
+can_unfold_more(TypeName, TypeNames) ->
+ Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end,
+ lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT.
+
+-spec do_opaque(erl_type(), opaques(), fun((_) -> T)) -> T.
+
+%% Probably a little faster than calling t_unopaque/2.
+%% Unions that are due to opaque types are unopaqued.
+do_opaque(?opaque(_) = Type, Opaques, Pred) ->
+ case Opaques =:= 'universe' orelse is_opaque_type(Type, Opaques) of
+ true -> do_opaque(t_opaque_structure(Type), Opaques, Pred);
+ false -> Pred(Type)
+ end;
+do_opaque(?union(List) = Type, Opaques, Pred) ->
+ [A,B,F,I,L,N,T,M,O,Map] = List,
+ if O =:= ?none -> Pred(Type);
+ true ->
+ case Opaques =:= 'universe' orelse is_opaque_type(O, Opaques) of
+ true ->
+ S = t_opaque_structure(O),
+ do_opaque(t_sup([A,B,F,I,L,N,T,M,S,Map]), Opaques, Pred);
+ false -> Pred(Type)
+ end
+ end;
+do_opaque(Type, _Opaques, Pred) ->
+ Pred(Type).
+
+map_all_values(?map(Pairs,_,DefV)) ->
+ [DefV|[V || {V, _, _} <- Pairs]].
+
+map_all_keys(?map(Pairs,DefK,_)) ->
+ [DefK|[K || {_, _, K} <- Pairs]].
+
+map_all_types(M) ->
+ map_all_keys(M) ++ map_all_values(M).
+
+%% Tests if a type has exactly one possible value.
+-spec t_is_singleton(erl_type()) -> boolean().
+
+t_is_singleton(Type) ->
+ t_is_singleton(Type, 'universe').
+
+-spec t_is_singleton(erl_type(), opaques()) -> boolean().
+
+t_is_singleton(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun is_singleton_type/1).
+
+%% Incomplete; not all representable singleton types are included.
+is_singleton_type(?nil) -> true;
+is_singleton_type(?atom(?any)) -> false;
+is_singleton_type(?atom(Set)) ->
+ ordsets:size(Set) =:= 1;
+is_singleton_type(?int_range(V, V)) -> true;
+is_singleton_type(?int_set(Set)) ->
+ ordsets:size(Set) =:= 1;
+is_singleton_type(?tuple(Types, Arity, _)) when is_integer(Arity) ->
+ lists:all(fun is_singleton_type/1, Types);
+is_singleton_type(?tuple_set([{Arity, [OnlyTuple]}])) when is_integer(Arity) ->
+ is_singleton_type(OnlyTuple);
+is_singleton_type(?map(Pairs, ?none, ?none)) ->
+ lists:all(fun({_,MNess,V}) -> MNess =:= ?mand andalso is_singleton_type(V)
+ end, Pairs);
+is_singleton_type(_) ->
+ false.
+
+%% Returns the only possible value of a singleton type.
+-spec t_singleton_to_term(erl_type(), opaques()) -> term().
+
+t_singleton_to_term(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun singleton_type_to_term/1).
+
+singleton_type_to_term(?nil) -> [];
+singleton_type_to_term(?atom(Set)) when Set =/= ?any ->
+ case ordsets:size(Set) of
+ 1 -> hd(ordsets:to_list(Set));
+ _ -> error(badarg)
+ end;
+singleton_type_to_term(?int_range(V, V)) -> V;
+singleton_type_to_term(?int_set(Set)) ->
+ case ordsets:size(Set) of
+ 1 -> hd(ordsets:to_list(Set));
+ _ -> error(badarg)
+ end;
+singleton_type_to_term(?tuple(Types, Arity, _)) when is_integer(Arity) ->
+ lists:map(fun singleton_type_to_term/1, Types);
+singleton_type_to_term(?tuple_set([{Arity, [OnlyTuple]}]))
+ when is_integer(Arity) ->
+ singleton_type_to_term(OnlyTuple);
+singleton_type_to_term(?map(Pairs, ?none, ?none)) ->
+ maps:from_list([{singleton_type_to_term(K), singleton_type_to_term(V)}
+ || {K,?mand,V} <- Pairs]).
+
+%% -----------------------------------
+%% Set
+%%
+
+set_singleton(Element) ->
+ ordsets:from_list([Element]).
+
+set_is_singleton(Element, Set) ->
+ set_singleton(Element) =:= Set.
+
+set_is_element(Element, Set) ->
+ ordsets:is_element(Element, Set).
+
+set_union(?any, _) -> ?any;
+set_union(_, ?any) -> ?any;
+set_union(S1, S2) ->
+ case ordsets:union(S1, S2) of
+ S when length(S) =< ?SET_LIMIT -> S;
+ _ -> ?any
+ end.
+
+%% The intersection and subtraction can return ?none.
+%% This should always be handled right away since ?none is not a valid set.
+%% However, ?any is considered a valid set.
+
+set_intersection(?any, S) -> S;
+set_intersection(S, ?any) -> S;
+set_intersection(S1, S2) ->
+ case ordsets:intersection(S1, S2) of
+ [] -> ?none;
+ S -> S
+ end.
+
+set_subtract(_, ?any) -> ?none;
+set_subtract(?any, _) -> ?any;
+set_subtract(S1, S2) ->
+ case ordsets:subtract(S1, S2) of
+ [] -> ?none;
+ S -> S
+ end.
+
+set_from_list(List) ->
+ case length(List) of
+ L when L =< ?SET_LIMIT -> ordsets:from_list(List);
+ L when L > ?SET_LIMIT -> ?any
+ end.
+
+set_to_list(Set) ->
+ ordsets:to_list(Set).
+
+set_filter(Fun, Set) ->
+ case ordsets:filter(Fun, Set) of
+ [] -> ?none;
+ NewSet -> NewSet
+ end.
+
+set_size(Set) ->
+ ordsets:size(Set).
+
+set_to_string(Set) ->
+ L = [case is_atom(X) of
+ true -> io_lib:write_string(atom_to_list(X), $'); % stupid emacs '
+ false -> flat_format("~w", [X])
+ end || X <- set_to_list(Set)],
+ string:join(L, " | ").
+
+set_min([H|_]) -> H.
+
+set_max(Set) ->
+ hd(lists:reverse(Set)).
+
+flat_format(F, S) ->
+ lists:flatten(io_lib:format(F, S)).
+
+%%=============================================================================
+%%
+%% Utilities for the binary type
+%%
+%%=============================================================================
+
+-spec gcd(integer(), integer()) -> integer().
+
+gcd(A, B) when B > A ->
+ gcd1(B, A);
+gcd(A, B) ->
+ gcd1(A, B).
+
+-spec gcd1(integer(), integer()) -> integer().
+
+gcd1(A, 0) -> A;
+gcd1(A, B) ->
+ case A rem B of
+ 0 -> B;
+ X -> gcd1(B, X)
+ end.
+
+-spec bitstr_concat(erl_type(), erl_type()) -> erl_type().
+
+bitstr_concat(?none, _) -> ?none;
+bitstr_concat(_, ?none) -> ?none;
+bitstr_concat(?bitstr(U1, B1), ?bitstr(U2, B2)) ->
+ t_bitstr(gcd(U1, U2), B1+B2).
+
+-spec bitstr_match(erl_type(), erl_type()) -> erl_type().
+
+bitstr_match(?none, _) -> ?none;
+bitstr_match(_, ?none) -> ?none;
+bitstr_match(?bitstr(0, B1), ?bitstr(0, B2)) when B1 =< B2 ->
+ t_bitstr(0, B2-B1);
+bitstr_match(?bitstr(0, _B1), ?bitstr(0, _B2)) ->
+ ?none;
+bitstr_match(?bitstr(0, B1), ?bitstr(U2, B2)) when B1 =< B2 ->
+ t_bitstr(U2, B2-B1);
+bitstr_match(?bitstr(0, B1), ?bitstr(U2, B2)) ->
+ t_bitstr(U2, handle_base(U2, B2-B1));
+bitstr_match(?bitstr(_, B1), ?bitstr(0, B2)) when B1 > B2 ->
+ ?none;
+bitstr_match(?bitstr(U1, B1), ?bitstr(U2, B2)) ->
+ GCD = gcd(U1, U2),
+ t_bitstr(GCD, handle_base(GCD, B2-B1)).
+
+-spec handle_base(integer(), integer()) -> integer().
+
+handle_base(Unit, Pos) when Pos >= 0 ->
+ Pos rem Unit;
+handle_base(Unit, Neg) ->
+ (Unit+(Neg rem Unit)) rem Unit.
+
+family(L) ->
+ R = sofs:relation(L),
+ F = sofs:relation_to_family(R),
+ sofs:to_external(F).
+
+%%=============================================================================
+%%
+%% Interface functions for abstract data types defined in this module
+%%
+%%=============================================================================
+
+-spec var_table__new() -> var_table().
+
+var_table__new() ->
+ maps:new().
+
+%%=============================================================================
+%% Consistency-testing function(s) below
+%%=============================================================================
+
+-ifdef(DO_ERL_TYPES_TEST).
+
+test() ->
+ Atom1 = t_atom(),
+ Atom2 = t_atom(foo),
+ Atom3 = t_atom(bar),
+ true = t_is_atom(Atom2),
+
+ True = t_atom(true),
+ False = t_atom(false),
+ Bool = t_boolean(),
+ true = t_is_boolean(True),
+ true = t_is_boolean(Bool),
+ false = t_is_boolean(Atom1),
+
+ Binary = t_binary(),
+ true = t_is_binary(Binary),
+
+ Bitstr = t_bitstr(),
+ true = t_is_bitstr(Bitstr),
+
+ Bitstr1 = t_bitstr(7, 3),
+ true = t_is_bitstr(Bitstr1),
+ false = t_is_binary(Bitstr1),
+
+ Bitstr2 = t_bitstr(16, 8),
+ true = t_is_bitstr(Bitstr2),
+ true = t_is_binary(Bitstr2),
+
+ ?bitstr(8, 16) = t_subtract(t_bitstr(4, 12), t_bitstr(8, 12)),
+ ?bitstr(8, 16) = t_subtract(t_bitstr(4, 12), t_bitstr(8, 12)),
+
+ Int1 = t_integer(),
+ Int2 = t_integer(1),
+ Int3 = t_integer(16#ffffffff),
+ true = t_is_integer(Int2),
+ true = t_is_byte(Int2),
+ false = t_is_byte(Int3),
+ false = t_is_byte(t_from_range(-1, 1)),
+ true = t_is_byte(t_from_range(1, ?MAX_BYTE)),
+
+ Tuple1 = t_tuple(),
+ Tuple2 = t_tuple(3),
+ Tuple3 = t_tuple([Atom1, Int1]),
+ Tuple4 = t_tuple([Tuple1, Tuple2]),
+ Tuple5 = t_tuple([Tuple3, Tuple4]),
+ Tuple6 = t_limit(Tuple5, 2),
+ Tuple7 = t_limit(Tuple5, 3),
+ true = t_is_tuple(Tuple1),
+
+ Port = t_port(),
+ Pid = t_pid(),
+ Ref = t_reference(),
+ Identifier = t_identifier(),
+ false = t_is_reference(Port),
+ true = t_is_identifier(Port),
+
+ Function1 = t_fun(),
+ Function2 = t_fun(Pid),
+ Function3 = t_fun([], Pid),
+ Function4 = t_fun([Port, Pid], Pid),
+ Function5 = t_fun([Pid, Atom1], Int2),
+ true = t_is_fun(Function3),
+
+ List1 = t_list(),
+ List2 = t_list(t_boolean()),
+ List3 = t_cons(t_boolean(), List2),
+ List4 = t_cons(t_boolean(), t_atom()),
+ List5 = t_cons(t_boolean(), t_nil()),
+ List6 = t_cons_tl(List5),
+ List7 = t_sup(List4, List5),
+ List8 = t_inf(List7, t_list()),
+ List9 = t_cons(),
+ List10 = t_cons_tl(List9),
+ true = t_is_boolean(t_cons_hd(List5)),
+ true = t_is_list(List5),
+ false = t_is_list(List4),
+
+ Product1 = t_product([Atom1, Atom2]),
+ Product2 = t_product([Atom3, Atom1]),
+ Product3 = t_product([Atom3, Atom2]),
+
+ Union1 = t_sup(Atom2, Atom3),
+ Union2 = t_sup(Tuple2, Tuple3),
+ Union3 = t_sup(Int2, Atom3),
+ Union4 = t_sup(Port, Pid),
+ Union5 = t_sup(Union4, Int1),
+ Union6 = t_sup(Function1, Function2),
+ Union7 = t_sup(Function4, Function5),
+ Union8 = t_sup(True, False),
+ true = t_is_boolean(Union8),
+ Union9 = t_sup(Int2, t_integer(2)),
+ true = t_is_byte(Union9),
+ Union10 = t_sup(t_tuple([t_atom(true), ?any]),
+ t_tuple([t_atom(false), ?any])),
+
+ ?any = t_sup(Product3, Function5),
+
+ Atom3 = t_inf(Union3, Atom1),
+ Union2 = t_inf(Union2, Tuple1),
+ Int2 = t_inf(Int1, Union3),
+ Union4 = t_inf(Union4, Identifier),
+ Port = t_inf(Union5, Port),
+ Function4 = t_inf(Union7, Function4),
+ ?none = t_inf(Product2, Atom1),
+ Product3 = t_inf(Product1, Product2),
+ Function5 = t_inf(Union7, Function5),
+ true = t_is_byte(t_inf(Union9, t_number())),
+ true = t_is_char(t_inf(Union9, t_number())),
+
+ io:format("3? ~p ~n", [?int_set([3])]),
+
+ RecDict = dict:store({foo, 2}, [bar, baz], dict:new()),
+ Record1 = t_from_term({foo, [1,2], {1,2,3}}),
+
+ Types = [
+ Atom1,
+ Atom2,
+ Atom3,
+ Binary,
+ Int1,
+ Int2,
+ Tuple1,
+ Tuple2,
+ Tuple3,
+ Tuple4,
+ Tuple5,
+ Tuple6,
+ Tuple7,
+ Ref,
+ Port,
+ Pid,
+ Identifier,
+ List1,
+ List2,
+ List3,
+ List4,
+ List5,
+ List6,
+ List7,
+ List8,
+ List9,
+ List10,
+ Function1,
+ Function2,
+ Function3,
+ Function4,
+ Function5,
+ Product1,
+ Product2,
+ Record1,
+ Union1,
+ Union2,
+ Union3,
+ Union4,
+ Union5,
+ Union6,
+ Union7,
+ Union8,
+ Union10,
+ t_inf(Union10, t_tuple([t_atom(true), t_integer()]))
+ ],
+ io:format("~p\n", [[t_to_string(X, RecDict) || X <- Types]]).
+
+-endif.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl
index c19330eb30..597460ce77 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl
@@ -52,7 +52,7 @@ exact_api_set_type(#exact_api{}=E) -> E.
-record(exact_adt, {}).
exact_adt_test(X) ->
- #exact_adt{} = exact_adt:exact_adt_set_type(X). % breaks the opaqueness
+ #exact_adt{} = exact_adt:exact_adt_set_type(X). % breaks the opacity
exact_adt_new(A) ->
A = #exact_adt{},
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl
index 2b157483bc..b906431b44 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl
@@ -16,11 +16,11 @@ ri11() ->
ri13() ->
A = simple1_adt:d1(),
- if is_record(A, r) -> true end. % breaks the opaqueness
+ if is_record(A, r) -> true end. % breaks the opacity
ri14() ->
A = simple1_adt:d1(),
- if is_record({A, 1}, r) -> true end. % breaks the opaqueness
+ if is_record({A, 1}, r) -> true end. % breaks the opacity
-type '1-3-t'() :: 1..3.
@@ -54,7 +54,7 @@ ri5() ->
ri6() ->
A = simple1_adt:d1(),
- if is_record(A, r) -> true end. % breaks opaqueness
+ if is_record(A, r) -> true end. % breaks opacity
ri7() ->
A = simple1_adt:d1(),
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl
index fb6d59d263..59b9e0fec4 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl
@@ -30,7 +30,7 @@ t3() ->
adt_t1() ->
R = rec_adt:r1(),
- {r1, a} = R. % breaks the opaqueness
+ {r1, a} = R. % breaks the opacity
-spec adt_t1(rec_adt:r1()) -> rec_adt:r1(). % invalid type spec
@@ -82,7 +82,7 @@ f() ->
r_adt() ->
{{r, rec_adt:f(), 2},
- #r{f = rec_adt:f(), o = 2}}. % breaks the opaqueness
+ #r{f = rec_adt:f(), o = 2}}. % breaks the opacity
-record(r2, % like #r1{}, but with initial value
{f1 = a :: a()}).
@@ -110,7 +110,7 @@ u3() ->
v1() ->
A = #r3{f1 = queue:new()},
- {r3, a} = A. % breaks the opaqueness
+ {r3, a} = A. % breaks the opacity
v2() ->
A = {r3, 10},
@@ -120,4 +120,4 @@ v2() ->
v3() ->
A = {r3, 10},
- #r3{f1 = 10} = A. % breaks the opaqueness
+ #r3{f1 = 10} = A. % breaks the opacity
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl
index 7db1100597..d67aa913d8 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl
@@ -194,7 +194,7 @@ tt1() ->
tt2() ->
A = simple1_adt:d1(),
- is_integer(A). % breaks the opaqueness
+ is_integer(A). % breaks the opacity
%% Comparison with integers
@@ -262,11 +262,11 @@ f2() ->
adt_f1() ->
T = simple1_adt:n1(),
- if is_function(T) -> ok end. % breaks the opaqueness
+ if is_function(T) -> ok end. % breaks the opacity
adt_f2() ->
T = simple1_adt:n1(),
- is_function(T). % breaks the opaqueness
+ is_function(T). % breaks the opacity
f3() ->
A = i1(),
@@ -281,12 +281,12 @@ f4() ->
adt_f3() ->
A = simple1_adt:i1(),
T = simple1_adt:n1(),
- if is_function(T, A) -> ok end. % breaks the opaqueness
+ if is_function(T, A) -> ok end. % breaks the opacity
adt_f4() ->
A = simple1_adt:i1(),
T = simple1_adt:n1(),
- is_function(T, A). % breaks the opaqueness
+ is_function(T, A). % breaks the opacity
adt_f4_a() ->
A = simple1_adt:i1(),
@@ -297,7 +297,7 @@ adt_f4_a() ->
adt_f4_b() ->
A = i1(),
T = simple1_adt:n1(),
- is_function(T, A). % breaks the opaqueness
+ is_function(T, A). % breaks the opacity
%% A few Boolean examples
@@ -404,7 +404,7 @@ bit_t1() ->
bit_adt_t1() ->
A = simple1_adt:i1(),
- <<100:(A)>>. % breaks the opaqueness
+ <<100:(A)>>. % breaks the opacity
bit_t3(A) ->
B = i1(),
@@ -415,14 +415,14 @@ bit_t3(A) ->
bit_adt_t2() ->
A = simple1_adt:i1(),
case <<"hej">> of
- <<_:A>> -> ok % breaks the opaqueness (but the message is strange)
+ <<_:A>> -> ok % breaks the opacity (but the message is strange)
end.
bit_adt_t3(A) ->
B = simple1_adt:i1(),
case none:none() of
- <<A: % breaks the opaqueness (the message is less than perfect)
+ <<A: % breaks the opacity (the message is less than perfect)
B>> -> 1
end.
@@ -445,7 +445,7 @@ bit_t4(A) ->
bit_adt_t4(A) ->
Sz = simple1_adt:i1(),
case A of
- <<_:Sz>> -> 1 % breaks the opaqueness
+ <<_:Sz>> -> 1 % breaks the opacity
end.
bit_t5() ->
@@ -457,7 +457,7 @@ bit_t5() ->
bit_adt_t5() ->
A = simple1_adt:bit1(),
case A of
- <<_/binary>> -> 1 % breaks the opaqueness
+ <<_/binary>> -> 1 % breaks the opacity
end.
-opaque bit1() :: binary().
@@ -475,7 +475,7 @@ call_f(A) ->
call_f_adt(A) ->
A = simple1_adt:a(),
- foo:A(A). % breaks the opaqueness
+ foo:A(A). % breaks the opacity
call_m(A) ->
A = a(),
@@ -483,7 +483,7 @@ call_m(A) ->
call_m_adt(A) ->
A = simple1_adt:a(),
- A:foo(A). % breaks the opaqueness
+ A:foo(A). % breaks the opacity
-opaque a() :: atom().
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl b/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl
index 9c8ea0af1c..ed6810634f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl
@@ -1,8 +1,8 @@
%%---------------------------------------------------------------------------
%% A test case with:
%% - a genuine matching error -- 1st branch
-%% - a violation of the opaqueness of timer:tref() -- 2nd branch
-%% - a subtle violation of the opaqueness of timer:tref() -- 3rd branch
+%% - a violation of the opacity of timer:tref() -- 2nd branch
+%% - a subtle violation of the opacity of timer:tref() -- 3rd branch
%% The test is supposed to check that these cases are treated properly.
%%---------------------------------------------------------------------------
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl
new file mode 100644
index 0000000000..094138e72b
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl
@@ -0,0 +1,18 @@
+-module(weird_warning1).
+-export([public_func/0]).
+
+-record(a, {
+ d = dict:new() :: dict:dict()
+ }).
+
+-record(b, {
+ q = queue:new() :: queue:queue()
+ }).
+
+public_func() ->
+ add_element(#b{}, my_key, my_value).
+
+add_element(#a{d = Dict}, Key, Value) ->
+ dict:store(Key, Value, Dict);
+add_element(#b{q = Queue}, Key, Value) ->
+ queue:in({Key, Value}, Queue).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl
new file mode 100644
index 0000000000..4e4512157b
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl
@@ -0,0 +1,14 @@
+-module(weird_warning2).
+-export([public_func/0]).
+
+-record(a, {d = dict:new() :: dict:dict()}).
+
+-record(b, {q = queue:new() :: queue:queue()}).
+
+public_func() ->
+ add_element(#a{}, my_key, my_value).
+
+add_element(#a{d = Dict}, Key, Value) ->
+ dict:store(Key, Value, Dict);
+add_element(#b{q = Queue}, Key, Value) ->
+ queue:in({Key, Value}, Queue).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl
new file mode 100644
index 0000000000..b70ca645cb
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl
@@ -0,0 +1,19 @@
+-module(weird_warning3).
+-export([public_func/0]).
+
+-record(a, {
+ d = dict:new() :: dict:dict()
+ }).
+
+-record(b, {
+ q = queue:new() :: queue:queue()
+ }).
+
+public_func() ->
+ %% Notice that t_to_string() will create "#a{d::queue:queue(_)}".
+ add_element({a, queue:new()}, my_key, my_value).
+
+add_element(#a{d = Dict}, Key, Value) ->
+ dict:store(Key, Value, Dict);
+add_element(#b{q = Queue}, Key, Value) ->
+ queue:in({Key, Value}, Queue).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl b/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl
index ca6bc0ab4a..6b825d85fe 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl
@@ -14,12 +14,12 @@
rel2fam(Rel) ->
sofs:to_external(sofs:relation_to_family(sofs:relation(Rel))).
-%% a definition that does not violate the opaqueness of gb_trees:tree()
+%% a definition that does not violate the opacity of gb_trees:tree()
gb_trees_smallest_key(Tree) ->
{Key, _V} = gb_trees:smallest(Tree),
Key.
-%% a definition that violates the opaqueness of gb_trees:tree()
+%% a definition that violates the opacity of gb_trees:tree()
gb_trees_largest_key({_, Tree}) ->
largest_key1(Tree).
diff --git a/lib/dialyzer/test/options2_SUITE_data/dialyzer_options b/lib/dialyzer/test/options2_SUITE_data/dialyzer_options
index 5db2e50d23..be57e2de72 100644
--- a/lib/dialyzer/test/options2_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/options2_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{defines, [{'vsn', 4}]}, {warnings, [no_return]}]}.
+{dialyzer_options, [{defines, [{'vsn', 4}]}, {warnings, [unknown, no_return]}]}.
diff --git a/lib/dialyzer/test/options2_SUITE_data/results/unknown_type b/lib/dialyzer/test/options2_SUITE_data/results/unknown_type
new file mode 100644
index 0000000000..d308c5a810
--- /dev/null
+++ b/lib/dialyzer/test/options2_SUITE_data/results/unknown_type
@@ -0,0 +1,2 @@
+
+:0: Unknown type unknown:type/0 \ No newline at end of file
diff --git a/lib/dialyzer/test/options2_SUITE_data/src/unknown_type.erl b/lib/dialyzer/test/options2_SUITE_data/src/unknown_type.erl
new file mode 100644
index 0000000000..7a891c0831
--- /dev/null
+++ b/lib/dialyzer/test/options2_SUITE_data/src/unknown_type.erl
@@ -0,0 +1,7 @@
+-module(unknown_type).
+
+-export([t/0]).
+
+-spec t() -> unknown:type().
+t() ->
+ a.
diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl
index 6ebe23b54b..fbfa979e1b 100644
--- a/lib/dialyzer/test/plt_SUITE.erl
+++ b/lib/dialyzer/test/plt_SUITE.erl
@@ -8,13 +8,15 @@
-export([suite/0, all/0, build_plt/1, beam_tests/1, update_plt/1,
local_fun_same_as_callback/1,
- remove_plt/1, run_plt_check/1, run_succ_typings/1]).
+ remove_plt/1, run_plt_check/1, run_succ_typings/1,
+ bad_dialyzer_attr/1]).
suite() ->
[{timetrap, ?plt_timeout}].
all() -> [build_plt, beam_tests, update_plt, run_plt_check,
- remove_plt, run_succ_typings, local_fun_same_as_callback].
+ remove_plt, run_succ_typings, local_fun_same_as_callback,
+ bad_dialyzer_attr].
build_plt(Config) ->
OutDir = ?config(priv_dir, Config),
@@ -24,6 +26,8 @@ build_plt(Config) ->
end.
beam_tests(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Plt = filename:join(PrivDir, "beam_tests.plt"),
Prog = <<"
-module(no_auto_import).
@@ -40,10 +44,12 @@ beam_tests(Config) when is_list(Config) ->
">>,
Opts = [no_auto_import],
{ok, BeamFile} = compile(Config, Prog, no_auto_import, Opts),
- [] = run_dialyzer(plt_build, [BeamFile], []),
+ [] = run_dialyzer(plt_build, [BeamFile], [{output_plt, Plt}]),
ok.
run_plt_check(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Plt = filename:join(PrivDir, "run_plt_check.plt"),
Mod1 = <<"
-module(run_plt_check1).
">>,
@@ -54,7 +60,7 @@ run_plt_check(Config) when is_list(Config) ->
{ok, BeamFile1} = compile(Config, Mod1, run_plt_check1, []),
{ok, BeamFile2} = compile(Config, Mod2A, run_plt_check2, []),
- [] = run_dialyzer(plt_build, [BeamFile1, BeamFile2], []),
+ [] = run_dialyzer(plt_build, [BeamFile1, BeamFile2], [{output_plt, Plt}]),
Mod2B = <<"
-module(run_plt_check2).
@@ -68,11 +74,13 @@ run_plt_check(Config) when is_list(Config) ->
% callgraph warning as run_plt_check2:call/1 makes a call to unexported
% function run_plt_check1:call/1.
- [_] = run_dialyzer(plt_check, [], []),
+ [_] = run_dialyzer(plt_check, [], [{init_plt, Plt}]),
ok.
run_succ_typings(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Plt = filename:join(PrivDir, "run_succ_typings.plt"),
Mod1A = <<"
-module(run_succ_typings1).
@@ -82,7 +90,7 @@ run_succ_typings(Config) when is_list(Config) ->
">>,
{ok, BeamFile1} = compile(Config, Mod1A, run_succ_typings1, []),
- [] = run_dialyzer(plt_build, [BeamFile1], []),
+ [] = run_dialyzer(plt_build, [BeamFile1], [{output_plt, Plt}]),
Mod1B = <<"
-module(run_succ_typings1).
@@ -105,9 +113,11 @@ run_succ_typings(Config) when is_list(Config) ->
{ok, BeamFile2} = compile(Config, Mod2, run_succ_typings2, []),
% contract types warning as run_succ_typings2:call/0 makes a call to
% run_succ_typings1:call/0, which returns a (not b) in the PLT.
- [_] = run_dialyzer(succ_typings, [BeamFile2], [{check_plt, false}]),
+ [_] = run_dialyzer(succ_typings, [BeamFile2],
+ [{check_plt, false}, {init_plt, Plt}]),
% warning not returned as run_succ_typings1 is updated in the PLT.
- [] = run_dialyzer(succ_typings, [BeamFile2], [{check_plt, true}]),
+ [] = run_dialyzer(succ_typings, [BeamFile2],
+ [{check_plt, true}, {init_plt, Plt}]),
ok.
@@ -249,6 +259,27 @@ remove_plt(Config) ->
{init_plt, Plt}] ++ Opts),
ok.
+bad_dialyzer_attr(Config) ->
+ Prog1 = <<"-module(dial).
+ -dialyzer({no_return, [undef/0]}).">>,
+ {ok, Beam1} = compile(Config, Prog1, dial, []),
+ {dialyzer_error,
+ "Analysis failed with error:\n"
+ "Could not scan the following file(s):\n"
+ " Unknown function undef/0 in line " ++ _} =
+ (catch run_dialyzer(plt_build, [Beam1], [])),
+
+ Prog2 = <<"-module(dial).
+ -dialyzer({no_return, [{undef,1,2}]}).">>,
+ {ok, Beam2} = compile(Config, Prog2, dial, []),
+ {dialyzer_error,
+ "Analysis failed with error:\n"
+ "Could not scan the following file(s):\n"
+ " Bad function {undef,1,2} in line " ++ _} =
+ (catch run_dialyzer(plt_build, [Beam2], [])),
+
+ ok.
+
compile(Config, Prog, Module, CompileOpts) ->
Source = lists:concat([Module, ".erl"]),
PrivDir = ?config(priv_dir,Config),
diff --git a/lib/dialyzer/test/small_SUITE_data/results/chars b/lib/dialyzer/test/small_SUITE_data/results/chars
new file mode 100644
index 0000000000..2c1f8f8d17
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/chars
@@ -0,0 +1,4 @@
+
+chars.erl:29: Invalid type specification for function chars:f/1. The success typing is (#{'b':=50}) -> 'ok'
+chars.erl:32: Function t1/0 has no local return
+chars.erl:32: The call chars:f(#{'b':=50}) breaks the contract (#{'a':=49,'b'=>50,'c'=>51}) -> 'ok'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/guards b/lib/dialyzer/test/small_SUITE_data/results/guards
index 824a7cfa24..cd0d3cace0 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/guards
+++ b/lib/dialyzer/test/small_SUITE_data/results/guards
@@ -10,8 +10,8 @@ guards.erl:136: The call guards:t16('a') will never return since it differs in t
guards.erl:136: The call guards:t16('c') will never return since it differs in the 1st argument from the success typing arguments: ('b')
guards.erl:55: Function t5/1 has no local return
guards.erl:55: Guard test is_integer(A::atom()) can never succeed
-guards.erl:59: Clause guard cannot succeed. The variable A was matched against the type any()
guards.erl:59: Function t6/1 has no local return
+guards.erl:59: Guard test is_integer(A::atom()) can never succeed
guards.erl:67: The call guards:t7({42}) will never return since it differs in the 1st argument from the success typing arguments: (atom() | integer())
guards.erl:75: The call guards:t8({42}) will never return since it differs in the 1st argument from the success typing arguments: (atom() | integer())
guards.erl:92: The variable _ can never match since previous clauses completely covered the type {'true','true'}
diff --git a/lib/dialyzer/test/small_SUITE_data/src/anno.erl b/lib/dialyzer/test/small_SUITE_data/src/anno.erl
new file mode 100644
index 0000000000..70f1d42141
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/anno.erl
@@ -0,0 +1,18 @@
+-module(anno).
+
+%% OTP-14131
+
+-export([t1/0, t2/0, t3/0]).
+
+t1() ->
+ A = erl_parse:anno_from_term({attribute, 1, module, my_test}),
+ compile:forms([A], []).
+
+t2() ->
+ A = erl_parse:new_anno({attribute, 1, module, my_test}),
+ compile:forms([A], []).
+
+t3() ->
+ A = erl_parse:new_anno({attribute, 1, module, my_test}),
+ T = erl_parse:anno_to_term(A),
+ {attribute, 1, module, my_test} = T.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/chars.erl b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
new file mode 100644
index 0000000000..1e9c8ab6b9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
@@ -0,0 +1,32 @@
+-module(chars).
+
+%% ERL-313
+
+-export([t/0]).
+-export([t1/0]).
+
+-record(r, {f :: $A .. $Z}).
+
+-type cs() :: $A..$Z | $a .. $z | $/.
+
+-spec t() -> $0-$0..$9-$0| $?.
+
+t() ->
+ c(#r{f = $z - 3}),
+ c($z - 3),
+ c($B).
+
+-spec c(cs()) -> $3-$0..$9-$0.
+
+c($A + 1) -> 2;
+c(C) ->
+ case C of
+ $z - 3 -> 3;
+ #r{f = $z - 3} -> 7
+ end.
+
+%% Display contract with character in warning:
+-spec f(#{a := $1, b => $2, c => $3}) -> ok. % invalid type spec
+f(_) -> ok.
+
+t1() -> f(#{b => $2}). % breaks the contract
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ms.erl b/lib/dialyzer/test/small_SUITE_data/src/ms.erl
new file mode 100644
index 0000000000..47a5e886cf
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ms.erl
@@ -0,0 +1,8 @@
+-module(ms).
+-export([t/0]).
+
+-include_lib("stdlib/include/ms_transform.hrl").
+
+t() ->
+ MS = dbg:fun2ms(fun(All) -> message(All) end),
+ erlang:trace_pattern({m, f, '_'}, MS).
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 077fe01e85..7d239fe9cd 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 3.0
+DIALYZER_VSN = 3.1.1
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index d68a78ed6d..72181a42b0 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -94,12 +94,12 @@ in this module.</p>
<taglist>
-<tag><c>Address()</c></tag>
-<tag><c>DiameterIdentity()</c></tag>
-<tag><c>Grouped()</c></tag>
-<tag><c>OctetString()</c></tag>
-<tag><c>Time()</c></tag>
-<tag><c>Unsigned32()</c></tag>
+<tag><c>Address()</c></tag><item/>
+<tag><c>DiameterIdentity()</c></tag><item/>
+<tag><c>Grouped()</c></tag><item/>
+<tag><c>OctetString()</c></tag><item/>
+<tag><c>Time()</c></tag><item/>
+<tag><c>Unsigned32()</c></tag><item/>
<tag><c>UTF8String()</c></tag>
<item>
<p>
@@ -159,8 +159,7 @@ Has one the following types.</p>
<p>
Unique identifier for the application in the scope of the
service.
-Defaults to the value of the <c>dictionary</c> option if
-unspecified.</p>
+Defaults to the value of the <c>dictionary</c> option.</p>
</item>
<tag><c>{dictionary, atom()}</c></tag>
@@ -187,7 +186,7 @@ Initial callback state.
The prevailing state is passed to some
&man_app;
callbacks, which can then return a new state.
-Defaults to the value of the <c>alias</c> option if unspecified.</p>
+Defaults to the value of the <c>alias</c> option.</p>
</item>
<tag><c>{call_mutates_state, true|false}</c></tag>
@@ -195,7 +194,7 @@ Defaults to the value of the <c>alias</c> option if unspecified.</p>
<p>
Whether or not the &app_pick_peer;
application callback can modify the application state.
-Defaults to <c>false</c> if unspecified.</p>
+Defaults to <c>false</c>.</p>
<warning>
<p>
@@ -228,7 +227,7 @@ question is as if a callback had taken place and returned
<c>{error, failure}</c>.</p>
<p>
-Defaults to <c>discard</c> if unspecified.</p>
+Defaults to <c>discard</c>.</p>
</item>
<tag><c>{request_errors, answer_3xxx|answer|callback}</c></tag>
@@ -249,7 +248,7 @@ place and its return value determines the answer sent to the peer, if
any.</p>
<p>
-Defaults to <c>answer_3xxx</c> if unspecified.</p>
+Defaults to <c>answer_3xxx</c>.</p>
<note>
<p>
@@ -339,8 +338,8 @@ Has one of the following types.</p>
<taglist>
-<tag><c>{'Origin-Host', &dict_DiameterIdentity;}</c></tag>
-<tag><c>{'Origin-Realm', &dict_DiameterIdentity;}</c></tag>
+<tag><c>{'Origin-Host', &dict_DiameterIdentity;}</c></tag><item/>
+<tag><c>{'Origin-Realm', &dict_DiameterIdentity;}</c></tag><item/>
<tag><c>{'Host-IP-Address', [&dict_Address;]}</c></tag>
<item>
<p>
@@ -352,8 +351,8 @@ question communicates an address list as described in
&man_transport;</p>
</item>
-<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag>
-<tag><c>{'Product-Name', &dict_UTF8String;}</c></tag>
+<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag><item/>
+<tag><c>{'Product-Name', &dict_UTF8String;}</c></tag><item/>
<tag><c>{'Origin-State-Id', &dict_Unsigned32;}</c></tag>
<item>
<p>
@@ -366,8 +365,8 @@ can be used as to retrieve a value that is computed when the diameter
application is started.</p>
</item>
-<tag><c>{'Supported-Vendor-Id', [&dict_Unsigned32;]}</c></tag>
-<tag><c>{'Auth-Application-Id', [&dict_Unsigned32;]}</c></tag>
+<tag><c>{'Supported-Vendor-Id', [&dict_Unsigned32;]}</c></tag><item/>
+<tag><c>{'Auth-Application-Id', [&dict_Unsigned32;]}</c></tag><item/>
<tag><c>{'Inband-Security-Id', [&dict_Unsigned32;]}</c></tag>
<item>
<p>
@@ -377,9 +376,9 @@ If 1 (TLS) is specified then TLS is selected if the CER/CEA received
from the peer offers it.</p>
</item>
-<tag><c>{'Acct-Application-Id', [&dict_Unsigned32;]}</c></tag>
-<tag><c>{'Vendor-Specific-Application-Id', [&dict_Grouped;]}</c></tag>
-<tag><c>{'Firmware-Revision', &dict_Unsigned32;}</c></tag>
+<tag><c>{'Acct-Application-Id', [&dict_Unsigned32;]}</c></tag><item/>
+<tag><c>{'Vendor-Specific-Application-Id', [&dict_Grouped;]}</c></tag><item/>
+<tag><c>{'Firmware-Revision', &dict_Unsigned32;}</c></tag><item/>
</taglist>
@@ -567,9 +566,8 @@ Can have one of the following types.</p>
<taglist>
-<tag><c>start</c></tag>
+<tag><c>start</c></tag><item/>
<tag><c>stop</c></tag>
-
<item>
<p>
The service is being started or stopped.
@@ -578,8 +576,8 @@ No event follows a <c>stop</c> event, and this event
implies the termination of all transport processes.</p>
</item>
-<tag><c>{up, Ref, Peer, Config, Pkt}</c></tag>
-<tag><c>{up, Ref, Peer, Config}</c></tag>
+<tag><c>{up, Ref, Peer, Config, Pkt}</c></tag><item/>
+<tag><c>{up, Ref, Peer, Config}</c></tag><item/>
<tag><c>{down, Ref, Peer, Config}</c></tag>
<item>
<pre>
@@ -788,8 +786,8 @@ be matched by corresponding &capability; configuration, of
</item>
-<marker id="incoming_maxlen"/>
-<tag><c>{incoming_maxlen, 0..16777215}</c></tag>
+<tag>
+<marker id="incoming_maxlen"/><c>{incoming_maxlen, 0..16777215}</c></tag>
<item>
<p>
Bound on the expected size of incoming Diameter messages.
@@ -917,8 +915,8 @@ Options <c>monitor</c> and <c>link</c> are ignored.</p>
Defaults to the empty list.</p>
</item>
-<marker id="strict_mbit"/>
-<tag><c>{strict_mbit, boolean()}</c></tag>
+<tag>
+<marker id="strict_mbit"/><c>{strict_mbit, boolean()}</c></tag>
<item>
<p>
Whether or not to regard an AVP setting the M-bit as erroneous when
@@ -935,7 +933,7 @@ Defaults to <c>true</c>.</p>
<p>
RFC 6733 is unclear about the semantics of the M-bit.
One the one hand, the CCF specification in section 3.2 documents AVP
-in a command grammar as meaning <b>any</b> arbitrary AVP; on the
+in a command grammar as meaning <em>any</em> arbitrary AVP; on the
other hand, 1.3.4 states that AVPs setting the M-bit cannot be added
to an existing command: the modified command must instead be
placed in a new Diameter application.</p>
@@ -945,7 +943,7 @@ allowing arbitrary AVPs setting the M-bit in a command makes its
interpretation implementation-dependent, since there's no
guarantee that all implementations will understand the same set of
arbitrary AVPs in the context of a given command.
-However, interpreting <c>AVP</c> in a command grammar as <b>any</b>
+However, interpreting <c>AVP</c> in a command grammar as any
AVP, regardless of M-bit, renders 1.3.4 meaningless, since the receiver
can simply ignore any AVP it thinks isn't relevant, regardless of the
sender's intent.</p>
@@ -960,8 +958,8 @@ occur in the message in question.</p>
</item>
-<marker id="string_decode"/>
-<tag><c>{string_decode, boolean()}</c></tag>
+<tag>
+<marker id="string_decode"/><c>{string_decode, boolean()}</c></tag>
<item>
<p>
Whether or not to decode AVPs of type &dict_OctetString; and its
@@ -1031,8 +1029,9 @@ Option passed to &add_transport;.
Has one of the following types.</p>
<taglist>
-<marker id="applications"/>
-<tag><c>{applications, [&application_alias;]}</c></tag>
+
+<tag>
+<marker id="applications"/><c>{applications, [&application_alias;]}</c></tag>
<item>
<p>
Diameter applications to which the transport should be restricted.
@@ -1050,8 +1049,8 @@ implies having to set matching *-Application-Id AVPs in a
</item>
-<marker id="capabilities"/>
-<tag><c>{capabilities, [&capability;]}</c></tag>
+<tag>
+<marker id="capabilities"/><c>{capabilities, [&capability;]}</c></tag>
<item>
<p>
AVPs used to construct outgoing CER/CEA messages.
@@ -1064,8 +1063,8 @@ may be particularly appropriate for Inband-Security-Id, in case
TLS is desired over TCP as implemented by &man_tcp;.</p>
</item>
-<marker id="capabilities_cb"/>
-<tag><c>{capabilities_cb, &evaluable;}</c></tag>
+<tag>
+<marker id="capabilities_cb"/><c>{capabilities_cb, &evaluable;}</c></tag>
<item>
<p>
Callback invoked upon reception of CER/CEA during capabilities
@@ -1112,8 +1111,8 @@ case the corresponding callbacks are applied until either all return
<c>ok</c> or one does not.</p>
</item>
-<marker id="capx_timeout"/>
-<tag><c>{capx_timeout, &dict_Unsigned32;}</c></tag>
+<tag>
+<marker id="capx_timeout"/><c>{capx_timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
Number of milliseconds after which a transport process having an
@@ -1127,8 +1126,8 @@ For a listening transport, the peer determines the timing.</p>
Defaults to 10000.</p>
</item>
-<marker id="connect_timer"/>
-<tag><c>{connect_timer, Tc}</c></tag>
+<tag>
+<marker id="connect_timer"/><c>{connect_timer, Tc}</c></tag>
<item>
<pre>
Tc = &dict_Unsigned32;
@@ -1158,9 +1157,8 @@ Defaults to 30000 for a connecting transport and 60000 for a listening
transport.</p>
</item>
-<marker id="disconnect_cb"/>
-<tag><c>{disconnect_cb, &evaluable;}</c></tag>
-
+<tag>
+<marker id="disconnect_cb"/><c>{disconnect_cb, &evaluable;}</c></tag>
<item>
<p>
Callback invoked prior to terminating the transport process of a
@@ -1236,8 +1234,8 @@ configured them.</p>
Defaults to a single callback returning <c>dpr</c>.</p>
</item>
-<marker id="dpa_timeout"/>
-<tag><c>{dpa_timeout, &dict_Unsigned32;}</c></tag>
+<tag>
+<marker id="dpa_timeout"/><c>{dpa_timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
Number of milliseconds after which a transport connection is
@@ -1247,8 +1245,8 @@ terminated following an outgoing DPR if DPA is not received.</p>
Defaults to 1000.</p>
</item>
-<marker id="dpr_timeout"/>
-<tag><c>{dpr_timeout, &dict_Unsigned32;}</c></tag>
+<tag>
+<marker id="dpr_timeout"/><c>{dpr_timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
Number of milliseconds after which a transport connection is
@@ -1259,8 +1257,8 @@ connection.</p>
Defaults to 5000.</p>
</item>
-<marker id="length_errors"/>
-<tag><c>{length_errors, exit|handle|discard}</c></tag>
+<tag>
+<marker id="length_errors"/><c>{length_errors, exit|handle|discard}</c></tag>
<item>
<p>
How to deal with errors in the Message Length field of the
@@ -1308,8 +1306,8 @@ the same peer.</p>
</item>
-<marker id="spawn_opt"/>
-<tag><c>{spawn_opt, [term()]}</c></tag>
+<tag>
+<marker id="spawn_opt"/><c>{spawn_opt, [term()]}</c></tag>
<item>
<p>
Options passed to &spawn_opt; when spawning a process for an
@@ -1320,15 +1318,15 @@ Options <c>monitor</c> and <c>link</c> are ignored.</p>
Defaults to the list configured on the service if not specified.</p>
</item>
-<marker id="transport_config"/>
-<tag><c>{transport_config, term()}</c></tag>
+<tag>
+<marker id="transport_config"/><c>{transport_config, term()}</c></tag><item/>
<tag><c>{transport_config, term(), &dict_Unsigned32; | infinity}</c></tag>
<item>
<p>
Term passed as the third argument to the &transport_start; function of
the relevant &transport_module; in order to
start a transport process.
-Defaults to the empty list if unspecified.</p>
+Defaults to the empty list.</p>
<p>
The 3-tuple form additionally specifies an interval, in milliseconds,
@@ -1349,12 +1347,12 @@ request a connection with one peer over SCTP or another
To listen on both SCTP and TCP, define one transport for each.</p>
</item>
-<marker id="transport_module"/>
-<tag><c>{transport_module, atom()}</c></tag>
+<tag>
+<marker id="transport_module"/><c>{transport_module, atom()}</c></tag>
<item>
<p>
Module implementing a transport process as defined in &man_transport;.
-Defaults to <c>diameter_tcp</c> if unspecified.</p>
+Defaults to <c>diameter_tcp</c>.</p>
<p>
Multiple <c>transport_module</c> and &transport_config;
@@ -1369,8 +1367,9 @@ modules in order until one establishes a connection within the
corresponding timeout (see below) or all fail.</p>
</item>
-<marker id="watchdog_config"/>
-<tag><c>{watchdog_config, [{okay|suspect, non_neg_integer()}]}</c></tag>
+<tag>
+<marker id="watchdog_config"/><c>{watchdog_config,
+ [{okay|suspect, non_neg_integer()}]}</c></tag>
<item>
<p>
Configuration that alters the behaviour of the watchdog
@@ -1393,8 +1392,8 @@ misbehaving nodes during test.</p>
</warning>
</item>
-<marker id="watchdog_timer"/>
-<tag><c>{watchdog_timer, TwInit}</c></tag>
+<tag>
+<marker id="watchdog_timer"/><c>{watchdog_timer, TwInit}</c></tag>
<item>
<pre>
TwInit = &dict_Unsigned32;
@@ -1412,7 +1411,7 @@ the callback.</p>
<p>
An integer value must be at least 6000 as required by RFC 3539.
-Defaults to 30000 if unspecified.</p>
+Defaults to 30000.</p>
</item>
</taglist>
@@ -1422,10 +1421,10 @@ Unrecognized options are silently ignored but are returned unmodified
by &service_info; and can be referred to
in predicate functions passed to &remove_transport;.</p>
-<marker id="transport_ref"/>
</item>
-<tag><c>transport_ref() = reference()</c></tag>
+<tag>
+<marker id="transport_ref"/><c>transport_ref() = reference()</c></tag>
<item>
<p>
Reference returned by &add_transport; that
@@ -1682,17 +1681,17 @@ returned.</p>
<taglist>
-<tag><c>'Origin-Host'</c></tag>
-<tag><c>'Origin-Realm'</c></tag>
-<tag><c>'Vendor-Id'</c></tag>
-<tag><c>'Product-Name'</c></tag>
-<tag><c>'Origin-State-Id'</c></tag>
-<tag><c>'Host-IP-Address'</c></tag>
-<tag><c>'Supported-Vendor'</c></tag>
-<tag><c>'Auth-Application-Id'</c></tag>
-<tag><c>'Inband-Security-Id'</c></tag>
-<tag><c>'Acct-Application-Id'</c></tag>
-<tag><c>'Vendor-Specific-Application-Id'</c></tag>
+<tag><c>'Origin-Host'</c></tag><item/>
+<tag><c>'Origin-Realm'</c></tag><item/>
+<tag><c>'Vendor-Id'</c></tag><item/>
+<tag><c>'Product-Name'</c></tag><item/>
+<tag><c>'Origin-State-Id'</c></tag><item/>
+<tag><c>'Host-IP-Address'</c></tag><item/>
+<tag><c>'Supported-Vendor'</c></tag><item/>
+<tag><c>'Auth-Application-Id'</c></tag><item/>
+<tag><c>'Inband-Security-Id'</c></tag><item/>
+<tag><c>'Acct-Application-Id'</c></tag><item/>
+<tag><c>'Vendor-Specific-Application-Id'</c></tag><item/>
<tag><c>'Firmware-Revision'</c></tag>
<item>
<p>
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index 973b6eb732..dfcd00975b 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -90,17 +90,14 @@ is called in response to an incoming Diameter request message.</p>
</list>
-</description>
-
-<note>
<p>
-The arities given for the the callback functions here assume no extra
-arguments.
+The arities for the the callback functions here assume no extra arguments.
All functions will also be passed any extra arguments configured with
the callback module itself when calling &mod_start_service;
and, for the call-specific callbacks, any extra arguments passed to
&mod_call;.</p>
-</note>
+
+</description>
<!-- ===================================================================== -->
<!-- ===================================================================== -->
@@ -110,9 +107,8 @@ and, for the call-specific callbacks, any extra arguments passed to
<taglist>
-<marker id="capabilities"/>
-
-<tag><c>capabilities() = #diameter_caps{}</c></tag>
+<tag>
+<marker id="capabilities"/><c>capabilities() = #diameter_caps{}</c></tag>
<item>
<p>
A record containing the identities of
@@ -126,9 +122,8 @@ Optional or possibly multiple values are encoded as lists of values,
mandatory values as the bare value.</p>
</item>
-<marker id="message"/>
-
-<tag><c>message() = &codec_message;</c></tag>
+<tag>
+<marker id="message"/><c>message() = &codec_message;</c></tag>
<item>
<p>
The representation of a Diameter message as passed to
@@ -136,9 +131,8 @@ The representation of a Diameter message as passed to
</item>
-<marker id="packet"/>
-
-<tag><c>packet() = &codec_packet;</c></tag>
+<tag>
+<marker id="packet"/><c>packet() = &codec_packet;</c></tag>
<item>
<p>
A container for incoming and outgoing Diameter messages that's passed
@@ -146,25 +140,22 @@ through encode/decode and transport.
Fields should not be set in return values except as documented.</p>
</item>
-<marker id="peer_ref"/>
-
-<tag><c>peer_ref() = term()</c></tag>
+<tag>
+<marker id="peer_ref"/><c>peer_ref() = term()</c></tag>
<item>
<p>
A term identifying a transport connection with a Diameter peer.</p>
</item>
-<marker id="peer"/>
-
-<tag><c>peer() = {&peer_ref;, &capabilities;}</c></tag>
+<tag>
+<marker id="peer"/><c>peer() = {&peer_ref;, &capabilities;}</c></tag>
<item>
<p>
A tuple representing a Diameter peer connection.</p>
</item>
-<marker id="state"/>
-
-<tag><c>state() = term()</c></tag>
+<tag>
+<marker id="state"/><c>state() = term()</c></tag>
<item>
<p>
The state maintained by the application callback functions
diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml
index a0313e2877..91e96058dd 100644
--- a/lib/diameter/doc/src/diameter_codec.xml
+++ b/lib/diameter/doc/src/diameter_codec.xml
@@ -88,10 +88,9 @@ files resulting from dictionary file compilation.</p>
<taglist>
-<marker id="integers"/>
-
-<tag><c>uint8()&nbsp; = 0..255</c></tag>
-<tag><c>uint24() = 0..16777215</c></tag>
+<tag>
+<marker id="integers"/><c>uint8()&nbsp; = 0..255</c></tag><item/>
+<tag><c>uint24() = 0..16777215</c></tag><item/>
<tag><c>uint32() = 0..4294967295</c></tag>
<item>
<p>
@@ -99,9 +98,8 @@ files resulting from dictionary file compilation.</p>
headers.</p>
</item>
-<marker id="avp"/>
-
-<tag><c>avp() = #diameter_avp{}</c></tag>
+<tag>
+<marker id="avp"/><c>avp() = #diameter_avp{}</c></tag>
<item>
<p>
The application-neutral representation of an AVP.
@@ -116,9 +114,9 @@ Fields have the following types.</p>
<taglist>
-<tag><c>code = uint32()</c></tag>
-<tag><c>is_mandatory = boolean()</c></tag>
-<tag><c>need_encryption = boolean()</c></tag>
+<tag><c>code = uint32()</c></tag><item/>
+<tag><c>is_mandatory = boolean()</c></tag><item/>
+<tag><c>need_encryption = boolean()</c></tag><item/>
<tag><c>vendor_id = uint32() | undefined</c></tag>
<item>
<p>
@@ -167,9 +165,8 @@ Possible types are <c>undefined</c> and the Diameter types:
</item>
-<marker id="dictionary"/>
-
-<tag><c>dictionary() = module()</c></tag>
+<tag>
+<marker id="dictionary"/><c>dictionary() = module()</c></tag>
<item>
<p>
@@ -179,9 +176,8 @@ The interface provided by a dictionary module is an
implementation detail that may change.</p>
</item>
-<marker id="header"/>
-
-<tag><c>header() = #diameter_header{}</c></tag>
+<tag>
+<marker id="header"/><c>header() = #diameter_header{}</c></tag>
<item>
<p>
The record representation of the Diameter header.
@@ -204,11 +200,11 @@ Fields have the following types.</p>
<taglist>
-<tag><c>version = uint8()</c></tag>
-<tag><c>length = uint24()</c></tag>
-<tag><c>cmd_code = uint24()</c></tag>
-<tag><c>application_id = uint32()</c></tag>
-<tag><c>hop_by_hop_id = uint32()</c></tag>
+<tag><c>version = uint8()</c></tag><item/>
+<tag><c>length = uint24()</c></tag><item/>
+<tag><c>cmd_code = uint24()</c></tag><item/>
+<tag><c>application_id = uint32()</c></tag><item/>
+<tag><c>hop_by_hop_id = uint32()</c></tag><item/>
<tag><c>end_to_end_id = uint32()</c></tag>
<item>
<p>
@@ -217,9 +213,9 @@ Hop-by-Hop Identifier and End-to-End Identifier fields of the Diameter
header.</p>
</item>
-<tag><c>is_request = boolean()</c></tag>
-<tag><c>is_proxiable = boolean()</c></tag>
-<tag><c>is_error = boolean()</c></tag>
+<tag><c>is_request = boolean()</c></tag><item/>
+<tag><c>is_proxiable = boolean()</c></tag><item/>
+<tag><c>is_error = boolean()</c></tag><item/>
<tag><c>is_retransmitted = boolean()</c></tag>
<item>
<p>
@@ -232,9 +228,8 @@ header.</p>
</item>
-<marker id="message"/>
-
-<tag><c>message() = record() | list()</c></tag>
+<tag>
+<marker id="message"/><c>message() = record() | list()</c></tag>
<item>
<p>
The representation of a Diameter message as passed to
@@ -257,9 +252,8 @@ question: messages are sent exactly as specified.</p>
</item>
-<marker id="packet"/>
-
-<tag><c>packet() = #diameter_packet{}</c></tag>
+<tag>
+<marker id="packet"/><c>packet() = #diameter_packet{}</c></tag>
<item>
<p>
A container for incoming and outgoing Diameter messages.
@@ -296,7 +290,7 @@ corresponding values.</p>
<warning>
<p>
-A record-valued <c>msg</c> field does <b>not</b> imply an absence of
+A record-valued <c>msg</c> field does <em>not</em> imply an absence of
decode errors.
The <c>errors</c> field should also be examined.</p>
</warning>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index ae40f99aee..9584d682c2 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "fileref.dtd" [
+<!DOCTYPE fileref SYSTEM "fileref.dtd" [
<!ENTITY format
'<seealso marker="#FILE_FORMAT">FILE FORMAT</seealso>'>
<!ENTITY records
@@ -121,9 +121,8 @@ The order in which sections are specified is unimportant.</p>
<taglist>
-<marker id="id"/>
-
-<tag><c>@id Number</c></tag>
+<tag>
+<marker id="id"/><c>@id Number</c></tag>
<item>
<p>
Defines the integer Number as the Diameter Application Id of the
@@ -146,14 +145,13 @@ Example:</p>
</item>
-<marker id="name"/>
-
-<tag><c>@name Mod</c></tag>
+<tag>
+<marker id="name"/><c>@name Mod</c></tag>
<item>
<p>
Defines the name of the generated dictionary module.
Can occur at most once and defaults to the name of the dictionary file
-minus any extension if unspecified.
+minus any extension.
The section has empty content.</p>
<p>
@@ -169,9 +167,8 @@ Example:</p>
</item>
-<marker id="prefix"/>
-
-<tag><c>@prefix Name</c></tag>
+<tag>
+<marker id="prefix"/><c>@prefix Name</c></tag>
<item>
<p>
Defines Name as the prefix to be added to record and constant names
@@ -194,9 +191,8 @@ Example:</p>
</item>
-<marker id="vendor"/>
-
-<tag><c>@vendor Number Name</c></tag>
+<tag>
+<marker id="vendor"/><c>@vendor Number Name</c></tag>
<item>
<p>
Defines the integer Number as the the default Vendor-Id of AVPs for
@@ -216,9 +212,8 @@ Example:</p>
</item>
-<marker id="avp_vendor_id"/>
-
-<tag><c>@avp_vendor_id Number</c></tag>
+<tag>
+<marker id="avp_vendor_id"/><c>@avp_vendor_id Number</c></tag>
<item>
<p>
Defines the integer Number as the Vendor-Id of the AVPs listed in the
@@ -238,9 +233,8 @@ Region-Set
</item>
-<marker id="inherits"/>
-
-<tag><c>@inherits Mod</c></tag>
+<tag>
+<marker id="inherits"/><c>@inherits Mod</c></tag>
<item>
<p>
Defines the name of a dictionary module containing AVP
@@ -274,9 +268,8 @@ Example:</p>
</pre>
</item>
-<marker id="avp_types"/>
-
-<tag><c>@avp_types</c></tag>
+<tag>
+<marker id="avp_types"/><c>@avp_types</c></tag>
<item>
<p>
Defines the name, code, type and flags of individual AVPs.
@@ -308,9 +301,8 @@ The P flag has been deprecated by &the_rfc;.</p>
</item>
-<marker id="custom_types"/>
-
-<tag><c>@custom_types Mod</c></tag>
+<tag>
+<marker id="custom_types"/><c>@custom_types Mod</c></tag>
<item>
<p>
Specifies AVPs for which module Mod provides encode/decode functions.
@@ -331,9 +323,8 @@ Framed-IP-Address
</pre>
</item>
-<marker id="codecs"/>
-
-<tag><c>@codecs Mod</c></tag>
+<tag>
+<marker id="codecs"/><c>@codecs Mod</c></tag>
<item>
<p>
Like <c>@custom_types</c> but requires the specified module to export
@@ -350,9 +341,8 @@ Framed-IP-Address
</pre>
</item>
-<marker id="messages"/>
-
-<tag><c>@messages</c></tag>
+<tag>
+<marker id="messages"/><c>@messages</c></tag>
<item>
<p>
Defines the messages of the application.
@@ -397,9 +387,8 @@ RTA ::= &lt; Diameter Header: 287, PXY >
</item>
-<marker id="grouped"/>
-
-<tag><c>@grouped</c></tag>
+<tag>
+<marker id="grouped"/><c>@grouped</c></tag>
<item>
<p>
Defines the contents of the AVPs of the application having type
@@ -424,9 +413,8 @@ Specifying a Vendor-Id in the definition of a grouped AVP is
equivalent to specifying it with <c>@avp_vendor_id</c>.</p>
</item>
-<marker id="enum"/>
-
-<tag><c>@enum Name</c></tag>
+<tag>
+<marker id="enum"/><c>@enum Name</c></tag>
<item>
<p>
Defines values of AVP Name having type Enumerated.
@@ -452,9 +440,8 @@ REMOVE_SIP_SERVER 3
</pre>
</item>
-<marker id="end"/>
-
-<tag><c>@end</c></tag>
+<tag>
+<marker id="end"/><c>@end</c></tag>
<item>
<p>
Causes parsing of the dictionary to terminate:
diff --git a/lib/diameter/doc/src/diameter_examples.xml b/lib/diameter/doc/src/diameter_examples.xml
index 853ef96bb3..2e1f2b3c03 100644
--- a/lib/diameter/doc/src/diameter_examples.xml
+++ b/lib/diameter/doc/src/diameter_examples.xml
@@ -42,4 +42,3 @@ Example code can be found in the diameter application's
<c>examples</c> subdirectory.</p>
</chapter>
-
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 00ccc39c15..6ca280c52b 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -150,7 +150,7 @@ Options <c>binary</c>,
<c>packet</c> and <c>active</c> cannot be specified.
Also, option <c>port</c> can be specified for a listening transport
to specify the local listening port, the default being the standardized
-3868 if unspecified.
+3868.
Note that the option <c>ip</c> specifies the local address.</p>
<p>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 736d4cbfbd..294e8a8864 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -65,9 +65,8 @@ parent).</p>
<taglist>
-<marker id="message"/>
-
-<tag><c>message() = binary() | &codec_packet;</c></tag>
+<tag>
+<marker id="message"/><c>message() = binary() | &codec_packet;</c></tag>
<item>
<p>
A Diameter message as passed over the transport interface.</p>
@@ -160,9 +159,9 @@ It should exit if its transport connection with its peer is lost.</p>
</funcs>
<!-- ===================================================================== -->
-<marker id="MESSAGES"/>
<section>
+<marker id="MESSAGES"/>
<title>MESSAGES</title>
<p>
@@ -234,7 +233,7 @@ established a connection with the peer.
Not sent if the transport process has <c>Type=connect</c>.</p>
</item>
-<tag><c>{diameter, {self(), connected, Remote}}</c></tag>
+<tag><c>{diameter, {self(), connected, Remote}}</c></tag><item/>
<tag><c>{diameter, {self(), connected, Remote, [LocalAddr]}}</c></tag>
<item>
<p>
diff --git a/lib/diameter/doc/src/diameterc.xml b/lib/diameter/doc/src/diameterc.xml
index 5bffe9a771..8f1c660989 100644
--- a/lib/diameter/doc/src/diameterc.xml
+++ b/lib/diameter/doc/src/diameterc.xml
@@ -11,7 +11,7 @@
<comref>
<header>
<copyright>
-<year>2011</year><year>2013</year>
+<year>2011</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -79,14 +79,14 @@ Write generated source to the specified directory.
Defaults to the current working directory.</p>
</item>
-<tag><![CDATA[-E]]></tag>
+<tag><![CDATA[-E]]></tag><item/>
<tag><![CDATA[-H]]></tag>
<item>
<p>
Suppress erl and hrl generation, respectively.</p>
</item>
-<tag><![CDATA[--name <name>]]></tag>
+<tag><![CDATA[--name <name>]]></tag><item/>
<tag><![CDATA[--prefix <prefix>]]></tag>
<item>
<p>
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index b1be7bdcf7..70e1880be5 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -43,6 +43,55 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 1.12.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An improvement in the handling of peer failover in
+ diameter 1.12.1 adversely affected performance when
+ sending requests. Further, the inefficient use of a
+ public table to route incoming answers has been removed.</p>
+ <p>
+ Own Id: OTP-14206</p>
+ </item>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>diameter 1.12.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Close diameter_tcp/sctp listening sockets at
+ diameter:stop_service/1.</p>
+ <p>
+ Broken by OTP-13611.</p>
+ <p>
+ Own Id: OTP-13787 Aux Id: OTP-13611 </p>
+ </item>
+ <item>
+ <p>
+ Update build scripts to not make assumtions about where
+ env, cp and perl are located.</p>
+ <p>
+ Own Id: OTP-13800</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 1.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -230,8 +279,8 @@ first.</p>
Fix decode of Grouped AVPs containing errors.</p>
<p>
RFC 6733 says this of Failed-AVP in 7.5:</p>
- <p>
- <taglist><item><p><c> In the case where the offending AVP
+
+ <taglist><tag></tag><item><p><c> In the case where the offending AVP
is embedded within a Grouped AVP, the Failed-AVP MAY
contain the grouped AVP, which in turn contains the
single offending AVP. The same method MAY be employed if
@@ -240,11 +289,11 @@ first.</p>
the grouped AVP hierarchy up to the single offending AVP.
This enables the recipient to detect the location of the
offending AVP when embedded in a
- group.</c></p></item></taglist></p>
+ group.</c></p></item></taglist>
<p>
It says this of DIAMETER_INVALID_AVP_LENGTH in 7.1.5:</p>
- <p>
- <taglist><item><p><c> The request contained an AVP with
+
+ <taglist><tag></tag><item><p><c> The request contained an AVP with
an invalid length. A Diameter message indicating this
error MUST include the offending AVPs within a Failed-AVP
AVP. In cases where the erroneous AVP length value
@@ -259,7 +308,8 @@ first.</p>
the minimum AVP header length, it is sufficient to
include an offending AVP header that is formulated by
padding the incomplete AVP header with zero up to the
- minimum AVP header length.</c></p></item></taglist></p>
+ minimum AVP header length.</c></p></item></taglist>
+
<p>
The AVPs placed in the errors field of a diameter_packet
record are intended to be appropriate for inclusion in a
@@ -924,8 +974,8 @@ first.</p>
Be lenient with the M-bit in Grouped AVPs.</p>
<p>
RFC 6733 says this, in 4.4:</p>
- <p>
- <taglist><item><p><c>Receivers of a Grouped AVP that does
+
+ <taglist><tag></tag><item><p><c>Receivers of a Grouped AVP that does
not have the 'M' (mandatory) bit set and one or more of
the encapsulated AVPs within the group has the 'M'
(mandatory) bit set MAY simply be ignored if the Grouped
@@ -933,14 +983,14 @@ first.</p>
encapsulated AVP with its 'M' (mandatory) bit set is
further encapsulated within other sub-groups, i.e., other
Grouped AVPs embedded within the Grouped
- AVP.</c></p></item></taglist></p>
+ AVP.</c></p></item></taglist>
<p>
The first sentence is mangled but take it to mean this:</p>
- <p>
- <taglist><item><p><c>An unrecognized AVP of type Grouped
+
+ <taglist><tag></tag><item><p><c>An unrecognized AVP of type Grouped
that does not set the 'M' bit MAY be ignored even if one
of its encapsulated AVPs sets the 'M'
- bit.</c></p></item></taglist></p>
+ bit.</c></p></item></taglist>
<p>
This is a bit of a non-statement since if the AVP is
unrecognized then its type is unknown. We therefore don't
diff --git a/lib/diameter/examples/code/relay.erl b/lib/diameter/examples/code/relay.erl
index 3846b1d161..806f79915b 100644
--- a/lib/diameter/examples/code/relay.erl
+++ b/lib/diameter/examples/code/relay.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@
{'Auth-Application-Id', [16#FFFFFFFF]},
{string_decode, false},
{application, [{alias, relay},
- {dictionary, diameter_relay},
+ {dictionary, diameter_gen_relay},
{module, relay_cb}]}]).
%% start/1
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 7f61620fc1..6bf748a727 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -123,7 +123,7 @@ ERL_COMPILE_FLAGS += \
# erl/hrl from dictionary file.
gen/diameter_gen_%.erl gen/diameter_gen_%.hrl: dict/%.dia
$(dia_verbose) \
- ../bin/diameterc -o gen -i $(EBIN) $<
+ escript ../bin/diameterc -o gen -i $(EBIN) $<
opt: $(TARGET_FILES)
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index e8f2f63f86..253f64133c 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -377,6 +377,7 @@ call(SvcName, App, Message) ->
| {capabilities, [capability()]}
| {capabilities_cb, evaluable()}
| {capx_timeout, 'Unsigned32'()}
+ | {capx_strictness, boolean()}
| {disconnect_cb, evaluable()}
| {dpr_timeout, 'Unsigned32'()}
| {dpa_timeout, 'Unsigned32'()}
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index fdbbd412a1..245a3ea7ac 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -580,6 +580,9 @@ opt({K, Tmo})
K == dpa_timeout ->
?IS_UINT32(Tmo);
+opt({capx_strictness, B}) ->
+ is_boolean(B);
+
opt({length_errors, T}) ->
lists:member(T, [exit, handle, discard]);
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index b835e87967..3928769b5e 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -299,8 +299,28 @@ spawn_opts(server, Opts) ->
spawn_opts(worker, Opts) ->
opts(5000, Opts).
-opts(HeapSize, Opts) ->
- [{min_heap_size, HeapSize} | lists:keydelete(min_heap_size, 1, Opts)].
+%% These setting are historical rather than useful. In particular, the
+%% server setting can bloat many processes unnecessarily. Let them be
+%% disabled with -diameter min_heap_size false.
+
+opts(Def, Opts) ->
+ Key = min_heap_size,
+ case getenv(Key, Def) of
+ N when is_integer(N), 0 =< N ->
+ [{Key, N} | lists:keydelete(Key, 1, Opts)];
+ _ ->
+ Opts
+ end.
+
+%% getenv/1
+
+getenv(Key, Def) ->
+ case application:get_env(Key) of
+ {ok, T} ->
+ T;
+ undefined ->
+ Def
+ end.
%% ---------------------------------------------------------------------------
%% # wait/1
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 996e75a8d3..7ee1e5fe59 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -128,6 +128,7 @@
%% outgoing DPR; boolean says whether or not
%% the request was sent explicitly with
%% diameter:call/4.
+ strict :: boolean(),
length_errors :: exit | handle | discard,
incoming_maxlen :: integer() | infinity}).
@@ -233,6 +234,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) ->
proplists:get_value(dpa_timeout, Opts, ?DPA_TIMEOUT)}),
Tmo = proplists:get_value(capx_timeout, Opts, ?CAPX_TIMEOUT),
+ Strictness = proplists:get_value(capx_strictness, Opts, true),
OnLengthErr = proplists:get_value(length_errors, Opts, exit),
{TPid, Addrs} = start_transport(T, Rest, Svc),
@@ -246,6 +248,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) ->
mode = M,
service = svc(Svc, Addrs),
length_errors = OnLengthErr,
+ strict = Strictness,
incoming_maxlen = Maxlen}.
%% The transport returns its local ip addresses so that different
%% transports on the same service can use different local addresses.
@@ -454,6 +457,9 @@ transition({timeout, _}, _) ->
%% Outgoing message.
transition({send, Msg}, S) ->
outgoing(Msg, S);
+transition({send, Msg, Route}, S) ->
+ put_route(Route),
+ outgoing(Msg, S);
%% Request for graceful shutdown at remove_transport, stop_service of
%% application shutdown.
@@ -483,8 +489,10 @@ transition({'DOWN', _, process, TPid, _},
= S) ->
start_next(S);
-%% Transport has died after connection timeout.
-transition({'DOWN', _, process, _, _}, _) ->
+%% Transport has died after connection timeout, or handler process has
+%% died.
+transition({'DOWN', _, process, Pid, _}, _) ->
+ erase_route(Pid),
ok;
%% State query.
@@ -494,6 +502,40 @@ transition({state, Pid}, #state{state = S, transport = TPid}) ->
%% Crash on anything unexpected.
+%% put_route/1
+%%
+%% Map identifiers in an outgoing request to be able to lookup the
+%% handler process when the answer is received.
+
+put_route({Pid, Ref, Seqs}) ->
+ MRef = monitor(process, Pid),
+ put(Pid, Seqs),
+ put(Seqs, {Pid, Ref, MRef}).
+
+%% get_route/1
+
+get_route(#diameter_packet{header = #diameter_header{is_request = false}}
+ = Pkt) ->
+ Seqs = diameter_codec:sequence_numbers(Pkt),
+ case erase(Seqs) of
+ {Pid, Ref, MRef} ->
+ demonitor(MRef),
+ erase(Pid),
+ {Pid, Ref, self()};
+ undefined ->
+ false
+ end;
+
+get_route(_) ->
+ false.
+
+%% erase_route/1
+
+erase_route(Pid) ->
+ erase(erase(Pid)).
+
+%% capx/1
+
capx(recv_CER) ->
'CER';
capx({'Wait-CEA', _, _}) ->
@@ -576,8 +618,7 @@ incoming({Msg, NPid}, S) ->
T
catch
{?MODULE, Name, Pkt} ->
- S#state.parent ! {recv, self(), Name, {Pkt, NPid}},
- rcv(Name, Pkt, S)
+ incoming(Name, Pkt, NPid, S)
end;
incoming(Msg, S) ->
@@ -585,10 +626,15 @@ incoming(Msg, S) ->
recv(Msg, S)
catch
{?MODULE, Name, Pkt} ->
- S#state.parent ! {recv, self(), Name, Pkt},
- rcv(Name, Pkt, S)
+ incoming(Name, Pkt, false, S)
end.
+%% incoming/4
+
+incoming(Name, Pkt, NPid, #state{parent = Pid} = S) ->
+ Pid ! {recv, self(), get_route(Pkt), Name, Pkt, NPid},
+ rcv(Name, Pkt, S).
+
%% recv/2
recv(#diameter_packet{header = #diameter_header{} = Hdr}
@@ -614,6 +660,17 @@ recv1(_,
when M < size(Bin) ->
invalid(false, incoming_maxlen_exceeded, {size(Bin), H});
+%% Ignore anything but an expected CER/CEA if so configured. This is
+%% non-standard behaviour.
+recv1(Name, _, #state{state = {'Wait-CEA', _, _},
+ strict = false})
+ when Name /= 'CEA' ->
+ ok;
+recv1(Name, _, #state{state = recv_CER,
+ strict = false})
+ when Name /= 'CER' ->
+ ok;
+
%% Incoming request after outgoing DPR: discard. Don't discard DPR, so
%% both ends don't do so when sending simultaneously.
recv1(Name,
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index ccf68f4d93..e4f77e3a24 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1858,13 +1858,6 @@ eq(Any, Id, PeerId) ->
%% OctetString() can be specified as an iolist() so test for string
%% rather then term equality.
-%% transports/1
-
-transports(#state{watchdogT = WatchdogT}) ->
- ets:select(WatchdogT, [{#watchdog{peer = '$1', _ = '_'},
- [{'is_pid', '$1'}],
- ['$1']}]).
-
%% ---------------------------------------------------------------------------
%% # service_info/2
%% ---------------------------------------------------------------------------
@@ -1887,7 +1880,6 @@ transports(#state{watchdogT = WatchdogT}) ->
-define(ALL_INFO, [capabilities,
applications,
transport,
- pending,
options]).
%% The rest.
@@ -1981,7 +1973,6 @@ complete_info(Item, #state{service = Svc} = S) ->
applications -> info_apps(S);
transport -> info_transport(S);
options -> info_options(S);
- pending -> info_pending(S);
keys -> ?ALL_INFO ++ ?CAP_INFO ++ ?OTHER_INFO;
all -> service_info(?ALL_INFO, S);
statistics -> info_stats(S);
@@ -2189,13 +2180,6 @@ info_apps(#state{service = #diameter_service{applications = Apps}}) ->
mk_app(#diameter_app{} = A) ->
lists:zip(record_info(fields, diameter_app), tl(tuple_to_list(A))).
-%% info_pending/1
-%%
-%% One entry for each outgoing request whose answer is outstanding.
-
-info_pending(#state{} = S) ->
- diameter_traffic:pending(transports(S)).
-
%% info_info/1
%%
%% Extract process_info from connections info.
diff --git a/lib/diameter/src/base/diameter_sup.erl b/lib/diameter/src/base/diameter_sup.erl
index 482289cb9a..01c51f0856 100644
--- a/lib/diameter/src/base/diameter_sup.erl
+++ b/lib/diameter/src/base/diameter_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@
-define(TABLES, [{diameter_sequence, [set]},
{diameter_service, [set, {keypos, 3}]},
- {diameter_request, [bag]},
+ {diameter_request, [set]},
{diameter_config, [bag, {keypos, 2}]}]).
%% start_link/0
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 2112941d5e..bc1ccf4feb 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
-export([send_request/4]).
%% towards diameter_watchdog
--export([receive_message/4]).
+-export([receive_message/6]).
%% towards diameter_peer_fsm and diameter_watchdog
-export([incr/4,
@@ -40,11 +40,11 @@
%% towards diameter_service
-export([make_recvdata/1,
peer_up/1,
- peer_down/1,
- pending/1]).
+ peer_down/1]).
-%% towards ?MODULE
--export([send/1]). %% send from remote node
+%% internal
+-export([send/1, %% send from remote node
+ init/1]). %% monitor process start
-include_lib("diameter/include/diameter.hrl").
-include("diameter_internal.hrl").
@@ -57,14 +57,12 @@
-define(DEFAULT_TIMEOUT, 5000). %% for outgoing requests
-define(DEFAULT_SPAWN_OPTS, []).
-%% Table containing outgoing requests for which a reply has yet to be
-%% received.
+%% Table containing outgoing entries that live and die with
+%% peer_up/down. The name is historic, since the table used to contain
+%% information about outgoing requests for which an answer has yet to
+%% be received.
-define(REQUEST_TABLE, diameter_request).
-%% Workaround for dialyzer's lack of understanding of match specs.
--type match(T)
- :: T | '_' | '$1' | '$2' | '$3' | '$4'.
-
%% Record diameter:call/4 options are parsed into.
-record(options,
{filter = none :: diameter:peer_filter(),
@@ -72,7 +70,7 @@
timeout = ?DEFAULT_TIMEOUT :: 0..16#FFFFFFFF,
detach = false :: boolean()}).
-%% Term passed back to receive_message/4 with every incoming message.
+%% Term passed back to receive_message/6 with every incoming message.
-record(recvdata,
{peerT :: ets:tid(),
service_name :: diameter:service_name(),
@@ -87,12 +85,12 @@
%% Record stored in diameter_request for each outgoing request.
-record(request,
- {ref :: match(reference()), %% used to receive answer
- caller :: match(pid()), %% calling process
- handler :: match(pid()), %% request process
- transport :: match(pid()), %% peer process
- caps :: match(#diameter_caps{}), %% of connection
- packet :: match(#diameter_packet{})}). %% of request
+ {ref :: reference(), %% used to receive answer
+ caller :: pid() | undefined, %% calling process
+ handler :: pid(), %% request process
+ transport :: pid() | undefined, %% peer process
+ caps :: #diameter_caps{} | undefined, %% of connection
+ packet :: #diameter_packet{} | undefined}). %% of request
%% ---------------------------------------------------------------------------
%% # make_recvdata/1
@@ -113,18 +111,27 @@ make_recvdata([SvcName, PeerT, Apps, SvcOpts | _]) ->
%% peer_up/1
%% ---------------------------------------------------------------------------
-%% Insert an element that is used to detect whether or not there has
-%% been a failover when inserting an outgoing request.
+%% Start a process that dies with peer_down/1, on which request
+%% processes can monitor. There is no other process that dies with
+%% peer_down since failover doesn't imply the loss of transport in the
+%% case of a watchdog transition into state SUSPECT.
peer_up(TPid) ->
- ets:insert(?REQUEST_TABLE, {TPid}).
+ proc_lib:start(?MODULE, init, [TPid]).
+
+init(TPid) ->
+ ets:insert(?REQUEST_TABLE, {TPid, self()}),
+ proc_lib:init_ack(self()),
+ proc_lib:hibernate(erlang, exit, [{shutdown, TPid}]).
%% ---------------------------------------------------------------------------
%% peer_down/1
%% ---------------------------------------------------------------------------
peer_down(TPid) ->
+ [{_, Pid}] = ets:lookup(?REQUEST_TABLE, TPid),
ets:delete(?REQUEST_TABLE, TPid),
- failover(TPid).
+ Pid ! ok, %% make it die
+ Pid.
%% ---------------------------------------------------------------------------
%% incr/4
@@ -199,54 +206,25 @@ incr_rc(Dir, Pkt, TPid, Dict0) ->
incr_rc(Dir, Pkt, TPid, {Dict0, Dict0, Dict0}).
%% ---------------------------------------------------------------------------
-%% pending/1
-%% ---------------------------------------------------------------------------
-
-pending(TPids) ->
- MatchSpec = [{{'$1',
- #request{caller = '$2',
- handler = '$3',
- transport = '$4',
- _ = '_'},
- '_'},
- [?ORCOND([{'==', T, '$4'} || T <- TPids])],
- [{{'$1', [{{caller, '$2'}},
- {{handler, '$3'}},
- {{transport, '$4'}}]}}]}],
-
- try
- ets:select(?REQUEST_TABLE, MatchSpec)
- catch
- error: badarg -> [] %% service has gone down
- end.
-
-%% ---------------------------------------------------------------------------
-%% # receive_message/4
+%% # receive_message/6
%%
%% Handle an incoming Diameter message.
%% ---------------------------------------------------------------------------
-%% Handle an incoming Diameter message in the watchdog process. This
-%% used to come through the service process but this avoids that
-%% becoming a bottleneck.
+%% Handle an incoming Diameter message in the watchdog process.
-receive_message(TPid, {Pkt, NPid}, Dict0, RecvData) ->
- NPid ! {diameter, incoming(TPid, Pkt, Dict0, RecvData)};
+receive_message(TPid, Route, Pkt, false, Dict0, RecvData) ->
+ incoming(TPid, Route, Pkt, Dict0, RecvData);
-receive_message(TPid, Pkt, Dict0, RecvData) ->
- incoming(TPid, Pkt, Dict0, RecvData).
+receive_message(TPid, Route, Pkt, NPid, Dict0, RecvData) ->
+ NPid ! {diameter, incoming(TPid, Route, Pkt, Dict0, RecvData)}.
%% incoming/4
-incoming(TPid, Pkt, Dict0, RecvData)
+incoming(TPid, Route, Pkt, Dict0, RecvData)
when is_pid(TPid) ->
#diameter_packet{header = #diameter_header{is_request = R}} = Pkt,
- recv(R,
- (not R) andalso lookup_request(Pkt, TPid),
- TPid,
- Pkt,
- Dict0,
- RecvData).
+ recv(R, Route, TPid, Pkt, Dict0, RecvData).
%% recv/6
@@ -261,8 +239,8 @@ recv(true, false, TPid, Pkt, Dict0, T) ->
end;
%% ... answer to known request ...
-recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) ->
- Pid ! {answer, Ref, Req, Dict0, Pkt},
+recv(false, {Pid, Ref, TPid}, _, Pkt, Dict0, _) ->
+ Pid ! {answer, Ref, TPid, Dict0, Pkt},
{answer, Pid};
%% Note that failover could have happened prior to this message being
@@ -911,7 +889,7 @@ failed(Rec, FailedAvp, Dict) ->
{'Failed-AVP', [FailedAvp]}
catch
error: _ ->
- Avps = Dict:'get-'('AVP', Rec),
+ Avps = Dict:'#get-'('AVP', Rec),
A = #diameter_avp{name = 'Failed-AVP',
value = FailedAvp},
{'AVP', [A|Avps]}
@@ -1452,7 +1430,7 @@ make_request_packet(#diameter_packet{header = Hdr} = Pkt,
make_request_packet(Msg, Pkt) ->
Pkt#diameter_packet{msg = Msg}.
-%% make_retransmit_packet/2
+%% make_retransmit_packet/1
make_retransmit_packet(#diameter_packet{msg = [#diameter_header{} = Hdr
| Avps]}
@@ -1495,32 +1473,39 @@ send_R(Pkt0,
packet = Pkt0},
incr(send, Pkt, TPid, AppDict),
- TRef = send_request(TPid, Pkt, Req, SvcName, Timeout),
+ {TRef, MRef} = zend_requezt(TPid, Pkt, Req, SvcName, Timeout),
Pid ! Ref, %% tell caller a send has been attempted
handle_answer(SvcName,
App,
- recv_A(Timeout, SvcName, App, Opts, {TRef, Req})).
+ recv_A(Timeout, SvcName, App, Opts, {TRef, MRef, Req})).
%% recv_A/5
-recv_A(Timeout, SvcName, App, Opts, {TRef, #request{ref = Ref} = Req}) ->
+recv_A(Timeout, SvcName, App, Opts, {TRef, MRef, #request{ref = Ref} = Req}) ->
%% Matching on TRef below ensures we ignore messages that pertain
%% to a previous transport prior to failover. The answer message
- %% includes the #request{} since it's not necessarily Req; that
- %% is, from the last peer to which we've transmitted.
+ %% includes the pid of the transport on which it was received,
+ %% which may not be the last peer to which we've transmitted.
receive
- {answer = A, Ref, Rq, Dict0, Pkt} -> %% Answer from peer
- {A, Rq, Dict0, Pkt};
+ {answer = A, Ref, TPid, Dict0, Pkt} -> %% Answer from peer
+ {A, #request{} = erase(TPid), Dict0, Pkt};
{timeout = Reason, TRef, _} -> %% No timely reply
{error, Req, Reason};
- {failover, TRef} -> %% Service says peer has gone down
- retransmit(pick_peer(SvcName, App, Req, Opts),
- Req,
- Opts,
- SvcName,
- Timeout)
+ {'DOWN', MRef, process, _, _} when false /= MRef -> %% local peer_down
+ failover(SvcName, App, Req, Opts, Timeout);
+ {failover, TRef} -> %% local or remote peer_down
+ failover(SvcName, App, Req, Opts, Timeout)
end.
+%% failover/5
+
+failover(SvcName, App, Req, Opts, Timeout) ->
+ retransmit(pick_peer(SvcName, App, Req, Opts),
+ Req,
+ Opts,
+ SvcName,
+ Timeout).
+
%% handle_answer/3
handle_answer(SvcName, App, {error, Req, Reason}) ->
@@ -1697,47 +1682,63 @@ encode(DictT, TPid, #diameter_packet{bin = undefined} = Pkt) ->
encode(_, _, #diameter_packet{} = Pkt) ->
Pkt.
+%% zend_requezt/5
+%%
+%% Strip potentially large record fields that aren't used by the
+%% processes the records can be send to, possibly on a remote node.
+
+zend_requezt(TPid, Pkt, Req, SvcName, Timeout) ->
+ put(TPid, Req),
+ send_request(TPid, z(Pkt), Req, SvcName, Timeout).
+
%% send_request/5
send_request(TPid, #diameter_packet{bin = Bin} = Pkt, Req, _SvcName, Timeout)
when node() == node(TPid) ->
Seqs = diameter_codec:sequence_numbers(Bin),
TRef = erlang:start_timer(Timeout, self(), TPid),
- Entry = {Seqs, Req, TRef},
-
- %% Ensure that request table is cleaned even if we receive an exit
- %% signal. An alternative would be to simply trap exits, but
- %% callbacks are applied in this process, and these could possibly
- %% be expecting the prevailing behaviour.
- Self = self(),
- spawn(fun() -> diameter_lib:wait([Self]), erase_request(Entry) end),
-
- store_request(Entry, TPid),
- send(TPid, Pkt),
- TRef;
+ send(TPid, Pkt, _Route = {self(), Req#request.ref, Seqs}),
+ {TRef, _MRef = peer_monitor(TPid, TRef)};
%% Send using a remote transport: spawn a process on the remote node
%% to relay the answer.
send_request(TPid, #diameter_packet{} = Pkt, Req, SvcName, Timeout) ->
TRef = erlang:start_timer(Timeout, self(), TPid),
- T = {TPid, Pkt, Req, SvcName, Timeout, TRef},
+ T = {TPid, Pkt, z(Req), SvcName, Timeout, TRef},
spawn(node(TPid), ?MODULE, send, [T]),
- TRef.
+ {TRef, false}.
+
+%% z/1
+%%
+%% Avoid sending potentially large terms unnecessarily. The records
+%% themselves are retained since they're sent between nodes in send/1
+%% and changing what's sent causes upgrade issues.
+
+z(#request{ref = Ref, handler = Pid}) ->
+ #request{ref = Ref,
+ handler = Pid};
+
+z(#diameter_packet{header = H, bin = Bin, transport_data = T}) ->
+ #diameter_packet{header = H,
+ bin = Bin,
+ transport_data = T}.
%% send/1
send({TPid, Pkt, #request{handler = Pid} = Req0, SvcName, Timeout, TRef}) ->
Req = Req0#request{handler = self()},
- recv(TPid, Pid, TRef, send_request(TPid, Pkt, Req, SvcName, Timeout)).
+ recv(TPid, Pid, TRef, zend_requezt(TPid, Pkt, Req, SvcName, Timeout)).
%% recv/4
%%
%% Relay an answer from a remote node.
-recv(TPid, Pid, TRef, LocalTRef) ->
+recv(TPid, Pid, TRef, {LocalTRef, MRef}) ->
receive
{answer, _, _, _, _} = A ->
Pid ! A;
+ {'DOWN', MRef, process, _, _} ->
+ Pid ! {failover, TRef};
{failover = T, LocalTRef} ->
Pid ! {T, TRef};
T ->
@@ -1746,14 +1747,13 @@ recv(TPid, Pid, TRef, LocalTRef) ->
%% send/2
-send(Pid, Pkt) -> %% Strip potentially large message terms.
- #diameter_packet{header = H,
- bin = Bin,
- transport_data = T}
- = Pkt,
- Pid ! {send, #diameter_packet{header = H,
- bin = Bin,
- transport_data = T}}.
+send(Pid, Pkt) ->
+ Pid ! {send, Pkt}.
+
+%% send/3
+
+send(Pid, Pkt, Route) ->
+ Pid ! {send, Pkt, Route}.
%% retransmit/4
@@ -1763,8 +1763,8 @@ retransmit({TPid, Caps, App}
= Req,
SvcName,
Timeout) ->
- have_request(Pkt0, TPid) %% Don't failover to a peer we've
- andalso ?THROW(timeout), %% already sent to.
+ undefined == get(TPid) %% Don't failover to a peer we've
+ orelse ?THROW(timeout), %% already sent to.
Pkt = make_retransmit_packet(Pkt0),
@@ -1774,6 +1774,8 @@ retransmit({TPid, Caps, App}
SvcName,
Timeout,
[]).
+%% When sending a binary, it's up to prepare_retransmit to modify it
+%% accordingly.
retransmit({send, Msg},
Transport,
@@ -1815,77 +1817,20 @@ resend_request(Pkt0,
?LOG(retransmission, Pkt#diameter_packet.header),
incr(TPid, {msg_id(Pkt, AppDict), send, retransmission}),
- TRef = send_request(TPid, Pkt, Req, SvcName, Tmo),
- {TRef, Req}.
+ {TRef, MRef} = zend_requezt(TPid, Pkt, Req, SvcName, Tmo),
+ {TRef, MRef, Req}.
-%% store_request/2
+%% peer_monitor/2
-store_request(T, TPid) ->
- ets:insert(?REQUEST_TABLE, T),
- ets:member(?REQUEST_TABLE, TPid)
- orelse begin
- {_Seqs, _Req, TRef} = T,
- self() ! {failover, TRef} %% failover/1 may have missed
- end.
-
-%% lookup_request/2
-%%
-%% Note the match on both the key and transport pid. The latter is
-%% necessary since the same Hop-by-Hop and End-to-End identifiers are
-%% reused in the case of retransmission.
-
-lookup_request(Msg, TPid) ->
- Seqs = diameter_codec:sequence_numbers(Msg),
- Spec = [{{Seqs, #request{transport = TPid, _ = '_'}, '_'},
- [],
- ['$_']}],
- case ets:select(?REQUEST_TABLE, Spec) of
- [{_, Req, _}] ->
- Req;
- [] ->
+peer_monitor(TPid, TRef) ->
+ case ets:lookup(?REQUEST_TABLE, TPid) of %% at peer_up/1
+ [{_, MPid}] ->
+ monitor(process, MPid);
+ [] -> %% transport has gone down
+ self() ! {failover, TRef},
false
end.
-%% erase_request/1
-
-erase_request(T) ->
- ets:delete_object(?REQUEST_TABLE, T).
-
-%% match_requests/1
-
-match_requests(TPid) ->
- Pat = {'_', #request{transport = TPid, _ = '_'}, '_'},
- ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}]).
-
-%% have_request/2
-
-have_request(Pkt, TPid) ->
- Seqs = diameter_codec:sequence_numbers(Pkt),
- Pat = {Seqs, #request{transport = TPid, _ = '_'}, '_'},
- '$end_of_table' /= ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}], 1).
-
-%% ---------------------------------------------------------------------------
-%% # failover/1-2
-%% ---------------------------------------------------------------------------
-
-failover(TPid)
- when is_pid(TPid) ->
- lists:foreach(fun failover/1, match_requests(TPid));
-%% Note that a request process can store its request after failover
-%% notifications are sent here: store_request/2 sends the notification
-%% in that case.
-
-%% Failover as a consequence of peer_down/1: inform the
-%% request process.
-failover({_, Req, TRef}) ->
- #request{handler = Pid,
- packet = #diameter_packet{msg = M}}
- = Req,
- M /= undefined andalso (Pid ! {failover, TRef}).
-%% Failover is not performed when msg = binary() since sending
-%% pre-encoded binaries is only partially supported. (Mostly for
-%% test.)
-
%% get_destination/2
get_destination(Dict, Msg) ->
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 2ba60a65fb..f28b8f2910 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -283,7 +283,7 @@ event(Msg,
?LOG(transition, {From, To}).
data(Msg, TPid, reopen, okay) ->
- {recv, TPid, 'DWA', _Pkt} = Msg, %% assert
+ {recv, TPid, false, 'DWA', _Pkt, _NPid} = Msg, %% assert
{TPid, T} = eraser(open),
[T];
@@ -447,12 +447,14 @@ transition({'DOWN', _, process, TPid, _Reason} = D,
end;
%% Incoming message.
-transition({recv, TPid, Name, PktT}, #watchdog{transport = TPid} = S) ->
+transition({recv, TPid, Route, Name, Pkt, NPid},
+ #watchdog{transport = TPid}
+ = S) ->
try
- incoming(Name, PktT, S)
+ incoming(Name, Pkt, NPid, S)
catch
#watchdog{dictionary = Dict0, receive_data = T} = NS ->
- diameter_traffic:receive_message(TPid, PktT, Dict0, T),
+ diameter_traffic:receive_message(TPid, Route, Pkt, NPid, Dict0, T),
NS
end;
@@ -582,15 +584,17 @@ send_watchdog(#watchdog{pending = false,
%% Don't count encode errors since we don't expect any on DWR/DWA.
-%% incoming/3
+%% incoming/4
-incoming(Name, {Pkt, NPid}, S) ->
- NS = recv(Name, Pkt, S),
- NPid ! {diameter, discard},
- NS;
+incoming(Name, Pkt, false, S) ->
+ recv(Name, Pkt, S);
-incoming(Name, Pkt, S) ->
- recv(Name, Pkt, S).
+incoming(Name, Pkt, NPid, S) ->
+ try
+ recv(Name, Pkt, S)
+ after
+ NPid ! {diameter, discard}
+ end.
%% recv/3
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index cdaa9aa7f9..864d5f0691 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-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -790,20 +790,7 @@ header() ->
("%% -------------------------------------------------------------------\n"
"%% This is a generated file.\n"
"%% -------------------------------------------------------------------\n"
- "\n"
- "%%\n"
- "%% Copyright (c) Ericsson AB. All rights reserved.\n"
- "%%\n"
- "%% The information in this document is the property of Ericsson.\n"
- "%%\n"
- "%% Except as specifically authorized in writing by Ericsson, the\n"
- "%% receiver of this document shall keep the information contained\n"
- "%% herein confidential and shall protect the same in whole or in\n"
- "%% part from disclosure and dissemination to third parties.\n"
- "%%\n"
- "%% Disclosure and disseminations to the receivers employees shall\n"
- "%% only be made on a strict need to know basis.\n"
- "%%\n\n").
+ "\n").
hrl_header(Name) ->
header() ++ "-hrl_name('" ++ ?S(Name) ++ ".hrl').\n".
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index 618d5a7f10..eb5a5a44f3 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,7 +49,9 @@
{"1.10", [{restart_application, diameter}]}, %% 18.0
{"1.11", [{restart_application, diameter}]}, %% 18.1
{"1.11.1", [{restart_application, diameter}]}, %% 18.2
- {"1.11.2", [{restart_application, diameter}]} %% 18.3
+ {"1.11.2", [{restart_application, diameter}]}, %% 18.3
+ {"1.12", [{restart_application, diameter}]}, %% 19.0
+ {"1.12.1", [{restart_application, diameter}]} %% 19.1
],
[
{"0.9", [{restart_application, diameter}]},
@@ -80,6 +82,8 @@
{"1.10", [{restart_application, diameter}]},
{"1.11", [{restart_application, diameter}]},
{"1.11.1", [{restart_application, diameter}]},
- {"1.11.2", [{restart_application, diameter}]}
+ {"1.11.2", [{restart_application, diameter}]},
+ {"1.12", [{restart_application, diameter}]},
+ {"1.12.1", [{restart_application, diameter}]}
]
}.
diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl
index 4a005b853d..f48e4347ee 100644
--- a/lib/diameter/src/transport/diameter_sctp.erl
+++ b/lib/diameter/src/transport/diameter_sctp.erl
@@ -98,7 +98,7 @@
-record(listener,
{ref :: reference(),
socket :: gen_sctp:sctp_socket(),
- count = 0 :: uint(), %% attached transport processes
+ service = false :: false | pid(), %% service process
pending = {0, queue:new()},
accept :: [match()]}).
%% Field pending implements two queues: the first of transport-to-be
@@ -129,11 +129,14 @@
-> {ok, pid(), [inet:ip_address()]}
when Ref :: diameter:transport_ref().
-start(T, #diameter_service{capabilities = Caps}, Opts)
+start(T, Svc, Opts)
when is_list(Opts) ->
+ #diameter_service{capabilities = Caps,
+ pid = SPid}
+ = Svc,
diameter_sctp_sup:start(), %% start supervisors on demand
Addrs = Caps#diameter_caps.host_ip_address,
- s(T, Addrs, lists:map(fun ip/1, Opts)).
+ s(T, Addrs, SPid, lists:map(fun ip/1, Opts)).
ip({ifaddr, A}) ->
{ip, A};
@@ -144,18 +147,22 @@ ip(T) ->
%% when there is not yet an association to assign it, or at comm_up on
%% a new association in which case the call retrieves a transport from
%% the pending queue.
-s({accept, Ref} = A, Addrs, Opts) ->
- {LPid, LAs} = listener(Ref, {Opts, Addrs}),
- try gen_server:call(LPid, {A, self()}, infinity) of
- {ok, TPid} -> {ok, TPid, LAs}
+s({accept, Ref} = A, Addrs, SPid, Opts) ->
+ {ok, LPid, LAs} = listener(Ref, {Opts, Addrs}),
+ try gen_server:call(LPid, {A, self(), SPid}, infinity) of
+ {ok, TPid} ->
+ {ok, TPid, LAs};
+ No ->
+ {error, No}
catch
- exit: Reason -> {error, Reason}
+ exit: Reason ->
+ {error, Reason}
end;
%% This implementation is due to there being no accept call in
%% gen_sctp in order to be able to accept a new association only
%% *after* an accepting transport has been spawned.
-s({connect = C, Ref}, Addrs, Opts) ->
+s({connect = C, Ref}, Addrs, _SPid, Opts) ->
diameter_sctp_sup:start_child({C, self(), Opts, Addrs, Ref}).
%% start_link/1
@@ -281,24 +288,23 @@ i({K, Ref}, #transport{mode = {accept, _}} = S) ->
%% Accepting processes can be started concurrently: ensure only one
%% listener is started.
-listener(LRef, T) ->
- diameter_sync:call({?MODULE, listener, LRef},
- {?MODULE, listener, [{LRef, T}]},
+listener(Ref, T) ->
+ diameter_sync:call({?MODULE, listener, Ref},
+ {?MODULE, listener, [{Ref, T}]},
infinity,
infinity).
-listener({LRef, T}) ->
- l(diameter_reg:match({?MODULE, listener, {LRef, '_'}}), LRef, T).
+listener({Ref, T}) ->
+ l(diameter_reg:match({?MODULE, listener, {Ref, '_'}}), Ref, T).
%% Existing listening process ...
l([{{?MODULE, listener, {_, AS}}, LPid}], _, _) ->
- {LAs, _Sock} = AS,
- {LPid, LAs};
+ {LAs, _Sock} = AS,
+ {ok, LPid, LAs};
%% ... or not.
-l([], LRef, T) ->
- {ok, LPid, LAs} = diameter_sctp_sup:start_child({listen, LRef, T}),
- {LPid, LAs}.
+l([], Ref, T) ->
+ diameter_sctp_sup:start_child({listen, Ref, T}).
%% open/3
@@ -364,11 +370,17 @@ type(T) ->
%% # handle_call/3
%% ---------------------------------------------------------------------------
-handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref,
- count = K}
- = S) ->
+handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref} = S) ->
{TPid, NewS} = accept(Ref, Pid, S),
- {reply, {ok, TPid}, NewS#listener{count = K+1}};
+ {reply, {ok, TPid}, NewS};
+
+handle_call({{accept, _} = T, Pid, SPid}, From, #listener{service = P} = S) ->
+ handle_call({T, Pid}, From, if not is_pid(P), is_pid(SPid) ->
+ monitor(process, SPid),
+ S#listener{service = SPid};
+ true ->
+ S
+ end);
handle_call(_, _, State) ->
{reply, nok, State}.
@@ -441,6 +453,13 @@ l({sctp, Sock, _RA, _RP, Data} = T, #listener{socket = Sock,
setopts(Sock),
NewS;
+%% Service process has died.
+l({'DOWN', _, process, Pid, _} = T, #listener{service = Pid,
+ socket = Sock}) ->
+ gen_sctp:close(Sock),
+ x(T);
+
+%% Accepting process has died.
l({'DOWN', _MRef, process, TPid, _}, #listener{pending = {_,Q}} = S) ->
down(queue:member(TPid, Q), TPid, S);
@@ -454,20 +473,17 @@ l({transport, remove, _} = T, #listener{socket = Sock}) ->
%% Accepting transport has died.
%% One that's waiting for transport start in the pending queue ...
-down(true, TPid, #listener{pending = {N,Q},
- count = K}
- = S) ->
+down(true, TPid, #listener{pending = {N,Q}} = S) ->
NQ = queue:filter(fun(P) -> P /= TPid end, Q),
if N < 0 -> %% awaiting an association ...
- S#listener{count = K-1,
- pending = {N+1, NQ}};
+ S#listener{pending = {N+1, NQ}};
true -> %% ... or one has been assigned
S#listener{pending = {N-1, NQ}}
end;
%% ... or one that's already attached.
-down(false, _TPid, #listener{count = K} = S) ->
- S#listener{count = K-1}.
+down(false, _TPid, S) ->
+ S.
%% t/2
%%
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index 546c2cfa5e..44abc5c3b4 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -71,11 +71,8 @@
%% a process owning the listening port.
%% Listener process state.
--record(listener, {socket :: inet:socket(),
- count = 1 :: non_neg_integer()}). %% accepting processes
-%% The count of accepting processes was previously used to terminate
-%% the listening process, but diameter_reg:subscribe/2 is now used for
-%% this. Leave the the count for trace purposes.
+-record(listener, {socket :: inet:socket(),
+ service = false :: false | pid()}). %% service process
%% Monitor process state.
-record(monitor,
@@ -138,11 +135,15 @@
| {ok, pid()}
when Ref :: diameter:transport_ref().
-start({T, Ref}, #diameter_service{capabilities = Caps}, Opts) ->
+start({T, Ref}, Svc, Opts) ->
+ #diameter_service{capabilities = Caps,
+ pid = SPid}
+ = Svc,
+
diameter_tcp_sup:start(), %% start tcp supervisors on demand
{Mod, Rest} = split(Opts),
Addrs = Caps#diameter_caps.host_ip_address,
- Arg = {T, Ref, Mod, self(), Rest, Addrs},
+ Arg = {T, Ref, Mod, self(), Rest, Addrs, SPid},
diameter_tcp_sup:start_child(Arg).
split([{module, M} | Opts]) ->
@@ -196,7 +197,7 @@ init(T) ->
%% i/1
%% A transport process.
-i({T, Ref, Mod, Pid, Opts, Addrs})
+i({T, Ref, Mod, Pid, Opts, Addrs, SPid})
when T == accept;
T == connect ->
monitor(process, Pid),
@@ -214,7 +215,7 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
?DEFAULT_FRAGMENT_TIMEOUT),
?IS_TIMEOUT(Tmo) orelse ?ERROR({fragment_timer, Tmo}),
Throttle = proplists:get_value(throttle_cb, OwnOpts, false),
- Sock = init(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
+ Sock = init(T, Ref, Mod, Pid, SslOpts, Rest, Addrs, SPid),
MPid ! {stop, self()}, %% tell the monitor to die
M = if SslOpts -> ssl; true -> Mod end,
putr(?REF_KEY, Ref),
@@ -228,6 +229,11 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
%% Put the reference in the process dictionary since we now use it
%% advertise the ssl socket after TLS upgrade.
+i({T, _Ref, _Mod, _Pid, _Opts, _Addrs} = Arg) %% from old code
+ when T == accept;
+ T == connect ->
+ i(erlang:append_element(Arg, _SPid = false));
+
%% A monitor process to kill the transport if the parent dies.
i(#monitor{parent = Pid, transport = TPid} = S) ->
proc_lib:init_ack({ok, self()}),
@@ -240,16 +246,18 @@ i(#monitor{parent = Pid, transport = TPid} = S) ->
%% death. However, a link can be unlinked and this is exactly what
%% gen_tcp seems to so. Links should be left to supervisors.
-i({listen, LRef, APid, {Mod, Opts, Addrs}}) ->
- [_] = diameter_config:subscribe(LRef, transport), %% assert existence
+i({listen = L, Ref, _APid, T}) -> %% from old code
+ i({L, Ref, T});
+
+i({listen, Ref, {Mod, Opts, Addrs}}) ->
+ [_] = diameter_config:subscribe(Ref, transport), %% assert existence
{[LA, LP], Rest} = proplists:split(Opts, [ip, port]),
LAddrOpt = get_addr(LA, Addrs),
LPort = get_port(LP),
{ok, LSock} = Mod:listen(LPort, gen_opts(LAddrOpt, Rest)),
LAddr = laddr(LAddrOpt, Mod, LSock),
- true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}),
+ true = diameter_reg:add_new({?MODULE, listener, {Ref, {LAddr, LSock}}}),
proc_lib:init_ack({ok, self(), {LAddr, LSock}}),
- monitor(process, APid),
#listener{socket = LSock}.
laddr([], Mod, Sock) ->
@@ -268,21 +276,22 @@ ssl_opts([{ssl_options, Opts}])
ssl_opts(T) ->
?ERROR({ssl_options, T}).
-%% init/7
+%% init/8
%% Establish a TLS connection before capabilities exchange ...
-init(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
- init(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
+init(Type, Ref, Mod, Pid, true, Opts, Addrs, SPid) ->
+ init(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs, SPid);
%% ... or not.
-init(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
- init(Type, Ref, Mod, Pid, Opts, Addrs).
+init(Type, Ref, Mod, Pid, _, Opts, Addrs, SPid) ->
+ init(Type, Ref, Mod, Pid, Opts, Addrs, SPid).
-%% init/6
+%% init/7
-init(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(accept = T, Ref, Mod, Pid, Opts, Addrs, SPid) ->
{[Matches], Rest} = proplists:split(Opts, [accept]),
- {LAddr, LSock} = listener(Ref, {Mod, Rest, Addrs}),
+ {ok, LPid, {LAddr, LSock}} = listener(Ref, {Mod, Rest, Addrs}),
+ ok = gen_server:call(LPid, {accept, SPid}, infinity),
proc_lib:init_ack({ok, self(), [LAddr]}),
Sock = ok(accept(Mod, LSock)),
ok = accept_peer(Mod, Sock, accept(Matches)),
@@ -290,7 +299,7 @@ init(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
diameter_peer:up(Pid),
Sock;
-init(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(connect = T, Ref, Mod, Pid, Opts, Addrs, _SPid) ->
{[LA, RA, RP], Rest} = proplists:split(Opts, [ip, raddr, rport]),
LAddrOpt = get_addr(LA, Addrs),
RAddr = get_addr(RA),
@@ -344,24 +353,26 @@ accept(Opts) ->
%% Accepting processes can be started concurrently: ensure only one
%% listener is started.
-listener(LRef, T) ->
- diameter_sync:call({?MODULE, listener, LRef},
- {?MODULE, listener, [{LRef, T, self()}]},
+listener(Ref, T) ->
+ diameter_sync:call({?MODULE, listener, Ref},
+ {?MODULE, listener, [{Ref, T, self()}]},
infinity,
infinity).
-listener({LRef, T, TPid}) ->
- l(diameter_reg:match({?MODULE, listener, {LRef, '_'}}), LRef, T, TPid).
+%% listener/1
+
+listener({Ref, T, _TPid}) ->
+ l(diameter_reg:match({?MODULE, listener, {Ref, '_'}}), Ref, T).
+
+%% l/3
%% Existing listening process ...
-l([{{?MODULE, listener, {_, AS}}, LPid}], _, _, TPid) ->
- LPid ! {accept, TPid},
- AS;
+l([{{?MODULE, listener, {_, AS}}, LPid}], _, _) ->
+ {ok, LPid, AS};
%% ... or not.
-l([], LRef, T, TPid) ->
- {ok, _, AS} = diameter_tcp_sup:start_child({listen, LRef, TPid, T}),
- AS.
+l([], Ref, T) ->
+ diameter_tcp_sup:start_child({listen, Ref, T}).
%% get_addr/1
@@ -440,6 +451,14 @@ portnr(Sock) ->
%% # handle_call/3
%% ---------------------------------------------------------------------------
+handle_call({accept, SPid}, _From, #listener{service = P} = S) ->
+ {reply, ok, if not is_pid(P), is_pid(SPid) ->
+ monitor(process, SPid),
+ S#listener{service = SPid};
+ true ->
+ S
+ end};
+
handle_call(_, _, State) ->
{reply, nok, State}.
@@ -507,19 +526,20 @@ m({'DOWN', _, process, Pid, _}, #monitor{parent = Pid,
%%
%% Transition listener state.
-%% An accepting transport is attaching.
-l({accept, TPid}, #listener{count = N} = S) ->
- monitor(process, TPid),
- S#listener{count = N+1};
-
-%% Accepting process has died.
-l({'DOWN', _, process, _, _}, #listener{count = N} = S) ->
- S#listener{count = N-1};
+%% Service process has died.
+l({'DOWN', _, process, Pid, _} = T, #listener{service = Pid,
+ socket = Sock}) ->
+ gen_tcp:close(Sock),
+ x(T);
%% Transport has been removed.
l({transport, remove, _} = T, #listener{socket = Sock}) ->
gen_tcp:close(Sock),
- x(T).
+ x(T);
+
+%% Possibly death of an accepting process monitored in old code.
+l(_, S) ->
+ S.
%% t/2
%%
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index 37c41a1761..869797f11f 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl
index b5e520e642..5353688bf4 100644
--- a/lib/diameter/test/diameter_relay_SUITE.erl
+++ b/lib/diameter/test/diameter_relay_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 6f3a4801ee..4c82d4dee2 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -248,17 +248,14 @@ all() ->
groups() ->
Ts = tc(),
Sctp = ?util:have_sctp(),
- [{?util:name([R,D,A,C]), [parallel], Ts} || R <- ?ENCODINGS,
- D <- ?RFCS,
- A <- ?ENCODINGS,
- C <- ?CONTAINERS]
+ [{B, [P], Ts} || {B,P} <- [{true, shuffle}, {false, parallel}]]
++
[{?util:name([T,R,D,A,C,SD,CD]),
[],
[start_services,
add_transports,
result_codes,
- {group, ?util:name([R,D,A,C])},
+ {group, SD orelse CD},
remove_transports,
stop_services]}
|| T <- ?TRANSPORTS,
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index 37fcbbc267..cca28dd23c 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -195,13 +195,21 @@ unique_string() ->
%% have_sctp/0
have_sctp() ->
- case gen_sctp:open() of
- {ok, Sock} ->
- gen_sctp:close(Sock),
- true;
- {error, E} when E == eprotonosupport;
- E == esocktnosupport -> %% fail on any other reason
- false
+ case erlang:system_info(system_architecture) of
+ %% We do not support the sctp version present in solaris
+ %% version "sparc-sun-solaris2.10", that behaves differently
+ %% from later versions and linux
+ "sparc-sun-solaris2.10" ->
+ false;
+ _->
+ case gen_sctp:open() of
+ {ok, Sock} ->
+ gen_sctp:close(Sock),
+ true;
+ {error, E} when E == eprotonosupport;
+ E == esocktnosupport -> %% fail on any other reason
+ false
+ end
end.
%% ---------------------------------------------------------------------------
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index cb750c69a3..94d9d72a48 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -1,6 +1,6 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2016. All Rights Reserved.
+# Copyright Ericsson AB 2010-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 1.12
+DIAMETER_VSN = 1.12.2
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/edoc/doc/overview.edoc b/lib/edoc/doc/overview.edoc
index d2bba9d744..3a2118928a 100644
--- a/lib/edoc/doc/overview.edoc
+++ b/lib/edoc/doc/overview.edoc
@@ -377,6 +377,12 @@ The following tags can be used before a function definition:
Useful for debug/test functions, etc. The content can be
used as a comment; it is ignored by EDoc.</dd>
+ <dt><a name="ftag-param">`@param'</a></dt>
+ <dd>Provide more information on a single parameter of the
+ enclosing function. The content consists of a parameter name,
+ followed by one or more whitespace characters, and XHTML text.
+ </dd>
+
<dt><a name="ftag-private">`@private'</a></dt>
<dd>Marks the function as private (i.e., not part of the public
interface), so that it will not appear in the normal
@@ -386,6 +392,10 @@ The following tags can be used before a function definition:
always "private".) The content can be used as a comment; it is
ignored by EDoc.</dd>
+ <dt><a name="ftag-returns">`@returns'</a></dt>
+ <dd>Specify additional information about the value returned by
+ the function. Content consists of XHTML text.</dd>
+
<dt><a name="ftag-see">`@see'</a></dt>
<dd>Make a reference to a module, function, datatype, or
application. (See {@section References}.)
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index ae8147c564..4982488335 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -32,6 +32,36 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.8.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Document the function tags <c>@param</c> and
+ <c>@returns</c>. </p>
+ <p>
+ Own Id: OTP-13930 Aux Id: PR-1175 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.8</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Improve types and specs in OTP documentation generated
+ from Erlang source files. </p>
+ <p>
+ Own Id: OTP-13720 Aux Id: ERL-120 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.7.19</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/edoc/include/edoc_doclet.hrl b/lib/edoc/include/edoc_doclet.hrl
index ac6763fb33..9893ff3ee0 100644
--- a/lib/edoc/include/edoc_doclet.hrl
+++ b/lib/edoc/include/edoc_doclet.hrl
@@ -15,7 +15,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Author contact: [email protected]
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index 94013bb5ac..7d61b9e9c5 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2007 Richard Carlsson
diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl
index 5b0fb68cf9..4b28c0b12e 100644
--- a/lib/edoc/src/edoc.hrl
+++ b/lib/edoc/src/edoc.hrl
@@ -15,7 +15,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Author contact: [email protected]
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index b797d74a71..86273b8352 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl
index 5961ca8cc0..9128c19a4d 100644
--- a/lib/edoc/src/edoc_doclet.erl
+++ b/lib/edoc/src/edoc_doclet.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2003-2006 Richard Carlsson
diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl
index e7a4c36ca4..5c8c648319 100644
--- a/lib/edoc/src/edoc_extract.erl
+++ b/lib/edoc/src/edoc_extract.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2003 Richard Carlsson
@@ -32,9 +32,9 @@
%% %% @headerfile "edoc.hrl" (disabled until it can be made private)
-include("edoc.hrl").
-%% @type filename() = file:filename().
-%% @type proplist() = proplists:property().
-%% @type syntaxTree() = erl_syntax:syntaxTree().
+%% @type filename() = //kernel/file:filename().
+%% @type proplist() = //stdlib/proplists:property().
+%% @type syntaxTree() = //syntax_tools/erl_syntax:syntaxTree().
%% @spec source(File::filename(), Env::edoc_env(), Options::proplist())
%% -> {ModuleName, edoc:edoc_module()}
@@ -639,11 +639,11 @@ file_macros(_Context, Env) ->
%%
%% The idea is to mimic how the @type tag works.
%% Using @type:
-%% @type t() = t1(). Some docs of t/0;
-%% Further docs of t/0.
+%%```@type t() = t1(). Some docs of t/0;
+%% Further docs of t/0.'''
%% The same thing using -type:
-%% -type t() :: t1(). % Some docs of t/0;
-%% Further docs of t/0.
+%%```-type t() :: t1(). % Some docs of t/0;
+%% Further docs of t/0.'''
find_type_docs(Forms0, Comments, Env, File) ->
Tree = erl_recomment:recomment_forms(Forms0, Comments),
Forms = preprocess_forms(Tree),
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index ef57b7b084..41a0b193ec 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index dcc239f6b4..8fbc83fa29 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2003 Richard Carlsson
@@ -935,7 +935,7 @@ get_doc_env(Opts) ->
%% Modules = [atom()]
%% proplist() = [term()]
%%
-%% @type proplist() = proplists:property().
+%% @type proplist() = //stdlib/proplists:property().
%% @type edoc_env(). Environment information needed by EDoc for
%% generating references. The data representation is not documented.
%%
diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl
index e1a54d5090..7c91cb0f57 100644
--- a/lib/edoc/src/edoc_macros.erl
+++ b/lib/edoc/src/edoc_macros.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl
index b9a9391053..9a45d5b0fa 100644
--- a/lib/edoc/src/edoc_refs.erl
+++ b/lib/edoc/src/edoc_refs.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_report.erl b/lib/edoc/src/edoc_report.erl
index dc6320df6d..ce54e71538 100644
--- a/lib/edoc/src/edoc_report.erl
+++ b/lib/edoc/src/edoc_report.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_run.erl b/lib/edoc/src/edoc_run.erl
index 261a649c70..d69bddc999 100644
--- a/lib/edoc/src/edoc_run.erl
+++ b/lib/edoc/src/edoc_run.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2003 Richard Carlsson
diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl
index 9e2e41e902..919159e125 100644
--- a/lib/edoc/src/edoc_tags.erl
+++ b/lib/edoc/src/edoc_tags.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
@@ -213,8 +213,10 @@ filter_tags([#tag{name = N, line = L} = T | Ts], Tags, Where, Ts1) ->
true ->
filter_tags(Ts, Tags, Where, [T | Ts1]);
false ->
- [warning(L, Where, "tag @~s not recognized.", [N]) ||
- Where =/= no],
+ case Where of
+ no -> ok;
+ _ -> warning(L, Where, "tag @~s not recognized.", [N])
+ end,
filter_tags(Ts, Tags, Where, Ts1)
end;
filter_tags([], _, _, Ts) ->
@@ -451,7 +453,7 @@ check_type(#tag{line = L, data = Data}, P0, Ls, Ts) ->
check_type(#t_def{type = Type}, P, Ls, Ts) ->
check_type(Type, P, Ls, Ts);
check_type(#t_type{name = Name, args = Args}, P, Ls, Ts) ->
- _ = check_used_type(Name, Args, P, Ls),
+ check_used_type(Name, Args, P, Ls),
check_types3(Args++Ts, P, Ls);
check_type(#t_var{}, P, Ls, Ts) ->
check_types3(Ts, P, Ls);
@@ -503,7 +505,8 @@ check_used_type(#t_name{name = N, module = Mod}=Name, Args, P, LocalTypes) ->
false ->
#parms{warn = W, line = L, file = File} = P,
%% true = ets:insert(DT, TypeName),
- [type_warning(L, File, "missing type", N, NArgs) || W]
+ _ = [type_warning(L, File, "missing type", N, NArgs) || W],
+ ok
end.
type_warning(Line, File, S, N, NArgs) ->
diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl
index 5bb68e79fb..bd4a583b8e 100644
--- a/lib/edoc/src/edoc_types.erl
+++ b/lib/edoc/src/edoc_types.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_types.hrl b/lib/edoc/src/edoc_types.hrl
index 3e5e91484f..3f502068af 100644
--- a/lib/edoc/src/edoc_types.hrl
+++ b/lib/edoc/src/edoc_types.hrl
@@ -15,7 +15,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Author contact: [email protected]
diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl
index 5d0d78bf3c..5d15bbcfcc 100644
--- a/lib/edoc/src/edoc_wiki.erl
+++ b/lib/edoc/src/edoc_wiki.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/otpsgml_layout.erl b/lib/edoc/src/otpsgml_layout.erl
index 052c75b9d4..8458a52f2d 100644
--- a/lib/edoc/src/otpsgml_layout.erl
+++ b/lib/edoc/src/otpsgml_layout.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index f38800b3e0..d66802fdac 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.19
+EDOC_VSN = 0.8.1
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index 43873e44e2..f2c7889e58 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -197,7 +197,7 @@
</type>
<desc>
<p> Add an entry. The entry must not exist.</p>
- <pre>
+ <code>
add(Handle,
"cn=Bill Valentine, ou=people, o=Example Org, dc=example, dc=com",
[{"objectclass", ["person"]},
@@ -205,7 +205,7 @@
{"sn", ["Valentine"]},
{"telephoneNumber", ["545 555 00"]}]
)
- </pre>
+ </code>
</desc>
</func>
<func>
@@ -216,9 +216,9 @@
</type>
<desc>
<p> Delete an entry.</p>
- <pre>
+ <code>
delete(Handle, "cn=Bill Valentine, ou=people, o=Example Org, dc=example, dc=com")
- </pre>
+ </code>
</desc>
</func>
@@ -259,11 +259,11 @@
</type>
<desc>
<p> Modify an entry.</p>
- <pre>
+ <code>
modify(Handle, "cn=Bill Valentine, ou=people, o=Example Org, dc=example, dc=com",
[eldap:mod_replace("telephoneNumber", ["555 555 00"]),
eldap:mod_add("description", ["LDAP Hacker"]) ])
- </pre>
+ </code>
</desc>
</func>
<func>
@@ -320,10 +320,10 @@
whether the current RDN should be removed from the attribute list after the after operation.
<c>NewSupDN</c> is the new parent that the RDN shall be moved to. If the old parent should
remain as parent, <c>NewSupDN</c> shall be "".</p>
- <pre>
+ <code>
modify_dn(Handle, "cn=Bill Valentine, ou=people, o=Example Org, dc=example, dc=com ",
"cn=Bill Jr Valentine", true, "")
- </pre>
+ </code>
</desc>
</func>
<func>
@@ -342,10 +342,10 @@
Default values: scope is <c>wholeSubtree()</c>, deref is <c>derefAlways()</c>,
types_only is <c>false</c> and timeout is <c>0</c> (meaning infinity).
</p>
- <pre>
+ <code>
Filter = eldap:substrings("cn", [{any,"V"}]),
search(Handle, [{base, "dc=example, dc=com"}, {filter, Filter}, {attributes, ["cn"]}]),
- </pre>
+ </code>
<p>The <c>timeout</c> option in the <c>SearchOptions</c> is for the ldap server, while
the timeout in <seealso marker="#open/2">eldap:open/2</seealso> is used for each
individual request in the search operation.
@@ -454,7 +454,7 @@
</type>
<desc> <p>Creates an extensible match filter. For example, </p>
<code>
- eldap:extensibleMatch("Bar", [{type,"sn"}, {matchingRule,"caseExactMatch"}]))
+ eldap:extensibleMatch("Bar", [{type,"sn"}, {matchingRule,"caseExactMatch"}]))
</code>
<p>creates a filter which performs a <c>caseExactMatch</c> on the attribute <c>sn</c> and matches with the value <c>"Bar"</c>. The default value of <c>dnAttributes</c> is <c>false</c>.</p> </desc>
</func>
diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile
index 21a0da926f..81fa8f187a 100644
--- a/lib/eldap/test/Makefile
+++ b/lib/eldap/test/Makefile
@@ -42,7 +42,7 @@ TARGET_FILES= \
SPEC_FILES = eldap.spec
-# COVER_FILE = eldap.cover
+COVER_FILE = eldap.cover
# ----------------------------------------------------
diff --git a/lib/eldap/test/eldap.cover b/lib/eldap/test/eldap.cover
new file mode 100644
index 0000000000..8c15956e72
--- /dev/null
+++ b/lib/eldap/test/eldap.cover
@@ -0,0 +1,3 @@
+{incl_app,eldap,details}.
+
+{excl_mods, eldap, ['ELDAPv3']}.
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index 21dc617d55..4824a755d9 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -31,7 +31,39 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.5</title>
+ <section><title>Erl_Docgen 0.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Docgen would previously emit "utf8" as the default
+ encoding in xml. This has now been remedied by emitting
+ the correct string "UTF-8" instead.</p>
+ <p>
+ Own Id: OTP-13971</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Improve types and specs in OTP documentation generated
+ from Erlang source files. </p>
+ <p>
+ Own Id: OTP-13720 Aux Id: ERL-120 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/erl_docgen/priv/bin/xref_mod_app.escript b/lib/erl_docgen/priv/bin/xref_mod_app.escript
index ac4278bf22..4a418fe144 100755
--- a/lib/erl_docgen/priv/bin/xref_mod_app.escript
+++ b/lib/erl_docgen/priv/bin/xref_mod_app.escript
@@ -84,7 +84,7 @@ preloaded(TopDir) ->
%% It's OK if too much data is generated as long as all applications
%% and all modules are mentioned.
appmods(D) ->
- ErlFiles = filelib:wildcard(filename:join([D,"src","*.erl"])),
+ ErlFiles = filelib:wildcard(filename:join([D,"src","**","*.erl"])),
AppV = filename:basename(D),
App = case string:rstr(AppV, "-") of
0 -> AppV;
diff --git a/lib/erl_docgen/priv/dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd
index 835407520a..615b88b61a 100644
--- a/lib/erl_docgen/priv/dtd/erlref.dtd
+++ b/lib/erl_docgen/priv/dtd/erlref.dtd
@@ -29,7 +29,7 @@
<!-- `name' is used in common.refs.dtd and must therefore
be defined in each *ref. dtd -->
-<!ELEMENT name (#PCDATA) >
+<!ELEMENT name (#PCDATA|seealso)* >
<!ATTLIST name name CDATA #IMPLIED
arity CDATA #IMPLIED
clause_i CDATA #IMPLIED
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index fe6c7d3c28..edab8e1c7e 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -2007,10 +2007,10 @@
</xsl:variable>
<xsl:choose>
<xsl:when test="ancestor::datatype">
- <a name="type-{$fname}"><span class="bold_code"><xsl:value-of select="."/></span></a><br/>
+ <a name="type-{$fname}"></a><span class="bold_code"><xsl:apply-templates/></span><br/>
</xsl:when>
<xsl:otherwise>
- <a name="{$fname}-{$arity}"><span class="bold_code"><xsl:value-of select="."/></span></a><br/>
+ <a name="{$fname}-{$arity}"></a><span class="bold_code"><xsl:apply-templates/></span><br/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index 0ac7985a48..13ff0a139d 100644
--- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -111,7 +111,16 @@ root_attributes(Element, Opts) ->
Enc ->
Enc
end,
- [#xmlAttribute{name=encoding, value=Encoding}].
+ [#xmlAttribute{name=encoding, value=reformat_encoding(Encoding)}].
+
+%% epp:default_encoding/0 returns 'utf8'
+reformat_encoding(utf8) -> "UTF-8";
+reformat_encoding(List) when is_list(List) ->
+ case string:to_lower(List) of
+ "utf8" -> "UTF-8";
+ _ -> List
+ end;
+reformat_encoding(Other) -> Other.
layout_chapter(#xmlElement{name=overview, content=Es}) ->
Title = get_text(title, Es),
@@ -563,7 +572,14 @@ otp_xmlify_a_fileref(FileRef1, AppS) ->
true ->
case split(Marker0, "-") of
[Func,Arity] ->
- Func++"/"++Arity;
+ try list_to_integer(Arity) of
+ _ ->
+ Func++"/"++Arity
+ catch
+ _:_ ->
+ %% This is "type-"<a-type>.
+ Marker0
+ end;
_ ->
Marker0
end
@@ -831,19 +847,49 @@ local_types([]) -> [];
local_types(Es) ->
local_defs2(get_elem(localdef, Es)).
+-define(LOCAL_TYPES, edoc_local_defs).
+
local_defs2([]) -> [];
local_defs2(Es) ->
+ case collect_local_types(Es) of
+ [] -> local_defs3(Es);
+ LocalTypes ->
+ ?LOCAL_TYPES = ets:new(?LOCAL_TYPES, [named_table]),
+ true = ets:insert(?LOCAL_TYPES, LocalTypes),
+ try
+ local_defs3(Es)
+ after
+ ets:delete(?LOCAL_TYPES)
+ end
+ end.
+
+local_defs3(Es) ->
{type,[?NL | [{v, localdef2(E)} || E <- Es]]}.
+%% Does not work well for parametrized types.
+collect_local_types(Es) ->
+ lists:append([collect_local_type(E) || E <- Es]).
+
+collect_local_type(#xmlElement{content = Es}) ->
+ case get_elem(typevar, Es) of
+ [] ->
+ [{t_abstype(get_content(abstype, Es))}];
+ [_] ->
+ []
+ end.
+
%% Like localdef/1, but does not use label_anchor/2 -- we don't want any
%% markers or em tags in <v> tag, plain text only!
+%% When used stand-alone, EDoc generates links to local types. An ETS
+%% table holds local types, to avoid generating links to them.
localdef2(#xmlElement{content = Es}) ->
- case get_elem(typevar, Es) of
- [] ->
- t_utype(get_elem(type, Es));
- [V] ->
- t_var(V) ++ [" = "] ++ t_utype(get_elem(type, Es))
- end.
+ Var = case get_elem(typevar, Es) of
+ [] ->
+ [t_abstype(get_content(abstype, Es))];
+ [V] ->
+ t_var(V)
+ end,
+ Var ++ [" = "] ++ t_utype(get_elem(type, Es)).
type_name(#xmlElement{content = Es}) ->
t_name(get_elem(erlangName, get_content(typedef, Es))).
@@ -855,10 +901,9 @@ types(Ts) ->
typedecl(Name, #xmlElement{content = Es}) ->
TypedefEs = get_content(typedef, Es),
Id = "type-"++Name,
- [{tag, typedef(TypedefEs)},
+ [{tag, [{marker,[{id,Id}],[]}] ++ typedef(TypedefEs)},
?NL,
- {item, [{marker,[{id,Id}],[]} |
- local_defs(get_elem(localdef, TypedefEs)) ++ fulldesc(Es)]},
+ {item, local_defs(get_elem(localdef, TypedefEs)) ++ fulldesc(Es)},
?NL].
typedef(Es) ->
@@ -866,14 +911,14 @@ typedef(Es) ->
++ seq(fun t_utype_elem/1, get_content(argtypes, Es), [")"])),
case get_elem(type, Es) of
[] ->
- [{tt, Name}];
+ Name;
Type ->
- [{tt, Name ++ [" = "] ++ t_utype(Type)}]
+ Name ++ [" = "] ++ t_utype(Type)
end.
-local_defs([]) -> [];
+local_defs([]) -> [{p,[]}];
local_defs(Es) ->
- [?NL, {ul, [{li, [{tt, localdef(E)}]} || E <- Es]}].
+ [?NL, {ul, [{li, [{p, localdef(E)}]} || E <- Es]}].
localdef(E = #xmlElement{content = Es}) ->
Var = case get_elem(typevar, Es) of
@@ -917,6 +962,7 @@ seealso_module(Es) ->
Es1 ->
{section,[{title,["See also"]},{p,seq(fun see/1, Es1, [])}]}
end.
+
seealso_function(Es) ->
case get_elem(see, Es) of
[] -> [];
@@ -988,7 +1034,14 @@ t_name([E]) ->
end.
t_utype([E]) ->
- t_utype_elem(E).
+ flatten_type(t_utype_elem(E)).
+
+%% Make sure see also are top elements of lists.
+flatten_type(T) ->
+ [case is_integer(E) of
+ true -> [E];
+ false -> E
+ end || E <- lists:flatten(T)].
t_utype_elem(E=#xmlElement{content = Es}) ->
case get_attrval(name, E) of
@@ -1021,16 +1074,14 @@ t_type([#xmlElement{name = tuple, content = Es}]) ->
t_tuple(Es);
t_type([#xmlElement{name = 'fun', content = Es}]) ->
t_fun(Es);
-t_type([#xmlElement{name = abstype, content = Es}]) ->
- t_abstype(Es);
+t_type([E = #xmlElement{name = abstype, content = Es}]) ->
+ t_abstype(E, Es);
t_type([#xmlElement{name = union, content = Es}]) ->
t_union(Es);
t_type([#xmlElement{name = record, content = Es}]) ->
t_record(Es);
t_type([#xmlElement{name = map, content = Es}]) ->
- t_map(Es);
-t_type([#xmlElement{name = map_field, content = Es}]) ->
- t_map_field(Es).
+ t_map(Es).
t_var(E) ->
[get_attrval(name, E)].
@@ -1065,35 +1116,53 @@ t_fun(Es) ->
t_record([E|Es]) ->
["#", get_attrval(value, E), "{"++ seq(fun t_field/1, Es) ++"}"].
+
t_field(#xmlElement{name=field, content=[Atom,Type]}) ->
[get_attrval(value, Atom), "="] ++ t_utype_elem(Type).
t_map(Es) ->
- ["#{"] ++ seq(fun t_utype_elem/1, Es, ["}"]).
+ ["#{"] ++ seq(fun t_map_field/1, Es, ["}"]).
+
+t_map_field(E = #xmlElement{name = map_field, content = [K,V]}) ->
+ KElem = t_utype_elem(K),
+ VElem = t_utype_elem(V),
+ AS = case get_attrval(assoc_type, E) of
+ "assoc" -> " => ";
+ "exact" -> " := "
+ end,
+ [KElem ++ AS ++ VElem].
-t_map_field([K,V]) ->
- [t_utype_elem(K) ++ " => " ++ t_utype_elem(V)].
+t_abstype(E, Es) ->
+ see_type(E, t_abstype(Es)).
t_abstype(Es) ->
- case split_at_colon(t_name(get_elem(erlangName, Es)),[]) of
- {Mod,Type} ->
- [Type, "("] ++
- seq(fun t_utype_elem/1, get_elem(type, Es), [")"]) ++
- [" (see module ", Mod, ")"];
- Type ->
- [Type, "("] ++
- seq(fun t_utype_elem/1, get_elem(type, Es), [")"])
+ Name = t_name(get_elem(erlangName, Es)),
+ [Name, "("] ++ seq(fun t_utype_elem/1, get_elem(type, Es), [")"]).
+
+see_type(E, Es0) ->
+ case get_attrval(href, E) of
+ [] -> Es0;
+ Href0 ->
+ try
+ false = is_local_type(Es0),
+ %% Fails for parametrized types:
+ Text = #xmlText{value = lists:append(Es0)},
+ {Href, Es} = otp_xmlify_a_href(Href0, [Text]),
+ [{seealso, [{marker, Href}], Es}]
+ catch
+ _:_ ->
+ Es0
+ end
end.
-%% Split at one colon, but not at two (or more)
-split_at_colon([$:,$:|_]=Rest,Acc) ->
- lists:reverse(Acc)++Rest;
-split_at_colon([$:|Type],Acc) ->
- {lists:reverse(Acc),Type};
-split_at_colon([Char|Rest],Acc) ->
- split_at_colon(Rest,[Char|Acc]);
-split_at_colon([],Acc) ->
- lists:reverse(Acc).
+is_local_type(Es) ->
+ try
+ [_] = ets:lookup(?LOCAL_TYPES, Es),
+ true
+ catch
+ _:_->
+ false
+ end.
t_union(Es) ->
seq(fun t_utype_elem/1, Es, " | ", []).
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 98d1c3f7be..d6106a2823 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.5
+ERL_DOCGEN_VSN = 0.6.1
diff --git a/lib/erl_interface/doc/src/book.xml b/lib/erl_interface/doc/src/book.xml
index c9194d96ff..94bfef7455 100644
--- a/lib/erl_interface/doc/src/book.xml
+++ b/lib/erl_interface/doc/src/book.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,19 +19,19 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
- <title>Erlang Interface</title>
+ <title>Erl_Interface</title>
<prepared>Gordon Beaton</prepared>
<docno></docno>
<date>1998-11-30</date>
<rev>1.2</rev>
- <file>book.sgml</file>
+ <file>book.xml</file>
</header>
<insidecover>
</insidecover>
- <pagetext>Erlang Interface</pagetext>
+ <pagetext>Erl_Interface</pagetext>
<preamble>
<contents level="2"></contents>
</preamble>
@@ -47,4 +47,3 @@
<listofterms></listofterms>
<index></index>
</book>
-
diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml
index 1177954eb9..ddfb4d88a8 100644
--- a/lib/erl_interface/doc/src/ei.xml
+++ b/lib/erl_interface/doc/src/ei.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -30,361 +30,508 @@
<checked></checked>
<date>2000-11-27</date>
<rev>PA1</rev>
- <file>ei.sgml</file>
+ <file>ei.xml</file>
</header>
<lib>ei</lib>
- <libsummary>routines for handling the erlang binary term format</libsummary>
+ <libsummary>Routines for handling the Erlang binary term format.</libsummary>
<description>
- <p>The library <c><![CDATA[ei]]></c> contains macros and functions to encode
- and decode the erlang binary term format.</p>
- <p>With <c><![CDATA[ei]]></c>, you can convert atoms, lists, numbers and
+ <p>The library <c>ei</c> contains macros and functions to encode
+ and decode the Erlang binary term format.</p>
+
+ <p><c>ei</c> allows you to convert atoms, lists, numbers, and
binaries to and from the binary format. This is useful when
- writing port programs and drivers. <c><![CDATA[ei]]></c> uses a given
- buffer, and no dynamic memory (with the exception of
- <c><![CDATA[ei_decode_fun()]]></c>), and is often quite fast.</p>
- <p>It also handles C-nodes, C-programs that talks erlang
- distribution with erlang nodes (or other C-nodes) using the
- erlang distribution format. The difference between <c><![CDATA[ei]]></c> and
- <c><![CDATA[erl_interface]]></c> is that <c><![CDATA[ei]]></c> uses the binary format
- directly when sending and receiving terms. It is also thread
- safe, and using threads, one process can handle multiple
- C-nodes. The <c><![CDATA[erl_interface]]></c> library is built on top of
- <c><![CDATA[ei]]></c>, but of legacy reasons, it doesn't allow for multiple
- C-nodes. In general, <c><![CDATA[ei]]></c> is the preferred way of doing
- C-nodes.</p>
- <p>The decode and encode functions use a buffer an index into the
+ writing port programs and drivers. <c>ei</c> uses a given
+ buffer, no dynamic memory (except
+ <c>ei_decode_fun()</c>) and is often quite fast.</p>
+
+ <p><c>ei</c> also handles C-nodes, C-programs that talks Erlang
+ distribution with Erlang nodes (or other C-nodes) using the
+ Erlang distribution format. The difference between <c>ei</c>
+ and <c>erl_interface</c> is that <c>ei</c> uses
+ the binary format directly when sending and receiving terms. It is also
+ thread safe, and using threads, one process can handle multiple
+ C-nodes. The <c>erl_interface</c> library is built on top of
+ <c>ei</c>, but of legacy reasons, it does not allow for
+ multiple C-nodes. In general, <c>ei</c> is the preferred way
+ of doing C-nodes.</p>
+
+ <p>The decode and encode functions use a buffer and an index into the
buffer, which points at the point where to encode and
decode. The index is updated to point right after the term
encoded/decoded. No checking is done whether the term fits in
the buffer or not. If encoding goes outside the buffer, the
- program may crash.</p>
- <p>All functions takes two parameter, <c><![CDATA[buf]]></c> is a pointer to
- the buffer where the binary data is / will be, <c><![CDATA[index]]></c> is a
- pointer to an index into the buffer. This parameter will be
- incremented with the size of the term decoded / encoded. The
- data is thus at <c><![CDATA[buf[*index]]]></c> when an <c><![CDATA[ei]]></c> function is
- called.</p>
- <p>The encode functions all assumes that the <c><![CDATA[buf]]></c> and
- <c><![CDATA[index]]></c> parameters points to a buffer big enough for the
- data. To get the size of an encoded term, without encoding it,
- pass <c><![CDATA[NULL]]></c> instead of a buffer pointer. The <c><![CDATA[index]]></c>
- parameter will be incremented, but nothing will be encoded. This
- is the way in <c><![CDATA[ei]]></c> to "preflight" term encoding.</p>
- <p>There are also encode-functions that uses a dynamic buffer. It
+ program can crash.</p>
+
+ <p>All functions take two parameters:</p>
+
+ <list type="bulleted">
+ <item><p><c>buf</c> is a pointer to
+ the buffer where the binary data is or will be.</p>
+ </item>
+ <item><p><c>index</c> is a pointer to an index into the
+ buffer. This parameter is incremented with the size of the term
+ decoded/encoded.</p>
+ </item>
+ </list>
+
+ <p>The data is thus at <c>buf[*index]</c> when an
+ <c>ei</c> function is called.</p>
+
+ <p>All encode functions assume that the <c>buf</c> and
+ <c>index</c> parameters point to a buffer large enough for
+ the data. To get the size of an encoded term, without encoding it,
+ pass <c>NULL</c> instead of a buffer pointer. Parameter
+ <c>index</c> is incremented, but nothing will be encoded. This
+ is the way in <c>ei</c> to "preflight" term encoding.</p>
+
+ <p>There are also encode functions that use a dynamic buffer. It
is often more convenient to use these to encode data. All encode
- functions comes in two versions: those starting with <c><![CDATA[ei_x]]></c>,
- uses a dynamic buffer.</p>
- <p>All functions return <c><![CDATA[0]]></c> if successful, and <c><![CDATA[-1]]></c> if
- not. (For instance, if a term is not of the expected type, or
- the data to decode is not a valid erlang term.)</p>
- <p>Some of the decode-functions needs a preallocated buffer. This
- buffer must be allocated big enough, and for non compound types
- the <c><![CDATA[ei_get_type()]]></c>
- function returns the size required (note that for strings an
- extra byte is needed for the 0 string terminator).</p>
+ functions comes in two versions; those starting with
+ <c>ei_x</c> use a dynamic buffer.</p>
+
+ <p>All functions return <c>0</c> if successful, otherwise
+ <c>-1</c> (for example, if a term is not of the expected
+ type, or the data to decode is an invalid Erlang term).</p>
+
+ <p>Some of the decode functions need a pre-allocated buffer. This
+ buffer must be allocated large enough, and for non-compound types
+ the <c>ei_get_type()</c>
+ function returns the size required (notice that for strings an
+ extra byte is needed for the <c>NULL</c>-terminator).</p>
</description>
- <section>
- <title>DATA TYPES</title>
+ <section>
+ <title>Data Types</title>
<taglist>
<tag><marker id="erlang_char_encoding"/>erlang_char_encoding</tag>
<item>
- <p/>
<code type="none">
typedef enum {
ERLANG_ASCII = 1,
ERLANG_LATIN1 = 2,
ERLANG_UTF8 = 4
-}erlang_char_encoding;
-</code>
- <p>The character encodings used for atoms. <c>ERLANG_ASCII</c> represents 7-bit ASCII.
- Latin1 and UTF8 are different extensions of 7-bit ASCII. All 7-bit ASCII characters
- are valid Latin1 and UTF8 characters. ASCII and Latin1 both represent each character
- by one byte. A UTF8 character can consist of one to four bytes. Note that these
- constants are bit-flags and can be combined with bitwise-or.</p>
+} erlang_char_encoding;</code>
+ <p>The character encodings used for atoms. <c>ERLANG_ASCII</c>
+ represents 7-bit ASCII. Latin-1 and UTF-8 are different extensions
+ of 7-bit ASCII. All 7-bit ASCII characters are valid Latin-1 and
+ UTF-8 characters. ASCII and Latin-1 both represent each character
+ by one byte. An UTF-8 character can consist of 1-4 bytes.
+ Notice that these constants are bit-flags and can be combined with
+ bitwise OR.</p>
</item>
</taglist>
</section>
+
<funcs>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name>
+ <fsummary>Decode an atom.</fsummary>
+ <desc>
+ <p>Decodes an atom from the binary format. The <c>NULL</c>-terminated
+ name of the atom is placed at <c>p</c>. At most
+ <c>MAXATOMLEN</c> bytes can be placed in the buffer.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)</nametext></name>
+ <fsummary>Decode an atom.</fsummary>
+ <desc>
+ <p>Decodes an atom from the binary format. The <c>NULL</c>-terminated
+ name of the atom is placed in buffer at <c>p</c> of length <c>plen</c>
+ bytes.</p>
+ <p>The wanted string encoding is specified by
+ <seealso marker="#erlang_char_encoding"><c>want</c></seealso>.
+ The original encoding used in the binary format (Latin-1 or UTF-8) can
+ be obtained from <c>*was</c>. The encoding of the resulting string
+ (7-bit ASCII, Latin-1, or UTF-8) can be obtained from <c>*result</c>.
+ Both <c>was</c> and <c>result</c> can be <c>NULL</c>. <c>*result</c>
+ can differ from <c>want</c> if <c>want</c> is a bitwise OR'd
+ combination like <c>ERLANG_LATIN1|ERLANG_UTF8</c> or if
+ <c>*result</c> turns out to be pure 7-bit ASCII
+ (compatible with both Latin-1 and UTF-8).</p>
+ <p>This function fails if the atom is too long for the buffer
+ or if it cannot be represented with encoding <c>want</c>.</p>
+ <p>This function was introduced in Erlang/OTP R16 as part of a first
+ step to support UTF-8 atoms.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name>
+ <fsummary>Decode a GMP arbitrary precision integer.</fsummary>
+ <desc>
+ <p>Decodes an integer in the binary format to a GMP
+ <c>mpz_t</c> integer. To use this function, the <c>ei</c>
+ library must be configured and compiled to use the GMP library.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name>
+ <fsummary>Decode a binary.</fsummary>
+ <desc>
+ <p>Decodes a binary from the binary format. Parameter
+ <c>len</c> is set to the actual size of the
+ binary. Notice that <c>ei_decode_binary()</c> assumes that
+ there is enough room for the binary. The size required can be
+ fetched by <c>ei_get_type()</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name>
+ <fsummary>Decode a boolean.</fsummary>
+ <desc>
+ <p>Decodes a boolean value from the binary format.
+ A boolean is actually an atom, <c>true</c> decodes 1
+ and <c>false</c> decodes 0.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name>
+ <fsummary>Decode an 8-bit integer between 0-255.</fsummary>
+ <desc>
+ <p>Decodes a char (8-bit) integer between 0-255 from the binary format.
+ For historical reasons the returned integer is of
+ type <c>char</c>. Your C code is to consider the
+ returned value to be of type <c>unsigned char</c> even if
+ the C compilers and system can define <c>char</c> to be
+ signed.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name>
+ <fsummary>Decode a double.</fsummary>
+ <desc>
+ <p>Decodes a double-precision (64-bit) floating
+ point number from the binary format.</p>
+ </desc>
+ </func>
+
<func>
- <name><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name>
- <fsummary>Set the ei library in compatibility mode</fsummary>
- <type>
- <v>unsigned release_number;</v>
- </type>
+ <name><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name>
+ <fsummary>Decode a term, without previous knowledge of type.</fsummary>
+ <desc>
+ <p>Decodes any term, or at least tries to. If the term
+ pointed at by <c>*index</c> in <c>buf</c> fits
+ in the <c>term</c> union, it is decoded, and the
+ appropriate field in <c>term->value</c> is set, and
+ <c>*index</c> is incremented by the term size.</p>
+ <p>The function returns <c>1</c> on successful decoding, <c>-1</c> on
+ error, and <c>0</c> if the term seems alright, but does not fit in the
+ <c>term</c> structure. If <c>1</c> is returned, the
+ <c>index</c> is incremented, and <c>term</c>
+ contains the decoded term.</p>
+ <p>The <c>term</c> structure contains the arity for a tuple
+ or list, size for a binary, string, or atom. It contains
+ a term if it is any of the following: integer, float, atom,
+ pid, port, or ref.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name>
+ <name><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name>
+ <fsummary>Decode a fun.</fsummary>
<desc>
- <marker id="ei_set_compat_rel"></marker>
- <p>By default, the <c><![CDATA[ei]]></c> library is only guaranteed
- to be compatible with other Erlang/OTP components from the same
- release as the <c><![CDATA[ei]]></c> library itself. For example, <c><![CDATA[ei]]></c> from
- the OTP R10 release is not compatible with an Erlang emulator
- from the OTP R9 release by default.</p>
- <p>A call to <c><![CDATA[ei_set_compat_rel(release_number)]]></c> sets the
- <c><![CDATA[ei]]></c> library in compatibility mode of release
- <c><![CDATA[release_number]]></c>. Valid range of <c><![CDATA[release_number]]></c>
- is [7, current release]. This makes it possible to
- communicate with Erlang/OTP components from earlier releases.</p>
- <note>
- <p>If this function is called, it may only be called once
- and must be called before any other functions in the <c><![CDATA[ei]]></c>
- library is called.</p>
- </note>
- <warning>
- <p>You may run into trouble if this feature is used
- carelessly. Always make sure that all communicating
- components are either from the same Erlang/OTP release, or
- from release X and release Y where all components
- from release Y are in compatibility mode of release X.</p>
- </warning>
+ <p>Decodes a fun from the binary format. Parameter
+ <c>p</c> is to be <c>NULL</c> or point to an
+ <c>erlang_fun</c> structure. This is the only decode
+ function that allocates memory. When the <c>erlang_fun</c>
+ is no longer needed, it is to be freed with
+ <c>free_fun</c>. (This has to do with the arbitrary size
+ of the environment for a fun.)</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name>
- <fsummary>Encode version</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name>
+ <fsummary>Decode a list.</fsummary>
<desc>
- <p>Encodes a version magic number for the binary format. Must
- be the first token in a binary term.</p>
+ <p>Decodes a list header from the binary
+ format. The number of elements is returned in
+ <c>arity</c>. The <c>arity+1</c> elements
+ follow (the last one is the tail of the list, normally an empty list).
+ If <c>arity</c> is <c>0</c>, it is an empty
+ list.</p>
+ <p>Notice that lists are encoded as strings if they consist
+ entirely of integers in the range 0..255. This function do
+ not decode such strings, use <c>ei_decode_string()</c>
+ instead.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name>
- <fsummary>Encode integer</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name>
+ <fsummary>Decode integer.</fsummary>
<desc>
- <p>Encodes a long integer in the binary format.
- Note that if the code is 64 bits the function ei_encode_long() is
- exactly the same as ei_encode_longlong().</p>
+ <p>Decodes a long integer from the binary format.
+ If the code is 64 bits, the function <c>ei_decode_long()</c> is
+ the same as <c>ei_decode_longlong()</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name>
- <fsummary>Encode unsigned integer</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name>
+ <fsummary>Decode integer.</fsummary>
<desc>
- <p>Encodes an unsigned long integer in the binary format.
- Note that if the code is 64 bits the function ei_encode_ulong() is
- exactly the same as ei_encode_ulonglong().</p>
+ <p>Decodes a GCC <c>long long</c> or Visual C++
+ <c>__int64</c>
+ (64-bit) integer from the binary format. This
+ function is missing in the VxWorks port.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name>
- <fsummary>Encode integer</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_map_header(const char *buf, int *index, int *arity)</nametext></name>
+ <fsummary>Decode a map.</fsummary>
<desc>
- <p>Encodes a GCC <c><![CDATA[long long]]></c> or Visual C++ <c><![CDATA[__int64]]></c> (64 bit)
- integer in the binary format. Note that this function is missing
- in the VxWorks port.</p>
+ <p>Decodes a map header from the binary
+ format. The number of key-value pairs is returned in
+ <c>*arity</c>. Keys and values follow in this order:
+ <c>K1, V1, K2, V2, ..., Kn, Vn</c>. This makes a total of
+ <c>arity*2</c> terms. If <c>arity</c> is zero, it is an empty map.
+ A correctly encoded map does not have duplicate keys.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name>
- <fsummary>Encode unsigned integer</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name>
+ <fsummary>Decode a <c>pid</c>.</fsummary>
<desc>
- <p>Encodes a GCC <c><![CDATA[unsigned long long]]></c> or Visual C++ <c><![CDATA[unsigned __int64]]></c> (64 bit) integer in the binary format. Note that
- this function is missing in the VxWorks port.</p>
+ <p>Decodes a process identifier (pid) from the binary format.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name>
- <fsummary>Encode an arbitrary precision integer</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name>
+ <fsummary>Decode a port.</fsummary>
<desc>
- <p>Encodes a GMP <c><![CDATA[mpz_t]]></c> integer to binary format.
- To use this function the ei library needs to be configured and compiled
- to use the GMP library. </p>
+ <p>Decodes a port identifier from the binary format.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name>
- <fsummary>Encode a double float</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name>
+ <fsummary>Decode a reference.</fsummary>
<desc>
- <p>Encodes a double-precision (64 bit) floating point number in
- the binary format.</p>
- <p>
- The function returns <c><![CDATA[-1]]></c> if the floating point number is not finite.
- </p>
+ <p>Decodes a reference from the binary format.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name>
- <fsummary>Encode a boolean</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name>
+ <fsummary>Decode a string.</fsummary>
<desc>
- <p>Encodes a boolean value, as the atom <c><![CDATA[true]]></c> if p is not
- zero or <c><![CDATA[false]]></c> if p is zero.</p>
+ <p>Decodes a string from the binary format. A
+ string in Erlang is a list of integers between 0 and
+ 255. Notice that as the string is just a list, sometimes
+ lists are encoded as strings by <c>term_to_binary/1</c>,
+ even if it was not intended.</p>
+ <p>The string is copied to <c>p</c>, and enough space must
+ be allocated. The returned string is <c>NULL</c>-terminated, so you
+ must add an extra byte to the memory requirement.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name>
- <fsummary>Encode an 8-bit integer between 0-255</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name>
+ <fsummary>Decode a <c>ETERM</c>.</fsummary>
+ <desc>
+ <p>Decodes a term from the binary format. The term
+ is return in <c>t</c> as a <c>ETERM*</c>, so
+ <c>t</c> is actually an <c>ETERM**</c> (see
+ <seealso marker="erl_eterm"><c>erl_eterm</c></seealso>).
+ The term is later to be deallocated.</p>
+ <p>Notice that this function is located in the <c>Erl_Interface</c>
+ library.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name>
+ <fsummary>Decode a trace token.</fsummary>
<desc>
- <p>Encodes a char (8-bit) as an integer between 0-255 in the binary format.
- Note that for historical reasons the integer argument is of
- type <c><![CDATA[char]]></c>. Your C code should consider the
- given argument to be of type <c><![CDATA[unsigned char]]></c> even if
- the C compilers and system may define <c><![CDATA[char]]></c> to be
- signed.</p>
+ <p>Decodes an Erlang trace token from the binary format.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name>
- <fsummary>Encode a string</fsummary>
+ <name><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name>
+ <fsummary>Decode a tuple.</fsummary>
<desc>
- <p>Encodes a string in the binary format. (A string in erlang
- is a list, but is encoded as a character array in the binary
- format.) The string should be zero-terminated, except for
- the <c><![CDATA[ei_x_encode_string_len()]]></c> function.</p>
+ <p>Decodes a tuple header, the number of elements
+ is returned in <c>arity</c>. The tuple elements follow
+ in order in the buffer.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name>
+ <fsummary>Decode unsigned integer.</fsummary>
+ <desc>
+ <p>Decodes an unsigned long integer from the binary format.
+ If the code is 64 bits, the function <c>ei_decode_ulong()</c> is
+ the same as <c>ei_decode_ulonglong()</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name>
+ <fsummary>Decode unsigned integer.</fsummary>
+ <desc>
+ <p>Decodes a GCC <c>unsigned long long</c> or Visual C++
+ <c>unsigned __int64</c> (64-bit) integer from the binary
+ format. This function is missing in the VxWorks port.</p>
</desc>
</func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name>
+ <fsummary>Decode an empty list (<c>nil</c>).</fsummary>
+ <desc>
+ <p>Decodes the version magic number for the
+ Erlang binary term format. It must be the first token in a
+ binary term.</p>
+ </desc>
+ </func>
+
<func>
<name><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name>
<name><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name>
<name><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name>
<name><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name>
- <fsummary>Encode an atom</fsummary>
+ <fsummary>Encode an atom.</fsummary>
<desc>
- <p>Encodes an atom in the binary format. The <c><![CDATA[p]]></c> parameter
- is the name of the atom in latin1 encoding. Only upto <c>MAXATOMLEN-1</c> bytes
- are encoded. The name should be zero-terminated, except for
- the <c><![CDATA[ei_x_encode_atom_len()]]></c> function.</p>
+ <p>Encodes an atom in the binary format. Parameter <c>p</c>
+ is the name of the atom in Latin-1 encoding. Only up to
+ <c>MAXATOMLEN-1</c> bytes
+ are encoded. The name is to be <c>NULL</c>-terminated, except for
+ the <c>ei_x_encode_atom_len()</c> function.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_encode_atom_as(char *buf, int *index, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
<name><ret>int</ret><nametext>ei_encode_atom_len_as(char *buf, int *index, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
<name><ret>int</ret><nametext>ei_x_encode_atom_as(ei_x_buff* x, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
<name><ret>int</ret><nametext>ei_x_encode_atom_len_as(ei_x_buff* x, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
- <fsummary>Encode an atom</fsummary>
+ <fsummary>Encode an atom.</fsummary>
<desc>
<p>Encodes an atom in the binary format with character encoding
- <seealso marker="#erlang_char_encoding"><c>to_enc</c></seealso> (latin1 or utf8).
- The <c>p</c> parameter is the name of the atom with character encoding
- <seealso marker="#erlang_char_encoding"><c>from_enc</c></seealso> (ascii, latin1 or utf8).
- The name must either be zero-terminated or a function variant with a <c>len</c>
- parameter must be used. If <c>to_enc</c> is set to the bitwise-or'd combination
- <c>(ERLANG_LATIN1|ERLANG_UTF8)</c>, utf8 encoding is only used if the atom string
- can not be represented in latin1 encoding.</p>
- <p>The encoding will fail if <c>p</c> is not a valid string in encoding <c>from_enc</c>,
- if the string is too long or if it can not be represented with character encoding <c>to_enc</c>.</p>
- <p>These functions were introduced in R16 release of Erlang/OTP as part of a first step
- to support UTF8 atoms. Atoms encoded with <c>ERLANG_UTF8</c>
- can not be decoded by earlier releases than R16.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name>
- <fsummary>Encode a binary</fsummary>
- <desc>
- <p>Encodes a binary in the binary format. The data is at
- <c><![CDATA[p]]></c>, of <c><![CDATA[len]]></c> bytes length.</p>
+ <seealso marker="#erlang_char_encoding"><c>to_enc</c></seealso>
+ (Latin-1 or UTF-8). Parameter <c>p</c> is the name of the atom with
+ character encoding
+ <seealso marker="#erlang_char_encoding"><c>from_enc</c></seealso>
+ (ASCII, Latin-1, or UTF-8). The name must either be <c>NULL</c>-terminated or
+ a function variant with a <c>len</c> parameter must be used.
+ If <c>to_enc</c> is set to the bitwise OR'd combination
+ <c>(ERLANG_LATIN1|ERLANG_UTF8)</c>, UTF-8 encoding is only used if the
+ atom string cannot be represented in Latin-1 encoding.</p>
+ <p>The encoding fails if <c>p</c> is an invalid string in encoding
+ <c>from_enc</c>, if the string is too long, or if it cannot be
+ represented with character encoding <c>to_enc</c>.</p>
+ <p>These functions were introduced in Erlang/OTP R16 as part of a first
+ step to support UTF-8 atoms. Atoms encoded with <c>ERLANG_UTF8</c>
+ cannot be decoded by earlier releases than R16.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name>
- <fsummary>Encode a pid</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name>
+ <fsummary>Encode an arbitrary precision integer.</fsummary>
<desc>
- <p>Encodes an erlang process identifier, pid, in the binary
- format. The <c><![CDATA[p]]></c> parameter points to an
- <c><![CDATA[erlang_pid]]></c> structure (which should have been obtained
- earlier with <c><![CDATA[ei_decode_pid()]]></c>).</p>
+ <p>Encodes a GMP <c>mpz_t</c> integer to binary format.
+ To use this function, the <c>ei</c> library must be configured and
+ compiled to use the GMP library.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name>
- <fsummary>Encode a fun</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name>
+ <fsummary>Encode a binary.</fsummary>
<desc>
- <p>Encodes a fun in the binary format. The <c><![CDATA[p]]></c> parameter
- points to an <c><![CDATA[erlang_fun]]></c> structure. The
- <c><![CDATA[erlang_fun]]></c> is not freed automatically, the
- <c><![CDATA[free_fun]]></c> should be called if the fun is not needed
- after encoding.</p>
+ <p>Encodes a binary in the binary format. The data is at
+ <c>p</c>, of <c>len</c> bytes length.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name>
- <fsummary>Encodes a port</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name>
+ <fsummary>Encode a boolean.</fsummary>
<desc>
- <p>Encodes an erlang port in the binary format. The <c><![CDATA[p]]></c>
- parameter points to a <c><![CDATA[erlang_port]]></c> structure (which
- should have been obtained earlier with
- <c><![CDATA[ei_decode_port()]]></c>.</p>
+ <p>Encodes a boolean value as the atom <c>true</c> if
+ <c>p</c> is not zero, or <c>false</c> if <c>p</c> is
+ zero.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name>
- <fsummary>Encodes a ref</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name>
+ <fsummary>Encode an 8-bit integer between 0-255.</fsummary>
<desc>
- <p>Encodes an erlang reference in the binary format. The
- <c><![CDATA[p]]></c> parameter points to a <c><![CDATA[erlang_ref]]></c> structure
- (which should have been obtained earlier with
- <c><![CDATA[ei_decode_ref()]]></c>.</p>
+ <p>Encodes a char (8-bit) as an integer between 0-255 in the binary
+ format. For historical reasons the integer argument is of
+ type <c>char</c>. Your C code is to consider the specified
+ argument to be of type <c>unsigned char</c> even if
+ the C compilers and system may define <c>char</c> to be
+ signed.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name>
- <fsummary>Encode an <c><![CDATA[erl_interface]]></c>term</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name>
+ <fsummary>Encode a double float.</fsummary>
<desc>
- <p>This function encodes an <c><![CDATA[ETERM]]></c>, as obtained from
- <c><![CDATA[erl_interface]]></c>. The <c><![CDATA[t]]></c> parameter is actually an
- <c><![CDATA[ETERM]]></c> pointer. This function doesn't free the
- <c><![CDATA[ETERM]]></c>.</p>
+ <p>Encodes a double-precision (64-bit) floating point number in
+ the binary format.</p>
+ <p>Returns <c>-1</c> if the floating point
+ number is not finite.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name>
- <fsummary>Encode a trace token</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name>
+ <fsummary>Encode an empty list (<c>nil</c>).</fsummary>
<desc>
- <p>This function encodes an erlang trace token in the binary
- format. The <c><![CDATA[p]]></c> parameter points to a
- <c><![CDATA[erlang_trace]]></c> structure (which should have been
- obtained earlier with <c><![CDATA[ei_decode_trace()]]></c>.</p>
+ <p>Encodes an empty list. It is often used at the tail of a list.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name>
- <fsummary>Encode a tuple</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name>
+ <fsummary>Encode a fun.</fsummary>
<desc>
- <p>This function encodes a tuple header, with a specified
- arity. The next <c><![CDATA[arity]]></c> terms encoded will be the
- elements of the tuple. Tuples and lists are encoded
- recursively, so that a tuple may contain another tuple or
- list.</p>
- <p>E.g. to encode the tuple <c><![CDATA[{a, {b, {}}}]]></c>:</p>
- <pre>
-ei_encode_tuple_header(buf, &amp;i, 2);
-ei_encode_atom(buf, &amp;i, "a");
-ei_encode_tuple_header(buf, &amp;i, 2);
-ei_encode_atom(buf, &amp;i, "b");
-ei_encode_tuple_header(buf, &amp;i, 0);
- </pre>
+ <p>Encodes a fun in the binary format. Parameter <c>p</c>
+ points to an <c>erlang_fun</c> structure. The
+ <c>erlang_fun</c> is not freed automatically, the
+ <c>free_fun</c> is to be called if the fun is not needed
+ after encoding.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name>
<name><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name>
- <fsummary>Encode a list</fsummary>
+ <fsummary>Encode a list.</fsummary>
<desc>
- <p>This function encodes a list header, with a specified
- arity. The next <c><![CDATA[arity+1]]></c> terms are the elements
- (actually its <c><![CDATA[arity]]></c> cons cells) and the tail of the
+ <p>Encodes a list header, with a specified
+ arity. The next <c>arity+1</c> terms are the elements
+ (actually its <c>arity</c> cons cells) and the tail of the
list. Lists and tuples are encoded recursively, so that a
- list may contain another list or tuple.</p>
- <p>E.g. to encode the list <c><![CDATA[[c, d, [e | f]]]]></c>:</p>
+ list can contain another list or tuple.</p>
+ <p>For example, to encode the list
+ <c>[c, d, [e | f]]</c>:</p>
<pre>
ei_encode_list_header(buf, &amp;i, 3);
ei_encode_atom(buf, &amp;i, "c");
@@ -392,14 +539,13 @@ ei_encode_atom(buf, &amp;i, "d");
ei_encode_list_header(buf, &amp;i, 1);
ei_encode_atom(buf, &amp;i, "e");
ei_encode_atom(buf, &amp;i, "f");
-ei_encode_empty_list(buf, &amp;i);
- </pre>
+ei_encode_empty_list(buf, &amp;i);</pre>
<note>
<p>It may seem that there is no way to create a list without
knowing the number of elements in advance. But indeed
- there is a way. Note that the list <c><![CDATA[[a, b, c]]]></c> can be
- written as <c><![CDATA[[a | [b | [c]]]]]></c>. Using this, a list can
- be written as conses.</p>
+ there is a way. Notice that the list <c>[a, b, c]</c>
+ can be written as <c>[a | [b | [c]]]</c>.
+ Using this, a list can be written as conses.</p>
</note>
<p>To encode a list, without knowing the arity in advance:</p>
<pre>
@@ -407,425 +553,350 @@ while (something()) {
ei_x_encode_list_header(&amp;x, 1);
ei_x_encode_ulong(&amp;x, i); /* just an example */
}
-ei_x_encode_empty_list(&amp;x);
- </pre>
+ei_x_encode_empty_list(&amp;x);</pre>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name>
- <fsummary>Encode an empty list (<c><![CDATA[nil]]></c>)</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name>
+ <fsummary>Encode integer.</fsummary>
<desc>
- <p>This function encodes an empty list. It's often used at the
- tail of a list.</p>
+ <p>Encodes a long integer in the binary format.
+ If the code is 64 bits, the function <c>ei_encode_long()</c> is
+ the same as <c>ei_encode_longlong()</c>.</p>
</desc>
</func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name>
+ <fsummary>Encode integer.</fsummary>
+ <desc>
+ <p>Encodes a GCC <c>long long</c> or Visual C++
+ <c>__int64</c> (64-bit) integer in the binary format.
+ This function is missing in the VxWorks port.</p>
+ </desc>
+ </func>
+
<func>
<name><ret>int</ret><nametext>ei_encode_map_header(char *buf, int *index, int arity)</nametext></name>
<name><ret>int</ret><nametext>ei_x_encode_map_header(ei_x_buff* x, int arity)</nametext></name>
- <fsummary>Encode a map</fsummary>
+ <fsummary>Encode a map.</fsummary>
<desc>
- <p>This function encodes a map header, with a specified arity. The next
+ <p>Encodes a map header, with a specified arity. The next
<c>arity*2</c> terms encoded will be the keys and values of the map
encoded in the following order: <c>K1, V1, K2, V2, ..., Kn, Vn</c>.
</p>
- <p>E.g. to encode the map <c>#{a => "Apple", b => "Banana"}</c>:</p>
+ <p>For example, to encode the map <c>#{a => "Apple", b =>
+ "Banana"}</c>:</p>
<pre>
ei_x_encode_map_header(&amp;x, 2);
ei_x_encode_atom(&amp;x, "a");
ei_x_encode_string(&amp;x, "Apple");
ei_x_encode_atom(&amp;x, "b");
-ei_x_encode_string(&amp;x, "Banana");
- </pre>
- <p>A correctly encoded map can not have duplicate keys.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name>
- <fsummary>Fetch the type and size of an encoded term</fsummary>
- <desc>
- <p>This function returns the type in <c><![CDATA[type]]></c> and size in
- <c><![CDATA[size]]></c> of the encoded term.
- For strings and atoms, size
- is the number of characters <em>not</em> including the
- terminating 0. For binaries, <c><![CDATA[size]]></c> is the number of
- bytes. For lists and tuples, <c><![CDATA[size]]></c> is the arity of the
- object. For other types, <c><![CDATA[size]]></c> is 0. In all cases,
- <c><![CDATA[index]]></c> is left unchanged.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name>
- <fsummary>Encode an empty list (<c><![CDATA[nil]]></c>)</fsummary>
- <desc>
- <p>This function decodes the version magic number for the
- erlang binary term format. It must be the first token in a
- binary term.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name>
- <fsummary>Decode integer</fsummary>
- <desc>
- <p>This function decodes a long integer from the binary format.
- Note that if the code is 64 bits the function ei_decode_long() is
- exactly the same as ei_decode_longlong().</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name>
- <fsummary>Decode unsigned integer</fsummary>
- <desc>
- <p>This function decodes an unsigned long integer from
- the binary format.
- Note that if the code is 64 bits the function ei_decode_ulong() is
- exactly the same as ei_decode_ulonglong().</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name>
- <fsummary>Decode integer</fsummary>
- <desc>
- <p>This function decodes a GCC <c><![CDATA[long long]]></c> or Visual C++ <c><![CDATA[__int64]]></c>
- (64 bit) integer from the binary format. Note that this
- function is missing in the VxWorks port.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name>
- <fsummary>Decode unsigned integer</fsummary>
- <desc>
- <p>This function decodes a GCC <c><![CDATA[unsigned long long]]></c> or Visual C++
- <c><![CDATA[unsigned __int64]]></c> (64 bit) integer from the binary format.
- Note that this function is missing in the VxWorks port.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name>
- <fsummary>Decode a GMP arbitrary precision integer</fsummary>
- <desc>
- <p>This function decodes an integer in the binary format to a GMP <c><![CDATA[mpz_t]]></c> integer.
- To use this function the ei library needs to be configured and compiled
- to use the GMP library. </p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name>
- <fsummary>Decode a double</fsummary>
- <desc>
- <p>This function decodes an double-precision (64 bit) floating
- point number from the binary format.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name>
- <fsummary>Decode a boolean</fsummary>
- <desc>
- <p>This function decodes a boolean value from the binary
- format. A boolean is actually an atom, <c><![CDATA[true]]></c> decodes 1
- and <c><![CDATA[false]]></c> decodes 0.</p>
+ei_x_encode_string(&amp;x, "Banana");</pre>
+ <p>A correctly encoded map cannot have duplicate keys.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name>
- <fsummary>Decode an 8-bit integer between 0-255</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name>
+ <fsummary>Encode a pid.</fsummary>
<desc>
- <p>This function decodes a char (8-bit) integer between 0-255
- from the binary format.
- Note that for historical reasons the returned integer is of
- type <c><![CDATA[char]]></c>. Your C code should consider the
- returned value to be of type <c><![CDATA[unsigned char]]></c> even if
- the C compilers and system may define <c><![CDATA[char]]></c> to be
- signed.</p>
+ <p>Encodes an Erlang process identifier (pid) in the binary
+ format. Parameter <c>p</c> points to an
+ <c>erlang_pid</c> structure (which should have been
+ obtained earlier with <c>ei_decode_pid()</c>).</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name>
- <fsummary>Decode a string</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name>
+ <fsummary>Encode a port.</fsummary>
<desc>
- <p>This function decodes a string from the binary format. A
- string in erlang is a list of integers between 0 and
- 255. Note that since the string is just a list, sometimes
- lists are encoded as strings by <c><![CDATA[term_to_binary/1]]></c>,
- even if it was not intended.</p>
- <p>The string is copied to <c><![CDATA[p]]></c>, and enough space must be
- allocated. The returned string is null terminated so you
- need to add an extra byte to the memory requirement.</p>
+ <p>Encodes an Erlang port in the binary format. Parameter
+ <c>p</c> points to a <c>erlang_port</c>
+ structure (which should have been obtained earlier with
+ <c>ei_decode_port()</c>).</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name>
- <fsummary>Decode an atom</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name>
+ <fsummary>Encode a ref.</fsummary>
<desc>
- <p>This function decodes an atom from the binary format. The
- null terminated name of the atom is placed at <c><![CDATA[p]]></c>. There can be at most
- <c><![CDATA[MAXATOMLEN]]></c> bytes placed in the buffer.</p>
+ <p>Encodes an Erlang reference in the binary format. Parameter
+ <c>p</c> points to a <c>erlang_ref</c>
+ structure (which should have been obtained earlier with
+ <c>ei_decode_ref()</c>).</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)</nametext></name>
- <fsummary>Decode an atom</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name>
+ <fsummary>Encode a string.</fsummary>
<desc>
- <p>This function decodes an atom from the binary format. The
- null terminated name of the atom is placed in buffer at <c>p</c> of length
- <c>plen</c> bytes.</p>
- <p>The wanted string encoding is specified by <seealso marker="#erlang_char_encoding">
- <c>want</c></seealso>. The original encoding used in the
- binary format (latin1 or utf8) can be obtained from <c>*was</c>. The actual encoding of the resulting string
- (7-bit ascii, latin1 or utf8) can be obtained from <c>*result</c>. Both <c>was</c> and <c>result</c> can be <c>NULL</c>.
-
- <c>*result</c> may differ from <c>want</c> if <c>want</c> is a bitwise-or'd combination like
- <c>ERLANG_LATIN1|ERLANG_UTF8</c> or if <c>*result</c> turn out to be pure 7-bit ascii
- (compatible with both latin1 and utf8).</p>
- <p>This function fails if the atom is too long for the buffer
- or if it can not be represented with encoding <c>want</c>.</p>
- <p>This function was introduced in R16 release of Erlang/OTP as part of a first step
- to support UTF8 atoms.</p>
+ <p>Encodes a string in the binary format. (A string in Erlang
+ is a list, but is encoded as a character array in the binary
+ format.) The string is to be <c>NULL</c>-terminated, except for
+ the <c>ei_x_encode_string_len()</c> function.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name>
- <fsummary>Decode a binary</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name>
+ <fsummary>Encode an <c>erl_interface</c> term.</fsummary>
<desc>
- <p>This function decodes a binary from the binary format. The
- <c><![CDATA[len]]></c> parameter is set to the actual size of the
- binary. Note that <c><![CDATA[ei_decode_binary()]]></c> assumes that there
- are enough room for the binary. The size required can be
- fetched by <c><![CDATA[ei_get_type()]]></c>.</p>
+ <p>Encodes an <c>ETERM</c>, as obtained from
+ <c>erl_interface</c>. Parameter <c>t</c> is
+ actually an <c>ETERM</c> pointer. This function
+ does not free the <c>ETERM</c>.</p>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name>
- <name><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name>
- <fsummary>Decode a fun</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name>
+ <fsummary>Encode a trace token.</fsummary>
<desc>
- <p>This function decodes a fun from the binary format. The
- <c><![CDATA[p]]></c> parameter should be NULL or point to an
- <c><![CDATA[erlang_fun]]></c> structure. This is the only decode
- function that allocates memory; when the <c><![CDATA[erlang_fun]]></c>
- is no longer needed, it should be freed with
- <c><![CDATA[free_fun]]></c>. (This has to do with the arbitrary size of
- the environment for a fun.)</p>
+ <p>Encodes an Erlang trace token in the binary format.
+ Parameter <c>p</c> points to a
+ <c>erlang_trace</c> structure (which should have been
+ obtained earlier with <c>ei_decode_trace()</c>).</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name>
- <fsummary>Decode a <c><![CDATA[pid]]></c></fsummary>
+ <name><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name>
+ <fsummary>Encode a tuple.</fsummary>
<desc>
- <p>Decodes a pid, process identifier, from the binary format.</p>
+ <p>Encodes a tuple header, with a specified
+ arity. The next <c>arity</c> terms encoded will be the
+ elements of the tuple. Tuples and lists are encoded
+ recursively, so that a tuple can contain another tuple or list.</p>
+ <p>For example, to encode the tuple <c>{a, {b, {}}}</c>:</p>
+ <pre>
+ei_encode_tuple_header(buf, &amp;i, 2);
+ei_encode_atom(buf, &amp;i, "a");
+ei_encode_tuple_header(buf, &amp;i, 2);
+ei_encode_atom(buf, &amp;i, "b");
+ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name>
- <fsummary>Decode a port</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name>
+ <fsummary>Encode unsigned integer.</fsummary>
<desc>
- <p>This function decodes a port identifier from the binary
- format.</p>
+ <p>Encodes an unsigned long integer in the binary format.
+ If the code is 64 bits, the function <c>ei_encode_ulong()</c> is
+ the same as <c>ei_encode_ulonglong()</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name>
- <fsummary>Decode a reference</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name>
+ <fsummary>Encode unsigned integer.</fsummary>
<desc>
- <p>This function decodes a reference from the binary format.</p>
+ <p>Encodes a GCC <c>unsigned long long</c> or Visual C++
+ <c>unsigned __int64</c> (64-bit) integer in the binary
+ format. This function is missing in the VxWorks port.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name>
- <fsummary>Decode a trace token</fsummary>
+ <name><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name>
+ <fsummary>Encode version.</fsummary>
<desc>
- <p>Decodes an erlang trace token from the binary format.</p>
+ <p>Encodes a version magic number for the binary format. Must
+ be the first token in a binary term.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name>
- <fsummary>Decode a tuple</fsummary>
+ <name><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name>
+ <fsummary>Fetch the type and size of an encoded term.</fsummary>
<desc>
- <p>This function decodes a tuple header, the number of elements
- is returned in <c><![CDATA[arity]]></c>. The tuple elements follows in order in
- the buffer.</p>
+ <p>Returns the type in <c>type</c> and size in
+ <c>size</c> of the encoded term. For strings and atoms,
+ size is the number of characters <em>not</em> including the
+ terminating <c>NULL</c>. For binaries, <c>size</c> is the number of
+ bytes. For lists and tuples, <c>size</c> is the arity of
+ the object. For other types, <c>size</c> is 0. In all
+ cases, <c>index</c> is left unchanged.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name>
- <fsummary>Decode a list</fsummary>
- <desc>
- <p>This function decodes a list header from the binary
- format. The number of elements is returned in
- <c><![CDATA[arity]]></c>. The <c><![CDATA[arity+1]]></c> elements follows (the last
- one is the tail of the list, normally an empty list.) If
- <c><![CDATA[arity]]></c> is <c><![CDATA[0]]></c>, it's an empty list.</p>
- <p>Note that lists are encoded as strings, if they consist
- entirely of integers in the range 0..255. This function will
- not decode such strings, use <c><![CDATA[ei_decode_string()]]></c>
- instead.</p>
+ <name><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name>
+ <name><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name>
+ <fsummary>Print a term in clear text.</fsummary>
+ <desc>
+ <p>Prints a term, in clear text, to the file
+ specified by <c>fp</c>, or the buffer pointed to by
+ <c>s</c>. It
+ tries to resemble the term printing in the Erlang shell.</p>
+ <p>In <c>ei_s_print_term()</c>, parameter
+ <c>s</c> is to
+ point to a dynamically (malloc) allocated string of
+ <c>BUFSIZ</c> bytes or a <c>NULL</c> pointer. The string
+ can be reallocated (and <c>*s</c> can be updated) by this
+ function if the result is more than <c>BUFSIZ</c>
+ characters. The string returned is <c>NULL</c>-terminated.</p>
+ <p>The return value is the number of characters written to the file
+ or string, or <c>-1</c> if <c>buf[index]</c> does not
+ contain a valid term.
+ Unfortunately, I/O errors on <c>fp</c> is not checked.</p>
+ <p>Argument <c>index</c> is updated, that is, this function
+ can be viewed as a decode function that decodes a term into a
+ human-readable format.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_map_header(const char *buf, int *index, int *arity)</nametext></name>
- <fsummary>Decode a map</fsummary>
+ <name><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name>
+ <fsummary>Set the ei library in compatibility mode.</fsummary>
+ <type>
+ <v>unsigned release_number;</v>
+ </type>
<desc>
- <p>This function decodes a map header from the binary
- format. The number of key-value pairs is returned in
- <c>*arity</c>. Keys and values follow in the following order:
- <c>K1, V1, K2, V2, ..., Kn, Vn</c>. This makes a total of
- <c>arity*2</c> terms. If <c>arity</c> is zero, it's an empty map.
- A correctly encoded map does not have duplicate keys.</p>
+ <marker id="ei_set_compat_rel"></marker>
+ <p>By default, the <c>ei</c> library is only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the <c>ei</c> library itself. For example,
+ <c>ei</c> from
+ Erlang/OTP R10 is not compatible with an Erlang emulator
+ from Erlang/OTP R9 by default.</p>
+ <p>A call to <c>ei_set_compat_rel(release_number)</c> sets
+ the <c>ei</c> library in compatibility mode of release
+ <c>release_number</c>. Valid range of
+ <c>release_number</c>
+ is <c>[7, current release]</c>. This makes it possible to
+ communicate with Erlang/OTP components from earlier releases.</p>
+ <note>
+ <p>If this function is called, it can only be called once
+ and must be called before any other functions in the
+ <c>ei</c> library are called.</p>
+ </note>
+ <warning>
+ <p>You can run into trouble if this feature is used
+ carelessly. Always ensure that all communicating
+ components are either from the same Erlang/OTP release, or
+ from release X and release Y where all components
+ from release Y are in compatibility mode of release X.</p>
+ </warning>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name>
- <fsummary>Decode a term, without prior knowledge of type</fsummary>
+ <name><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name>
+ <fsummary>Skip a term.</fsummary>
<desc>
- <p>This function decodes any term, or at least tries to. If the
- term pointed at by <c><![CDATA[*index]]></c> in <c><![CDATA[buf]]></c> fits in the
- <c><![CDATA[term]]></c> union, it is decoded, and the appropriate field
- in <c><![CDATA[term->value]]></c> is set, and <c><![CDATA[*index]]></c> is
- incremented by the term size.</p>
- <p>The function returns 1 on successful decoding, -1 on error,
- and 0 if the term seems alright, but does not fit in the
- <c><![CDATA[term]]></c> structure. If it returns 1, the <c><![CDATA[index]]></c>
- will be incremented, and the <c><![CDATA[term]]></c> contains the
- decoded term.</p>
- <p>The <c><![CDATA[term]]></c> structure will contain the arity for a tuple
- or list, size for a binary, string or atom. It will contains
- a term if it's any of the following: integer, float, atom,
- pid, port or ref.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name>
- <fsummary>Decode a <c><![CDATA[ETERM]]></c></fsummary>
- <desc>
- <p>This function decodes a term from the binary format. The
- term is return in <c><![CDATA[t]]></c> as a <c><![CDATA[ETERM*]]></c>, so <c><![CDATA[t]]></c>
- is actually an <c><![CDATA[ETERM**]]></c> (see
- <c><![CDATA[erl_interface(3)]]></c>. The term should later be
- deallocated.</p>
- <p>Note that this function is located in the erl_interface
- library.</p>
+ <p>Skips a term in the specified buffer;
+ recursively skips elements of lists and tuples, so that a
+ full term is skipped. This is a way to get the size of an
+ Erlang term.</p>
+ <p><c>buf</c> is the buffer.</p>
+ <p><c>index</c> is updated to point right after the term
+ in the buffer.</p>
+ <note>
+ <p>This can be useful when you want to hold arbitrary
+ terms: skip them and copy the binary term data to some
+ buffer.</p>
+ </note>
+ <p>Returns <c>0</c> on success, otherwise
+ <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name>
- <name><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name>
- <fsummary>Print a term in clear text</fsummary>
+ <name><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name>
+ <fsummary>Append a buffer at the end.</fsummary>
<desc>
- <p>This function prints a term, in clear text, to the file
- given by <c><![CDATA[fp]]></c>, or the buffer pointed to by <c><![CDATA[s]]></c>. It
- tries to resemble the term printing in the erlang shell.</p>
- <p>In <c><![CDATA[ei_s_print_term()]]></c>, the parameter <c><![CDATA[s]]></c> should
- point to a dynamically (malloc) allocated string of
- <c><![CDATA[BUFSIZ]]></c> bytes or a NULL pointer. The string may be
- reallocated (and <c><![CDATA[*s]]></c> may be updated) by this function
- if the result is more than <c><![CDATA[BUFSIZ]]></c> characters. The
- string returned is zero-terminated.</p>
- <p>The return value is the number of characters written to the
- file or string, or -1 if <c><![CDATA[buf[index]]]></c> doesn't contain a
- valid term. Unfortunately, I/O errors on <c><![CDATA[fp]]></c> is not
- checked.</p>
- <p>The argument <c><![CDATA[index]]></c> is updated, i.e. this function can
- be viewed as en decode function that decodes a term into a
- human readable format.</p>
+ <p>Appends data at the end of buffer <c>x</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name>
<name><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name>
<fsummary>Format a term from a format string and parameters.</fsummary>
<desc>
- <p>Format a term, given as a string, to a buffer. This
- functions works like a sprintf for erlang terms. The
- <c><![CDATA[fmt]]></c> contains a format string, with arguments like
- <c><![CDATA[~d]]></c>, to insert terms from variables. The following
+ <p>Formats a term, given as a string, to a buffer.
+ Works like a sprintf for Erlang terms.
+ <c>fmt</c> contains a format string, with arguments like
+ <c>~d</c>, to insert terms from variables. The following
formats are supported (with the C types given):</p>
- <p></p>
<pre>
-~a - an atom, char*
-~c - a character, char
-~s - a string, char*
-~i - an integer, int
-~l - a long integer, long int
-~u - a unsigned long integer, unsigned long int
-~f - a float, float
-~d - a double float, double float
-~p - an Erlang PID, erlang_pid*
- </pre>
- <p>For instance, to encode a tuple with some stuff:</p>
+~a An atom, char*
+~c A character, char
+~s A string, char*
+~i An integer, int
+~l A long integer, long int
+~u A unsigned long integer, unsigned long int
+~f A float, float
+~d A double float, double float
+~p An Erlang pid, erlang_pid*</pre>
+ <p>For example, to encode a tuple with some stuff:</p>
<pre>
ei_x_format("{~a,~i,~d}", "numbers", 12, 3.14159)
-encodes the tuple {numbers,12,3.14159}
- </pre>
- <p>The <c><![CDATA[ei_x_format_wo_ver()]]></c> formats into a buffer, without
- the initial version byte.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name>
- <fsummary>Allocate a new buffer</fsummary>
- <desc>
- <p>This function allocates a new <c><![CDATA[ei_x_buff]]></c> buffer. The
- fields of the structure pointed to by <c><![CDATA[x]]></c> parameter is
- filled in, and a default buffer is allocated. The
- <c><![CDATA[ei_x_new_with_version()]]></c> also puts an initial version
- byte, that is used in the binary format. (So that
- <c><![CDATA[ei_x_encode_version()]]></c> won't be needed.)</p>
+encodes the tuple {numbers,12,3.14159}</pre>
+ <p><c>ei_x_format_wo_ver()</c> formats into a buffer,
+ without the initial version byte.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name>
- <fsummary>Frees a buffer</fsummary>
- <desc>
- <p>This function frees an <c><![CDATA[ei_x_buff]]></c> buffer. The memory
- used by the buffer is returned to the OS.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name>
- <fsummary>Appends a buffer at the end</fsummary>
+ <fsummary>Free a buffer.</fsummary>
<desc>
- <p>These functions appends data at the end of the buffer <c><![CDATA[x]]></c>.</p>
+ <p>Frees an <c>ei_x_buff</c> buffer.
+ The memory used by the buffer is returned to the OS.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name>
- <fsummary>skip a term</fsummary>
+ <name><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name>
+ <fsummary>Allocate a new buffer.</fsummary>
<desc>
- <p>This function skips a term in the given buffer, it
- recursively skips elements of lists and tuples, so that a
- full term is skipped. This is a way to get the size of an
- erlang term.</p>
- <p><c><![CDATA[buf]]></c> is the buffer.</p>
- <p><c><![CDATA[index]]></c> is updated to point right after the term in the
- buffer.</p>
- <note>
- <p>This can be useful when you want to hold arbitrary
- terms: just skip them and copy the binary term data to some
- buffer.</p>
- </note>
- <p>The function returns <c><![CDATA[0]]></c> on success and <c><![CDATA[-1]]></c> on
- failure.</p>
+ <p>Allocates a new <c>ei_x_buff</c> buffer. The
+ fields of the structure pointed to by parameter <c>x</c>
+ is filled in, and a default buffer is allocated.
+ <c>ei_x_new_with_version()</c> also puts an initial
+ version byte, which is used in the binary format (so that
+ <c>ei_x_encode_version()</c> will not be needed.)</p>
</desc>
</func>
</funcs>
<section>
<title>Debug Information</title>
- <p>Some tips on what to check when the emulator doesn't seem to
- receive the terms that you send.</p>
+ <p>Some tips on what to check when the emulator does not seem to
+ receive the terms that you send:</p>
+
<list type="bulleted">
- <item>be careful with the version header, use
- <c><![CDATA[ei_x_new_with_version()]]></c> when appropriate</item>
- <item>turn on distribution tracing on the erlang node</item>
- <item>check the result codes from ei_decode_-calls</item>
+ <item>Be careful with the version header, use
+ <c>ei_x_new_with_version()</c> when appropriate.</item>
+ <item>Turn on distribution tracing on the Erlang node.</item>
+ <item>Check the result codes from <c>ei_decode_-calls</c>.</item>
</list>
</section>
<section>
<title>See Also</title>
- <p>erl_interface(3)</p>
+ <p><seealso marker="erl_eterm"><c>erl_eterm</c></seealso></p>
</section>
</cref>
-
diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml
index 516357b6a3..607a7cbff4 100644
--- a/lib/erl_interface/doc/src/ei_connect.xml
+++ b/lib/erl_interface/doc/src/ei_connect.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,100 +19,233 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>ei_connect</title>
<prepared>Jakob Cederlund</prepared>
<docno></docno>
- <approved>?</approved>
- <checked>?</checked>
+ <approved></approved>
+ <checked></checked>
<date>2001-09-01</date>
<rev>A</rev>
- <file>ei_connect.sgml</file>
+ <file>ei_connect.xml</file>
</header>
<lib>ei_connect</lib>
- <libsummary>Communicate with distributed erlang</libsummary>
+ <libsummary>Communicate with distributed Erlang.</libsummary>
<description>
- <p>This module enables C programs to communicate with erlang nodes,
- using the erlang distribution over TCP/IP.</p>
- <p>A C node appears to Erlang as a
- <em>hidden node</em>.
+ <p>This module enables C-programs to communicate with Erlang nodes,
+ using the Erlang distribution over TCP/IP.</p>
+
+ <p>A C-node appears to Erlang as a <em>hidden node</em>.
That is, Erlang processes that know the name of the
- C node are able to communicate with it in a normal manner, but
- the node name will not appear in the listing provided by the
- Erlang function <c><![CDATA[nodes/0]]></c>.</p>
- <p>The environment variable <c><![CDATA[ERL_EPMD_PORT]]></c> can be used
- to indicate which logical cluster a C node belongs to.</p>
+ C-node can communicate with it in a normal manner, but
+ the node name is not shown in the listing provided by
+ <seealso marker="erts:erlang#nodes/0"><c>erlang:nodes/0</c></seealso>
+ in <c>ERTS</c>.</p>
+
+ <p>The environment variable <c>ERL_EPMD_PORT</c> can be used
+ to indicate which logical cluster a C-node belongs to.</p>
</description>
<section>
- <title>Timeout functions</title>
+ <title>Time-Out Functions</title>
<p>Most functions appear in a version with the suffix
- <c><![CDATA[_tmo]]></c> appended to the function name. Those function take
- an additional argument, a timeout in <em>milliseconds</em>. The
- semantics is this; for each communication primitive involved in
+ <c>_tmo</c> appended to the function name. Those functions
+ take an extra argument, a time-out in <em>milliseconds</em>. The
+ semantics is this: for each communication primitive involved in
the operation, if the primitive does not complete within the time
- specified, the function will return an error and
- <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[ETIMEDOUT]]></c>. With
- communication primitive is meant an operation on the socket, like
- <c><![CDATA[connect]]></c>, <c><![CDATA[accept]]></c>, <c><![CDATA[recv]]></c> or <c><![CDATA[send]]></c>.</p>
- <p>Obviously the timeouts are for implementing fault tolerance,
- not to keep hard realtime promises. The <c><![CDATA[_tmo]]></c> functions
+ specified, the function returns an error and
+ <c>erl_errno</c> is set to <c>ETIMEDOUT</c>.
+ With communication primitive is meant an operation on the socket, like
+ <c>connect</c>, <c>accept</c>,
+ <c>recv</c>, or <c>send</c>.</p>
+
+ <p>Clearly the time-outs are for implementing fault tolerance,
+ not to keep hard real-time promises. The <c>_tmo</c> functions
are for detecting non-responsive peers and to avoid blocking on
- socket operations. </p>
- <p>A timeout value of <c><![CDATA[0]]></c> (zero), means that timeouts are
- disabled. Calling a <c><![CDATA[_tmo]]></c>-function with the last argument as
- <c><![CDATA[0]]></c> is therefore exactly the same thing as calling the
- function without the <c><![CDATA[_tmo]]></c> suffix.</p>
- <p>As with all other ei functions, you are <em>not</em> expected
- to put the socket in non blocking mode yourself in the program. Every
- use of non blocking mode is embedded inside the timeout
+ socket operations.</p>
+
+ <p>A time-out value of <c>0</c> (zero) means that time-outs are
+ disabled. Calling a <c>_tmo</c> function with the last
+ argument as <c>0</c> is therefore the same thing as calling
+ the function without the <c>_tmo</c> suffix.</p>
+
+ <p>As with all other functions starting with <c>ei_</c>,
+ you are <em>not</em> expected
+ to put the socket in non-blocking mode yourself in the program. Every
+ use of non-blocking mode is embedded inside the time-out
functions. The socket will always be back in blocking mode after
the operations are completed (regardless of the result). To
- avoid problems, leave the socket options alone. Ei will handle
+ avoid problems, leave the socket options alone. <c>ei</c> handles
any socket options that need modification.</p>
- <p>In all other senses, the <c><![CDATA[_tmo]]></c> functions inherit all
- the return values and the semantics from the functions without
- the <c><![CDATA[_tmo]]></c> suffix.</p>
+
+ <p>In all other senses, the <c>_tmo</c> functions inherit all
+ the return values and the semantics from the functions without
+ the <c>_tmo</c> suffix.</p>
</section>
+
<funcs>
<func>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyname(const char *name)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
+ <fsummary>Name lookup functions.</fsummary>
+ <desc>
+ <p>Convenience functions for some common name lookup functions.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name>
+ <fsummary>Accept a connection from another node.</fsummary>
+ <desc>
+ <p>Used by a server process to accept a
+ connection from a client process.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>ec</c> is the C-node structure.</p>
+ </item>
+ <item>
+ <p><c>listensock</c> is an open socket descriptor on
+ which <c>listen()</c> has previously been called.</p>
+ </item>
+ <item>
+ <p><c>conp</c> is a pointer to an
+ <c>ErlConnect</c> struct, described as follows:</p>
+ <code type="none"><![CDATA[
+typedef struct {
+ char ipadr[4];
+ char nodename[MAXNODELEN];
+} ErlConnect;
+ ]]></code>
+ </item>
+ </list>
+ <p>On success, <c>conp</c> is filled in with the address and
+ node name of the connecting client and a file descriptor is
+ returned. On failure, <c>ERL_ERROR</c> is returned and
+ <c>erl_errno</c> is set to <c>EIO</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name>
+ <fsummary>Accept a connection from another node with optional
+ time-out.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <c>ei_accept</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name>
+ <name><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name>
+ <fsummary>Establish a connection to an Erlang node.</fsummary>
+ <desc>
+ <p>Sets up a connection to an Erlang node.</p>
+ <p><c>ei_xconnect()</c> requires the IP address of the
+ remote host and the alive name of the remote node to be
+ specified. <c>ei_connect()</c> provides an alternative
+ interface and determines the information from the node name
+ provided.</p>
+ <list type="bulleted">
+ <item><c>addr</c> is the 32-bit IP address of the remote
+ host.</item>
+ <item><c>alive</c> is the alivename of the remote node.
+ </item>
+ <item><c>node</c> is the name of the remote node.</item>
+ </list>
+ <p>These functions return an open file descriptor on success, or
+ a negative value indicating that an error occurred. In the latter
+ case they set <c>erl_errno</c> to one of the
+ following:</p>
+ <taglist>
+ <tag><c>EHOSTUNREACH</c></tag>
+ <item>The remote host <c>node</c> is unreachable.</item>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ <p>Also, <c>errno</c> values from
+ <c>socket</c><em>(2)</em> and
+ <c>connect</c><em>(2)</em>
+ system calls may be propagated into <c>erl_errno</c>.</p>
+ <p><em>Example:</em></p>
+ <code type="none"><![CDATA[
+#define NODE "[email protected]"
+#define ALIVE "madonna"
+#define IP_ADDR "150.236.14.75"
+
+/*** Variant 1 ***/
+int fd = ei_connect(&ec, NODE);
+
+/*** Variant 2 ***/
+struct in_addr addr;
+addr.s_addr = inet_addr(IP_ADDR);
+fd = ei_xconnect(&ec, &addr, ALIVE);
+ ]]></code>
+ </desc>
+ </func>
+
+ <func>
<name><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name>
<name><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name>
<fsummary>Initialize for a connection.</fsummary>
<desc>
- <p>These function initializes the <c><![CDATA[ec]]></c> structure, to
+ <p>Initializes the <c>ec</c> structure, to
identify the node name and cookie of the server. One of them
- has to be called before other functions that works on the
- type <c><![CDATA[ei_cnode]]></c> or a file descriptor associated with a
- connection to another node are used.</p>
- <p><c><![CDATA[ec]]></c> is a structure containing information about the
- C-node. It is used in other <c><![CDATA[ei]]></c> functions for
- connecting and receiving data.</p>
- <p><c><![CDATA[this_node_name]]></c> is the registered name of the process
- (the name before '@').</p>
- <p><c><![CDATA[cookie]]></c> is the cookie for the node.</p>
- <p><c><![CDATA[creation]]></c> identifies a specific instance of a C
- node. It can help prevent the node from receiving messages
- sent to an earlier process with the same registered name.</p>
- <p><c><![CDATA[thishostname]]></c> is the name of the machine we're running
- on. If long names are to be used, it should be fully
- qualified (i.e. <c><![CDATA[durin.erix.ericsson.se]]></c> instead of
- <c><![CDATA[durin]]></c>).</p>
- <p><c><![CDATA[thisalivename]]></c> is the registered name of the process.</p>
- <p><c><![CDATA[thisnodename]]></c> is the full name of the node,
- i.e. <c><![CDATA[einode@durin]]></c>.</p>
- <p><c><![CDATA[thispaddr]]></c> if the IP address of the host.</p>
- <p>A C node acting as a server will be assigned a creation
- number when it calls <c><![CDATA[ei_publish()]]></c>.</p>
- <p>A connection is closed by simply closing the socket. Refer
- to system documentation to close the socket gracefully (when
- there are outgoing packets before close).</p>
- <p>This function return a negative value indicating that an error
+ must be called before other functions that works on the
+ <c>ei_cnode</c> type or a file descriptor associated with
+ a connection to another node is used.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>ec</c> is a structure containing information about
+ the C-node. It is used in other <c>ei</c> functions
+ for connecting and receiving data.</p>
+ </item>
+ <item>
+ <p><c>this_node_name</c> is the registered name of the
+ process (the name before '@').</p>
+ </item>
+ <item>
+ <p><c>cookie</c> is the cookie for the node.</p>
+ </item>
+ <item>
+ <p><c>creation</c> identifies a specific instance of a
+ C-node. It can help prevent the node from receiving messages
+ sent to an earlier process with the same registered name.</p>
+ </item>
+ <item>
+ <p><c>thishostname</c> is the name of the machine we are
+ running on. If long names are to be used, they are to be fully
+ qualified (that is, <c>durin.erix.ericsson.se</c>
+ instead of <c>durin</c>).</p>
+ </item>
+ <item>
+ <p><c>thisalivename</c> is the registered name of the
+ process.</p>
+ </item>
+ <item>
+ <p><c>thisnodename</c> is the full name of the node,
+ that is, <c>einode@durin</c>.</p>
+ </item>
+ <item>
+ <p><c>thispaddr</c> if the IP address of the host.</p>
+ </item>
+ </list>
+ <p>A C-node acting as a server is assigned a creation
+ number when it calls <c>ei_publish()</c>.</p>
+ <p>A connection is closed by simply closing the socket.
+ For information about how to close the socket gracefully (when
+ there are outgoing packets before close), see the relevant system
+ documentation.</p>
+ <p>These functions return a negative value indicating that an error
occurred.</p>
- <p>Example 1:
- </p>
+ <p><em>Example 1:</em></p>
<code type="none"><![CDATA[
int n = 0;
struct in_addr addr;
@@ -129,8 +262,7 @@ if (ei_connect_xinit(&ec,
exit(-1);
}
]]></code>
- <p>Example 2:
- </p>
+ <p><em>Example 2:</em></p>
<code type="none"><![CDATA[
if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
fprintf(stderr,"ERROR when initializing: %d",erl_errno);
@@ -139,114 +271,184 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
]]></code>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name>
- <name><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name>
- <fsummary>Establishe a connection to an Erlang node</fsummary>
+ <name><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name>
+ <name><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name>
+ <fsummary>Establish a connection to an Erlang node with optional
+ time-out.</fsummary>
<desc>
- <p>These functions set up a connection to an Erlang node.</p>
- <p><c><![CDATA[ei_xconnect()]]></c> requires the IP address of the remote
- host and the alive name of the remote node
- to be specified. <c><![CDATA[ei_connect()]]></c> provides an alternative
- interface, and determines the information from the node name
- provided.</p>
- <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the remote host.</p>
- <p><c><![CDATA[alive]]></c> is the alivename of the remote node.</p>
- <p><c><![CDATA[node]]></c> is the name of the remote node.</p>
- <p>These functions return an open file descriptor on success, or
- a negative value indicating that an error occurred --- in
- which case they will set <c><![CDATA[erl_errno]]></c> to one of:</p>
- <taglist>
- <tag><c><![CDATA[EHOSTUNREACH]]></c></tag>
- <item>The remote host <c><![CDATA[node]]></c> is unreachable</item>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
- <item>I/O error.</item>
- </taglist>
- <p>Additionally, <c><![CDATA[errno]]></c> values from
- <c><![CDATA[socket]]></c><em>(2)</em> and <c><![CDATA[connect]]></c><em>(2)</em>
- system calls may be propagated into <c><![CDATA[erl_errno]]></c>.</p>
- <p>Example:</p>
- <code type="none"><![CDATA[
-#define NODE "[email protected]"
-#define ALIVE "madonna"
-#define IP_ADDR "150.236.14.75"
+ <p>Equivalent to
+ <c>ei_connect</c> and <c>ei_xconnect</c> with an optional time-out
+ argument, see the description at the beginning of this manual
+ page.</p>
+ </desc>
+ </func>
-/*** Variant 1 ***/
-int fd = ei_connect(&ec, NODE);
+ <func>
+ <name><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name>
+ <name><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name>
+ <fsummary>Get and set functions for tracing.</fsummary>
+ <desc>
+ <p>Used to set tracing on the distribution. The levels are different
+ verbosity levels. A higher level means more information. See also
+ section <seealso marker="#debug_information">
+ Debug Information</seealso>.</p>
+ <p>These functions are not thread safe.</p>
+ </desc>
+ </func>
-/*** Variant 2 ***/
-struct in_addr addr;
-addr.s_addr = inet_addr(IP_ADDR);
-fd = ei_xconnect(&ec, &addr, ALIVE);
- ]]></code>
+ <func>
+ <name><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name>
+ <fsummary>Publish a node name.</fsummary>
+ <desc>
+ <p>Used by a server process to register
+ with the local name server EPMD, thereby allowing
+ other processes to send messages by using the registered name.
+ Before calling either of these functions, the process should
+ have called <c>bind()</c> and <c>listen()</c>
+ on an open socket.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>ec</c> is the C-node structure.</p>
+ </item>
+ <item>
+ <p><c>port</c> is the local name to register, and is to
+ be the same as the port number that was previously bound to the
+ socket.</p>
+ </item>
+ <item>
+ <p><c>addr</c> is the 32-bit IP address of the local
+ host.</p>
+ </item>
+ </list>
+ <p>To unregister with EPMD, simply close the returned descriptor. Do
+ not use <c>ei_unpublish()</c>, which is deprecated
+ anyway.</p>
+ <p>On success, the function returns a descriptor connecting the
+ calling process to EPMD. On failure, <c>-1</c> is returned and
+ <c>erl_errno</c> is set to <c>EIO</c>.</p>
+ <p>Also, <c>errno</c> values from
+ <c>socket</c><em>(2)</em> and
+ <c>connect</c><em>(2)</em> system calls may be propagated
+ into <c>erl_errno</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name>
- <name><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name>
- <fsummary>Establish a connection to an Erlang node with optional timeout</fsummary>
+ <name><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name>
+ <fsummary>Publish a node name with optional time-out.</fsummary>
<desc>
- <p>ei_connect and ei_xconnect with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>Equivalent to
+ <c>ei_publish</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name>
- <fsummary>Receive a message</fsummary>
+ <fsummary>Receive a message.</fsummary>
<desc>
- <p>This function receives a message consisting of a sequence
+ <p>Receives a message consisting of a sequence
of bytes in the Erlang external format.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. It
- is obtained from a previous <c><![CDATA[ei_connect]]></c> or
- <c><![CDATA[ei_accept]]></c>.</p>
- <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected
- message. </p>
- <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p>
- <p>If a <em>tick</em> occurs, i.e., the Erlang node on the
+ <list type="bulleted">
+ <item>
+ <p><c>fd</c> is an open descriptor to an Erlang
+ connection. It is obtained from a previous
+ <c>ei_connect</c> or <c>ei_accept</c>.</p>
+ </item>
+ <item>
+ <p><c>bufp</c> is a buffer large enough to hold the
+ expected message.</p>
+ </item>
+ <item>
+ <p><c>bufsize</c> indicates the size of
+ <c>bufp</c>.</p>
+ </item>
+ </list>
+ <p>If a <em>tick</em> occurs, that is, the Erlang node on the
other end of the connection has polled this node to see if it
- is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> and
- no message will be placed in the buffer. Also,
- <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[EAGAIN]]></c>.</p>
+ is still alive, the function returns <c>ERL_TICK</c> and
+ no message is placed in the buffer. Also,
+ <c>erl_errno</c> is set to <c>EAGAIN</c>.</p>
<p>On success, the message is placed in the specified buffer
and the function returns the number of bytes actually read. On
- failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set
- <c><![CDATA[erl_errno]]></c> to one of:</p>
+ failure, the function returns <c>ERL_ERROR</c> and sets
+ <c>erl_errno</c> to one of the following:</p>
<taglist>
- <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <tag><c>EAGAIN</c></tag>
<item>Temporary error: Try again.</item>
- <tag><c><![CDATA[EMSGSIZE]]></c></tag>
- <item>Buffer too small.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>EMSGSIZE</c></tag>
+ <item>Buffer is too small.</item>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
</taglist>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name>
- <fsummary>Receive a message with optional timeout</fsummary>
+ <name><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name>
+ <fsummary>Obsolete function for receiving a message.</fsummary>
<desc>
- <p>ei_receive with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>This function is retained for compatibility with code
+ generated by the interface compiler and with code following
+ examples in the same application.</p>
+ <p>In essence, the function performs the same operation as
+ <c>ei_xreceive_msg</c>, but instead of using an
+ <c>ei_x_buff</c>, the function expects a pointer to a character
+ pointer (<c>mbufp</c>), where the character pointer
+ is to point to a memory area allocated by <c>malloc</c>.
+ Argument <c>bufsz</c> is to be a pointer to an integer
+ containing the exact size (in bytes) of the memory area. The function
+ may reallocate the memory area and will in such cases put the new
+ size in <c>*bufsz</c> and update
+ <c>*mbufp</c>.</p>
+ <p>Returns either <c>ERL_TICK</c> or the
+ <c>msgtype</c> field of the
+ <c>erlang_msg *msg</c>. The length
+ of the message is put in <c>*msglen</c>. On error
+ a value <c>&lt; 0</c> is returned.</p>
+ <p>It is recommended to use <c>ei_xreceive_msg</c> instead when
+ possible, for the sake of readability. However, the function will
+ be retained in the interface for compatibility and
+ will <em>not</em> be removed in future releases without prior
+ notice.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name>
+ <fsummary>Obsolete function for receiving a message with time-out.
+ </fsummary>
+ <desc>
+ <p>Equivalent to
+ <c>ei_receive_encoded</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
<name><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
- <fsummary>Receive a message</fsummary>
+ <fsummary>Receive a message.</fsummary>
<desc>
- <p>These functions receives a message to the buffer in
- <c><![CDATA[x]]></c>. <c><![CDATA[ei_xreceive_msg]]></c> allows the buffer in
- <c><![CDATA[x]]></c> to grow, but <c><![CDATA[ei_receive_msg]]></c> fails if the
- message is bigger than the preallocated buffer in <c><![CDATA[x]]></c>.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[msg]]></c> is a pointer to an <c><![CDATA[erlang_msg]]></c> structure
- and contains information on the message received.</p>
- <p><c><![CDATA[x]]></c> is buffer obtained from <c><![CDATA[ei_x_new]]></c>.</p>
- <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the
- <c><![CDATA[msg]]></c> struct will be initialized. <c><![CDATA[erlang_msg]]></c>
- is defined as follows:</p>
+ <p>Receives a message to the buffer in <c>x</c>.
+ <c>ei_xreceive_msg</c> allows the buffer in
+ <c>x</c> to grow, but <c>ei_receive_msg</c>
+ fails if the message is larger than the pre-allocated buffer in
+ <c>x</c>.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>msg</c> is a pointer to an
+ <c>erlang_msg</c> structure
+ and contains information on the message received.</item>
+ <item><c>x</c> is buffer obtained from
+ <c>ei_x_new</c>.</item>
+ </list>
+ <p>On success, the functions return <c>ERL_MSG</c> and the
+ <c>msg</c> struct is initialized.
+ <c>erlang_msg</c> is defined as follows:</p>
<code type="none"><![CDATA[
typedef struct {
long msgtype;
@@ -257,125 +459,82 @@ typedef struct {
erlang_trace token;
} erlang_msg;
]]></code>
- <p><c><![CDATA[msgtype]]></c> identifies the type of message, and is one of
- <c><![CDATA[ERL_SEND]]></c>, <c><![CDATA[ERL_REG_SEND]]></c>, <c><![CDATA[ERL_LINK]]></c>,
- <c><![CDATA[ERL_UNLINK]]></c> and <c><![CDATA[ERL_EXIT]]></c>.</p>
- <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_SEND]]></c> this indicates that an
- ordinary send operation has taken place, and <c><![CDATA[msg->to]]></c>
- contains the Pid of the recipient (the C-node). If
- <c><![CDATA[type]]></c> is <c><![CDATA[ERL_REG_SEND]]></c> then a registered send
- operation took place, and <c><![CDATA[msg->from]]></c> contains the Pid
- of the sender.</p>
- <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_LINK]]></c> or <c><![CDATA[ERL_UNLINK]]></c>, then
- <c><![CDATA[msg->to]]></c> and <c><![CDATA[msg->from]]></c> contain the pids of the
- sender and recipient of the link or unlink.</p>
- <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_EXIT]]></c>, then this indicates that
- a link has been broken. In this case, <c><![CDATA[msg->to]]></c> and
- <c><![CDATA[msg->from]]></c> contain the pids of the linked processes.</p>
- <p>The return value is the same as for <c><![CDATA[ei_receive]]></c>, see
- above.</p>
+ <p><c>msgtype</c> identifies the type of message, and is
+ one of the following:</p>
+ <taglist>
+ <tag><c>ERL_SEND</c></tag>
+ <item>
+ <p>Indicates that an ordinary send operation has occurred.
+ <c>msg-&gt;to</c> contains the pid of the recipient (the
+ C-node).</p>
+ </item>
+ <tag><c>ERL_REG_SEND</c></tag>
+ <item>
+ <p>A registered send operation occurred.
+ <c>msg-&gt;from</c> contains the pid of the sender.</p>
+ </item>
+ <tag><c>ERL_LINK</c> or
+ <c>ERL_UNLINK</c></tag>
+ <item>
+ <p><c>msg-&gt;to</c> and
+ <c>msg-&gt;from</c> contain the pids of the
+ sender and recipient of the link or unlink.</p>
+ </item>
+ <tag><c>ERL_EXIT</c></tag>
+ <item>
+ <p>Indicates a broken link. <c>msg-&gt;to</c> and
+ <c>msg-&gt;from</c> contain the pids of the linked
+ processes.</p>
+ </item>
+ </taglist>
+ <p>The return value is the same as for
+ <seealso marker="#ei_receive"><c>ei_receive</c></seealso>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name>
<name><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name>
- <fsummary>Receive a message with optional timeout</fsummary>
- <desc>
- <p>ei_receive_msg and ei_xreceive_msg with an optional timeout argument,
- see the description at the beginning of this document.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name>
- <fsummary>Obsolete function for receiving a message</fsummary>
- <desc>
- <p>This function is retained for compatibility with code
- generated by the interface compiler and with code following
- examples in the same application.</p>
- <p>In essence the function performs the same operation as
- <c><![CDATA[ei_xreceive_msg]]></c>, but instead of using an ei_x_buff, the
- function expects a pointer to a character pointer
- (<c><![CDATA[mbufp]]></c>), where the character pointer should point to a
- memory area allocated by <c><![CDATA[malloc]]></c>. The argument
- <c><![CDATA[bufsz]]></c> should be a pointer to an integer containing the
- exact size (in bytes) of the memory area. The function may
- reallocate the memory area and will in such cases put the new
- size in <c><![CDATA[*bufsz]]></c> and update <c><![CDATA[*mbufp]]></c>.</p>
- <p>Furthermore the function returns either ERL_TICK or the
- <c><![CDATA[msgtype]]></c> field of the <c><![CDATA[erlang_msg *msg]]></c>. The actual
- length of the message is put in <c><![CDATA[*msglen]]></c>. On error it
- will return a value <c><![CDATA[< 0]]></c>.</p>
- <p>It is recommended to use ei_xreceive_msg instead when
- possible, for the sake of readability. The function will
- however be retained in the interface for compatibility and
- will <em>not</em> be removed not be removed in future releases
- without notice.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name>
- <fsummary>Obsolete function for receiving a message with timeout</fsummary>
- <desc>
- <p>ei_receive_encoded with an optional timeout argument,
- see the description at the beginning of this document.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
- <fsummary>Send a message</fsummary>
- <desc>
- <p>This function sends an Erlang term to a process.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[to]]></c> is the Pid of the intended recipient of the
- message.</p>
- <p><c><![CDATA[buf]]></c> is the buffer containing the term in binary
- format.</p>
- <p><c><![CDATA[len]]></c> is the length of the message in bytes.</p>
- <p>The function returns 0 if successful, otherwise -1, in the
- latter case it will set <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
- <fsummary>Send a message with optional timeout</fsummary>
+ <fsummary>Receive a message with optional time-out.</fsummary>
<desc>
- <p>ei_send with an optional timeout argument,
- see the description at the beginning of this document.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
- <fsummary>Obsolete function to send a message</fsummary>
- <desc>
- <p>Works exactly as ei_send, the alternative name retained for
- backward compatibility. The function will <em>not</em> be
- removed without notice.</p>
+ <p>Equivalent to <c>ei_receive_msg</c> and <c>ei_xreceive_msg</c>
+ with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
- <fsummary>Obsolete function to send a message with optional timeout</fsummary>
+ <name><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name>
+ <fsummary>Receive a message with optional time-out.</fsummary>
<desc>
- <p>ei_send_encoded with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>Equivalent to
+ <c>ei_receive</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name>
- <fsummary>Send a message to a registered name</fsummary>
+ <fsummary>Send a message to a registered name.</fsummary>
<desc>
- <p>This function sends an Erlang term to a registered process.
- </p>
- <p>This function sends an Erlang term to a process.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[server_name]]></c> is the registered name of the intended
- recipient.</p>
- <p><c><![CDATA[buf]]></c> is the buffer containing the term in binary
- format.</p>
- <p><c><![CDATA[len]]></c> is the length of the message in bytes.</p>
- <p>The function returns 0 if successful, otherwise -1, in the
- latter case it will set <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p>
- <p>Example, send the atom "ok" to the process "worker":</p>
+ <p>Sends an Erlang term to a registered process.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>fd</c> is an open descriptor to an Erlang
+ connection.</p>
+ </item>
+ <item><c>server_name</c> is the registered name of the
+ intended recipient.</item>
+ <item><c>buf</c> is the buffer containing the term in
+ binary format.</item>
+ <item><c>len</c> is the length of the message in bytes.
+ </item>
+ </list>
+ <p>Returns <c>0</c> if successful, otherwise <c>-1</c>. In
+ the latter case it sets <c>erl_errno</c> to
+ <c>EIO</c>.</p>
+ <p><em>Example:</em></p>
+ <p>Send the atom "ok" to the process "worker":</p>
<code type="none"><![CDATA[
ei_x_buff x;
ei_x_new_with_version(&x);
@@ -385,96 +544,98 @@ if (ei_reg_send(&ec, fd, x.buff, x.index) < 0)
]]></code>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name>
- <fsummary>Send a message to a registered name with optional timeout</fsummary>
- <desc>
- <p>ei_reg_send with an optional timeout argument,
- see the description at the beginning of this document.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
- <fsummary>Obsolete function to send a message to a registered name</fsummary>
- <desc>
- <p>This function is retained for compatibility with code
- generated by the interface compiler and with code following
- examples in the same application.</p>
- <p>The function works as <c><![CDATA[ei_reg_send]]></c> with one
- exception. Instead of taking the <c><![CDATA[ei_cnode]]></c> as a first
- argument, it takes a second argument, an <c><![CDATA[erlang_pid]]></c>
- which should be the process identifier of the sending process
- (in the erlang distribution protocol). </p>
- <p>A suitable <c><![CDATA[erlang_pid]]></c> can be constructed from the
- <c><![CDATA[ei_cnode]]></c> structure by the following example code:</p>
- <code type="none"><![CDATA[
- ei_cnode ec;
- erlang_pid *self;
- int fd; /* the connection fd */
- ...
- self = ei_self(&ec);
- self->num = fd;
- ]]></code>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
- <fsummary>Obsolete function to send a message to a registered name with timeout</fsummary>
+ <fsummary>Send a message to a registered name with optional time-out
+ </fsummary>
<desc>
- <p>ei_send_reg_encoded with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>Equivalent to
+ <c>ei_reg_send</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name>
<name><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name>
<name><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name>
- <fsummary>Remote Procedure Call from C to Erlang</fsummary>
+ <fsummary>Remote Procedure Call from C to Erlang.</fsummary>
<desc>
- <p>These functions support calling Erlang functions on remote nodes.
- <c><![CDATA[ei_rpc_to()]]></c> sends an rpc request to a remote node and
- <c><![CDATA[ei_rpc_from()]]></c> receives the results of such a call.
- <c><![CDATA[ei_rpc()]]></c> combines the functionality of these two functions
- by sending an rpc request and waiting for the results. See also
- <c><![CDATA[rpc:call/4]]></c>. </p>
- <p><c><![CDATA[ec]]></c> is the C-node structure previously initiated by a
- call to <c><![CDATA[ei_connect_init()]]></c> or
- <c><![CDATA[ei_connect_xinit()]]></c></p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[timeout]]></c> is the maximum time (in ms) to wait for
- results. Specify <c><![CDATA[ERL_NO_TIMEOUT]]></c> to wait forever.
- <c><![CDATA[ei_rpc()]]></c> will wait infinitely for the answer,
- i.e. the call will never time out.</p>
- <p><c><![CDATA[mod]]></c> is the name of the module containing the function
- to be run on the remote node.</p>
- <p><c><![CDATA[fun]]></c> is the name of the function to run.</p>
- <p><c><![CDATA[argbuf]]></c> is a pointer to a buffer with an encoded
- Erlang list, without a version magic number, containing the
- arguments to be passed to the function.</p>
- <p><c><![CDATA[argbuflen]]></c> is the length of the buffer containing the
- encoded Erlang list.</p>
- <p><c><![CDATA[msg]]></c> structure of type <c><![CDATA[erlang_msg]]></c> and contains
- information on the message received. See <c><![CDATA[ei_receive_msg()]]></c>
- for a description of the <c><![CDATA[erlang_msg]]></c> format.</p>
- <p><c><![CDATA[x]]></c> points to the dynamic buffer that receives the
- result. For for <c><![CDATA[ei_rpc()]]></c> this will be the result
- without the version magic number. For <c><![CDATA[ei_rpc_from()]]></c>
- the result will return a version magic number and a 2-tuple
- <c><![CDATA[{rex,Reply}]]></c>.</p>
- <p><c><![CDATA[ei_rpc()]]></c> returns the number of bytes in the result
- on success and -1 on failure. <c><![CDATA[ei_rpc_from()]]></c> returns
- number of bytes or one of <c><![CDATA[ERL_TICK]]></c>, <c><![CDATA[ERL_TIMEOUT]]></c>
- and <c><![CDATA[ERL_ERROR]]></c> otherwise. When failing,
- all three functions set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <p>Supports calling Erlang functions on remote nodes.
+ <c>ei_rpc_to()</c> sends an RPC request to a remote node
+ and <c>ei_rpc_from()</c> receives the results of such a
+ call. <c>ei_rpc()</c> combines the functionality of these
+ two functions by sending an RPC request and waiting for the results.
+ See also <seealso marker="kernel:rpc#call/4">
+ <c>rpc:call/4</c></seealso> in Kernel.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>ec</c> is the C-node structure previously
+ initiated by a call to <c>ei_connect_init()</c> or
+ <c>ei_connect_xinit()</c>.</p>
+ </item>
+ <item>
+ <p><c>fd</c> is an open descriptor to an Erlang
+ connection.</p>
+ </item>
+ <item>
+ <p><c>timeout</c> is the maximum time (in milliseconds)
+ to wait for results. Specify <c>ERL_NO_TIMEOUT</c> to
+ wait forever.
+ <c>ei_rpc()</c> waits infinitely for the answer,
+ that is, the call will never time out.</p>
+ </item>
+ <item>
+ <p><c>mod</c> is the name of the module containing the
+ function to be run on the remote node.</p>
+ </item>
+ <item>
+ <p><c>fun</c> is the name of the function to run.</p>
+ </item>
+ <item>
+ <p><c>argbuf</c> is a pointer to a buffer with an
+ encoded Erlang list, without a version magic number, containing
+ the arguments to be passed to the function.</p>
+ </item>
+ <item>
+ <p><c>argbuflen</c> is the length of the buffer
+ containing the encoded Erlang list.</p>
+ </item>
+ <item>
+ <p><c>msg</c> is structure of type
+ <c>erlang_msg</c> and contains information on the
+ message
+ received. For a description of the <c>erlang_msg</c>
+ format, see <seealso marker="#ei_receive_msg">
+ <c>ei_receive_msg</c></seealso>.</p>
+ </item>
+ <item>
+ <p><c>x</c> points to the dynamic buffer that receives
+ the result. For <c>ei_rpc()</c> this is the result
+ without the version magic number. For
+ <c>ei_rpc_from()</c> the result returns a version
+ magic number and a 2-tuple <c>{rex,Reply}</c>.</p>
+ </item>
+ </list>
+ <p><c>ei_rpc()</c> returns the number of bytes in the
+ result on success and <c>-1</c> on failure.
+ <c>ei_rpc_from()</c> returns the
+ number of bytes, otherwise one of <c>ERL_TICK</c>,
+ <c>ERL_TIMEOUT</c>,
+ and <c>ERL_ERROR</c>. When failing, all three
+ functions set <c>erl_errno</c> to one of the
+ following:</p>
<taglist>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
- <tag><c><![CDATA[ETIMEDOUT]]></c></tag>
- <item>Timeout expired.</item>
- <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <tag><c>ETIMEDOUT</c></tag>
+ <item>Time-out expired.</item>
+ <tag><c>EAGAIN</c></tag>
<item>Temporary error: Try again.</item>
</taglist>
- <p>Example, check to see if an erlang process is alive:</p>
+ <p><em>Example:</em></p>
+ <p>Check to see if an Erlang process is alive:</p>
<code type="none"><![CDATA[
int index = 0, is_alive;
ei_x_buff args, result;
@@ -495,170 +656,190 @@ if (ei_decode_version(result.buff, &index) < 0
]]></code>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name>
- <fsummary>Publish a node name</fsummary>
+ <name><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name>
+ <fsummary>Retrieve the pid of the C-node.</fsummary>
<desc>
- <p>These functions are used by a server process to register
- with the local name server <em>epmd</em>, thereby allowing
- other processes to send messages by using the registered name.
- Before calling either of these functions, the process should
- have called <c><![CDATA[bind()]]></c> and <c><![CDATA[listen()]]></c> on an open socket.</p>
- <p><c><![CDATA[ec]]></c> is the C-node structure.</p>
- <p><c><![CDATA[port]]></c> is the local name to register, and should be the
- same as the port number that was previously bound to the socket.</p>
- <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the local host.</p>
- <p>To unregister with epmd, simply close the returned
- descriptor. Do not use <c><![CDATA[ei_unpublish()]]></c>, which is deprecated anyway.</p>
- <p>On success, the functions return a descriptor connecting the
- calling process to epmd. On failure, they return -1 and set
- <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p>
- <p>Additionally, <c><![CDATA[errno]]></c> values from <c><![CDATA[socket]]></c><em>(2)</em>
- and <c><![CDATA[connect]]></c><em>(2)</em> system calls may be propagated
- into <c><![CDATA[erl_errno]]></c>.</p>
+ <p>Retrieves the pid of the C-node. Every C-node
+ has a (pseudo) pid used in <c>ei_send_reg</c>,
+ <c>ei_rpc</c>,
+ and others. This is contained in a field in the <c>ec</c>
+ structure. It will be safe for a long time to fetch this
+ field directly from the <c>ei_cnode</c> structure.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name>
- <fsummary>Publish a node name with optional timeout</fsummary>
+ <name><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
+ <fsummary>Send a message.</fsummary>
<desc>
- <p>ei_publish with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>Sends an Erlang term to a process.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>to</c> is the pid of the intended recipient of
+ the message.</item>
+ <item><c>buf</c> is the buffer containing the term in
+ binary format.</item>
+ <item><c>len</c> is the length of the message in bytes.
+ </item>
+ </list>
+ <p>Returns <c>0</c> if successful, otherwise <c>-1</c>. In
+ the latter case it sets <c>erl_errno</c> to
+ <c>EIO</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name>
- <fsummary>Accept a connection from another node</fsummary>
+ <name><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
+ <fsummary>Obsolete function to send a message.</fsummary>
<desc>
- <p>This function is used by a server process to accept a
- connection from a client process.</p>
- <p><c><![CDATA[ec]]></c> is the C-node structure.</p>
- <p><c><![CDATA[listensock]]></c> is an open socket descriptor on which
- <c><![CDATA[listen()]]></c> has previously been called.</p>
- <p><c><![CDATA[conp]]></c> is a pointer to an <c><![CDATA[ErlConnect]]></c> struct,
- described as follows:</p>
- <code type="none"><![CDATA[
-typedef struct {
- char ipadr[4];
- char nodename[MAXNODELEN];
-} ErlConnect;
- ]]></code>
- <p>On success, <c><![CDATA[conp]]></c> is filled in with the address and
- node name of the connecting client and a file descriptor is
- returned. On failure, <c><![CDATA[ERL_ERROR]]></c> is returned and
- <c><![CDATA[erl_errno]]></c> is set to <c><![CDATA[EIO]]></c>.</p>
+ <p>Works exactly as <c>ei_send</c>, the alternative name is retained for
+ backward compatibility. The function will <em>not</em> be
+ removed without prior notice.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name>
- <fsummary>Accept a connection from another node with optional timeout</fsummary>
+ <name><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <fsummary>Obsolete function to send a message with optional time-out.
+ </fsummary>
<desc>
- <p>ei_accept with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>Equivalent to
+ <c>ei_send_encoded</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name>
- <fsummary>Forcefully unpublish a node name</fsummary>
+ <name><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
+ <fsummary>Obsolete function to send a message to a registered name.
+ </fsummary>
<desc>
- <p>This function can be called by a process to unregister a
- specified node from epmd on the localhost. This is however usually not
- allowed, unless epmd was started with the -relaxed_command_check
- flag, which it normally isn't.</p>
-
- <p>To unregister a node you have published, you should
- close the descriptor that was returned by
- <c><![CDATA[ei_publish()]]></c>.</p>
+ <p>This function is retained for compatibility with code
+ generated by the interface compiler and with code following
+ examples in the same application.</p>
+ <p>The function works as <c>ei_reg_send</c> with one
+ exception. Instead of taking <c>ei_cnode</c> as first
+ argument, it takes a second argument, an
+ <c>erlang_pid</c>,
+ which is to be the process identifier of the sending process
+ (in the Erlang distribution protocol).</p>
+ <p>A suitable <c>erlang_pid</c> can be constructed from the
+ <c>ei_cnode</c> structure by the following example
+ code:</p>
+ <code type="none"><![CDATA[
+ei_cnode ec;
+erlang_pid *self;
+int fd; /* the connection fd */
+...
+self = ei_self(&ec);
+self->num = fd;
+ ]]></code>
+ </desc>
+ </func>
- <warning>
- <p>This function is deprecated and will be removed in a future
- release.</p>
- </warning>
- <p><c><![CDATA[ec]]></c> is the node structure of the node to unregister.</p>
- <p>If the node was successfully unregistered from epmd, the
- function returns 0. Otherwise, it returns -1 and sets
- <c><![CDATA[erl_errno]]></c> is to <c><![CDATA[EIO]]></c>.</p>
+ <func>
+ <name><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
+ <fsummary>Obsolete function to send a message to a registered name with
+ time-out.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <c>ei_send_reg_encoded</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name>
- <fsummary>Unpublish a node name with optional timeout</fsummary>
+ <name><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <fsummary>Send a message with optional time-out.</fsummary>
<desc>
- <p>ei_unpublish with an optional timeout argument,
- see the description at the beginning of this document.</p>
+ <p>Equivalent to
+ <c>ei_send</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
+
<func>
<name><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name>
<name><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name>
<name><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name>
- <fsummary>Retrieve some values</fsummary>
+ <fsummary>Retrieve some values.</fsummary>
<desc>
- <p>These functions can be used to retrieve information about
- the C Node. These values are initially set with
- <c><![CDATA[ei_connect_init()]]></c> or <c><![CDATA[ei_connect_xinit()]]></c>.</p>
- <p>They simply fetches the appropriate field from the <c><![CDATA[ec]]></c>
+ <p>Can be used to retrieve information about
+ the C-node. These values are initially set with
+ <c>ei_connect_init()</c> or
+ <c>ei_connect_xinit()</c>.</p>
+ <p>These function simply fetch the appropriate field from the
+ <c>ec</c>
structure. Read the field directly will probably be safe for
a long time, so these functions are not really needed.</p>
</desc>
</func>
+
<func>
- <name><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name>
- <fsummary>Retrieve the Pid of the C-node</fsummary>
- <desc>
- <p>This function retrieves the Pid of the C-node. Every C-node
- has a (pseudo) pid used in <c><![CDATA[ei_send_reg]]></c>, <c><![CDATA[ei_rpc]]></c>
- and others. This is contained in a field in the <c><![CDATA[ec]]></c>
- structure. It will be safe for a long time to fetch this
- field directly from the <c><![CDATA[ei_cnode]]></c> structure.</p>
- </desc>
- </func>
- <func>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyname(const char *name)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
- <fsummary>Name lookup functions</fsummary>
+ <name><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name>
+ <fsummary>Forcefully unpublish a node name.</fsummary>
<desc>
- <p>These are convenience functions for some common name lookup functions.</p>
+ <p>Can be called by a process to unregister a
+ specified node from EPMD on the local host. This is, however, usually
+ not allowed, unless EPMD was started with flag
+ <c>-relaxed_command_check</c>, which it normally is not.</p>
+ <p>To unregister a node you have published, you should
+ close the descriptor that was returned by
+ <c>ei_publish()</c>.</p>
+ <warning>
+ <p>This function is deprecated and will be removed in a future
+ release.</p>
+ </warning>
+ <p><c>ec</c> is the node structure of the node to
+ unregister.</p>
+ <p>If the node was successfully unregistered from EPMD, the
+ function returns <c>0</c>. Otherwise, <c>-1</c> is returned and
+ <c>erl_errno</c> is set to <c>EIO</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name>
- <name><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name>
- <fsummary>Get and set functions for tracing.</fsummary>
+ <name><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name>
+ <fsummary>Unpublish a node name with optional time-out.</fsummary>
<desc>
- <p>These functions are used to set tracing on the distribution. The levels are different verbosity levels. A higher level means more information.
- See also Debug Information and <c><![CDATA[EI_TRACELEVEL]]></c> below. </p>
- <p> <c><![CDATA[ei_set_tracelevel]]></c> and <c><![CDATA[ei_get_tracelevel]]></c> are not thread safe. </p>
+ <p>Equivalent to
+ <c>ei_unpublish</c> with an optional time-out argument,
+ see the description at the beginning of this manual page.</p>
</desc>
</func>
</funcs>
<section>
+ <marker id="debug_information"></marker>
<title>Debug Information</title>
<p>If a connection attempt fails, the following can be checked:</p>
+
<list type="bulleted">
- <item><c><![CDATA[erl_errno]]></c></item>
- <item>that the right cookie was used</item>
- <item>that <em>epmd</em> is running</item>
- <item>the remote Erlang node on the other side is running the
- same version of Erlang as the <c><![CDATA[ei]]></c>
- library.</item>
- <item>the environment variable <c><![CDATA[ERL_EPMD_PORT]]></c>
- is set correctly.</item>
+ <item><c>erl_errno</c>.</item>
+ <item>That the correct cookie was used</item>
+ <item>That EPMD is running</item>
+ <item>That the remote Erlang node on the other side is running the
+ same version of Erlang as the <c>ei</c> library</item>
+ <item>That environment variable <c>ERL_EPMD_PORT</c>
+ is set correctly</item>
</list>
- <p>The connection attempt can be traced by setting a tracelevel by either using
- <c><![CDATA[ei_set_tracelevel]]></c> or by setting the environment variable <c><![CDATA[EI_TRACELEVEL]]></c>.
- The different tracelevels has the following messages:</p>
+
+ <p>The connection attempt can be traced by setting a trace level by either
+ using <c>ei_set_tracelevel</c> or by setting environment
+ variable <c>EI_TRACELEVEL</c>.
+ The trace levels have the following messages:</p>
+
<list>
- <item>1: Verbose error messages</item>
- <item>2: Above messages and verbose warning messages </item>
- <item>3: Above messages and progress reports for connection handling</item>
- <item>4: Above messages and progress reports for communication</item>
- <item>5: Above messages and progress reports for data conversion</item>
+ <item>1: Verbose error messages</item>
+ <item>2: Above messages and verbose warning messages</item>
+ <item>3: Above messages and progress reports for connection handling
+ </item>
+ <item>4: Above messages and progress reports for communication</item>
+ <item>5: Above messages and progress reports for data conversion</item>
</list>
</section>
</cref>
-
diff --git a/lib/erl_interface/doc/src/ei_users_guide.xml b/lib/erl_interface/doc/src/ei_users_guide.xml
index 4b9809aee4..0eed50b50b 100644
--- a/lib/erl_interface/doc/src/ei_users_guide.xml
+++ b/lib/erl_interface/doc/src/ei_users_guide.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,10 +19,10 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
- <title>The El Library User's Guide</title>
+ <title>Erl_Interface User's Guide</title>
<prepared>Kent Boortz</prepared>
<responsible>Kent Boortz</responsible>
<docno></docno>
@@ -32,100 +32,158 @@
<rev></rev>
<file>ei_users_guide.xml</file>
</header>
- <p>The Erl_Interface library contains functions. which help you
- integrate programs written in C and Erlang. The functions in
- Erl_Interface support the following:</p>
- <list type="bulleted">
- <item>manipulation of data represented as Erlang data types</item>
- <item>conversion of data between C and Erlang formats</item>
- <item>encoding and decoding of Erlang data types for transmission or storage</item>
- <item>communication between C nodes and Erlang processes</item>
- <item>backup and restore of C node state to and from Mnesia</item>
- </list>
- <p>In the following sections, these topics are described:</p>
- <list type="bulleted">
- <item>compiling your code for use with Erl_Interface</item>
- <item>initializing Erl_Interface</item>
- <item>encoding, decoding, and sending Erlang terms</item>
- <item>building terms and patterns</item>
- <item>pattern matching</item>
- <item>connecting to a distributed Erlang node</item>
- <item>using EPMD</item>
- <item>sending and receiving Erlang messages</item>
- <item>remote procedure calls</item>
- <item>global names</item>
- <item>the registry</item>
- </list>
+
+ <section>
+ <title>Introduction</title>
+ <p>The <c>Erl_Interface</c> library contains functions that help you
+ integrate programs written in C and Erlang. The functions in
+ <c>Erl_Interface</c> support the following:</p>
+ <list type="bulleted">
+ <item>Manipulation of data represented as Erlang data types</item>
+ <item>Conversion of data between C and Erlang formats</item>
+ <item>Encoding and decoding of Erlang data types for transmission or
+ storage</item>
+ <item>Communication between C nodes and Erlang processes</item>
+ <item>Backup and restore of C node state to and from
+ <seealso marker="mnesia:mnesia">Mnesia</seealso></item>
+ </list>
+ <note>
+ <p>By default, the <c>Erl_Interface</c> libraries are only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the libraries themselves. For information about how to
+ communicate with Erlang/OTP components from earlier releases, see
+ function <seealso marker="ei#ei_set_compat_rel">
+ <c>ei:ei_set_compat_rel</c></seealso> and
+ <seealso marker="erl_eterm#erl_set_compat_rel">
+ <c>erl_eterm:erl_set_compat_rel</c></seealso>.</p>
+ </note>
+
+ <section>
+ <title>Scope</title>
+ <p>In the following sections, these topics are described:</p>
+ <list type="bulleted">
+ <item>Compiling your code for use with <c>Erl_Interface</c></item>
+ <item>Initializing <c>Erl_Interface</c></item>
+ <item>Encoding, decoding, and sending Erlang terms</item>
+ <item>Building terms and patterns</item>
+ <item>Pattern matching</item>
+ <item>Connecting to a distributed Erlang node</item>
+ <item>Using the Erlang Port Mapper Daemon (EPMD)</item>
+ <item>Sending and receiving Erlang messages</item>
+ <item>Remote procedure calls</item>
+ <item>Using global names</item>
+ <item>Using the registry</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>It is assumed that the reader is familiar with the Erlang programming
+ language.</p>
+ </section>
+ </section>
<section>
<title>Compiling and Linking Your Code</title>
- <p>In order to use any of the Erl_Interface functions, include the
+ <p>To use any of the <c>Erl_Interface</c> functions, include the
following lines in your code:</p>
+
<code type="none"><![CDATA[
#include "erl_interface.h"
#include "ei.h" ]]></code>
- <p>Determine where the top directory of your OTP installation is. You
- can find this out by starting Erlang and entering the following
+
+ <p>Determine where the top directory of your OTP installation is.
+ To find this, start Erlang and enter the following
command at the Eshell prompt:</p>
+
<code type="none"><![CDATA[
Eshell V4.7.4 (abort with ^G)
1> code:root_dir().
/usr/local/otp ]]></code>
- <p>To compile your code, make sure that your C compiler knows where
- to find <c><![CDATA[erl_interface.h]]></c> by specifying an appropriate <c><![CDATA[-I]]></c>
- argument on the command line, or by adding it to the <c><![CDATA[CFLAGS]]></c>
- definition in your <c><![CDATA[Makefile]]></c>. The correct value for this path is
- <c><![CDATA[$OTPROOT/lib/erl_interface]]></c><em>Vsn</em><c><![CDATA[/include]]></c>, where <c><![CDATA[$OTPROOT]]></c> is the path
- reported by <c><![CDATA[code:root_dir/0]]></c> in the above example, and <em>Vsn</em> is
- the version of the Erl_interface application, for example
- <c><![CDATA[erl_interface-3.2.3]]></c></p>
+
+ <p>To compile your code, ensure that your C compiler knows where
+ to find <c>erl_interface.h</c> by specifying an appropriate
+ <c>-I</c> argument on the command line, or add it to
+ the <c>CFLAGS</c> definition in your
+ <c>Makefile</c>. The correct value for this path is
+ <c>$OTPROOT/lib/erl_interface-$EIVSN/include</c>,
+ where:</p>
+
+ <list type="bulleted">
+ <item>
+ <p><c>$OTPROOT</c> is the path reported by
+ <c>code:root_dir/0</c> in the example above.</p>
+ </item>
+ <item>
+ <p><c>$EIVSN</c> is the version of the <c>Erl_Interface</c> application,
+ for example, <c>erl_interface-3.2.3</c>.</p>
+ </item>
+ </list>
+
+ <p>Compiling the code:</p>
+
<code type="none"><![CDATA[
$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c ]]></code>
- <p>When linking, you will need to specify the path to
- <c><![CDATA[liberl_interface.a]]></c> and <c><![CDATA[libei.a]]></c> with
- <c><![CDATA[-L$OTPROOT/lib/erl_interface-3.2.3/lib]]></c>, and you will need to specify the
- name of the libraries with <c><![CDATA[-lerl_interface -lei]]></c>. You can do
- this on the command line or by adding the flags to the <c><![CDATA[LDFLAGS]]></c>
- definition in your <c><![CDATA[Makefile]]></c>.</p>
+
+ <p>When linking:</p>
+
+ <list type="bulleted">
+ <item>Specify the path to <c>liberl_interface.a</c> and
+ <c>libei.a</c> with
+ <c>-L$OTPROOT/lib/erl_interface-3.2.3/lib</c>.</item>
+ <item>Specify the name of the libraries with
+ <c>-lerl_interface -lei</c>.</item>
+ </list>
+
+ <p>Do this on the command line or add the flags to the
+ <c>LDFLAGS</c> definition in your
+ <c>Makefile</c>.</p>
+
+ <p>Linking the code:</p>
+
<code type="none"><![CDATA[
$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
lib myprog.o -lerl_interface -lei -o myprog ]]></code>
- <p>Also, on some systems it may be necessary to link with some
- additional libraries (e.g. <c><![CDATA[libnsl.a]]></c> and <c><![CDATA[libsocket.a]]></c> on
- Solaris, or <c><![CDATA[wsock32.lib]]></c> on Windows) in order to use the
- communication facilities of Erl_Interface.</p>
- <p>If you are using Erl_Interface functions in a threaded
+
+ <p>On some systems it can be necessary to link with some more
+ libraries (for example, <c>libnsl.a</c> and
+ <c>libsocket.a</c> on Solaris, or
+ <c>wsock32.lib</c> on Windows) to use the
+ communication facilities of <c>Erl_Interface</c>.</p>
+
+ <p>If you use the <c>Erl_Interface</c> functions in a threaded
application based on POSIX threads or Solaris threads, then
- Erl_Interface needs access to some of the synchronization
- facilities in your threads package, and you will need to specify
- additional compiler flags in order to indicate which of the packages
- you are using. Define <c><![CDATA[_REENTRANT]]></c> and either <c><![CDATA[STHREADS]]></c> or
- <c><![CDATA[PTHREADS]]></c>. The default is to use POSIX threads if
- <c><![CDATA[_REENTRANT]]></c> is specified.</p>
+ <c>Erl_Interface</c> needs access to some of the synchronization
+ facilities in your threads package. You must specify extra
+ compiler flags to indicate which of the packages you use. Define
+ <c>_REENTRANT</c> and either <c>STHREADS</c> or
+ <c>PTHREADS</c>. The default is to use POSIX threads if
+ <c>_REENTRANT</c> is specified.</p>
</section>
<section>
- <title>Initializing the erl_interface Library</title>
- <p>Before calling any of the other Erl_Interface functions, you
- must call <c><![CDATA[erl_init()]]></c> exactly once to initialize the library.
- <c><![CDATA[erl_init()]]></c> takes two arguments, however the arguments are no
- longer used by Erl_Interface, and should therefore be specified
- as <c><![CDATA[erl_init(NULL,0)]]></c>.</p>
+ <title>Initializing the Erl_Interface Library</title>
+ <p>Before calling any of the other <c>Erl_Interface</c> functions, call
+ <c>erl_init()</c> exactly once to initialize the library.
+ <c>erl_init()</c> takes two arguments. However, the arguments
+ are no longer used by <c>Erl_Interface</c> and are therefore to be
+ specified as <c>erl_init(NULL,0)</c>.</p>
</section>
<section>
- <title>Encoding, Decoding and Sending Erlang Terms</title>
+ <title>Encoding, Decoding, and Sending Erlang Terms</title>
<p>Data sent between distributed Erlang nodes is encoded in the
- Erlang external format. Consequently, you have to encode and decode
+ Erlang external format. You must therefore encode and decode
Erlang terms into byte streams if you want to use the distribution
- protocol to communicate between a C program and Erlang. </p>
- <p>The Erl_Interface library supports this activity. It has a
- number of C functions which create and manipulate Erlang data
+ protocol to communicate between a C program and Erlang.</p>
+
+ <p>The <c>Erl_Interface</c> library supports this activity. It has
+ several C functions that create and manipulate Erlang data
structures. The library also contains an encode and a decode function.
- The example below shows how to create and encode an Erlang tuple
- <c><![CDATA[{tobbe,3928}]]></c>:</p>
- <code type="none"><![CDATA[
+ The following example shows how to create and encode an Erlang tuple
+ <c>{tobbe,3928}</c>:</p>
+ <code type="none"><![CDATA[
ETERM *arr[2], *tuple;
char buf[BUFSIZ];
int i;
@@ -134,58 +192,70 @@ arr[0] = erl_mk_atom("tobbe");
arr[1] = erl_mk_integer(3928);
tuple = erl_mk_tuple(arr, 2);
i = erl_encode(tuple, buf); ]]></code>
- <p>Alternatively, you can use <c><![CDATA[erl_send()]]></c> and
- <c><![CDATA[erl_receive_msg]]></c>, which handle the encoding and decoding of
- messages transparently.</p>
- <p>Refer to the Reference Manual for a complete description of the
- following modules:</p>
+
+ <p>Alternatively, you can use <c>erl_send()</c> and
+ <c>erl_receive_msg</c>, which handle the encoding and
+ decoding of messages transparently.</p>
+
+ <p>For a complete description, see the following modules:</p>
<list type="bulleted">
- <item>the <c><![CDATA[erl_eterm]]></c> module for creating Erlang terms</item>
- <item>the <c><![CDATA[erl_marshal]]></c> module for encoding and decoding routines.</item>
+ <item><seealso marker="erl_eterm"><c>erl_eterm</c></seealso>
+ for creating Erlang terms</item>
+ <item><seealso marker="erl_marshal"><c>erl_marshal</c></seealso>
+ for encoding and decoding routines</item>
</list>
</section>
<section>
+ <marker id="building_terms_and_patterns"/>
<title>Building Terms and Patterns</title>
- <p>The previous example can be simplified by using
- <c><![CDATA[erl_format()]]></c> to create an Erlang term.</p>
- <code type="none"><![CDATA[
+ <p>The previous example can be simplified by using the
+ <seealso marker="erl_format"><c>erl_format</c></seealso> module
+ to create an Erlang term:</p>
+ <code type="none"><![CDATA[
ETERM *ep;
ep = erl_format("{~a,~i}", "tobbe", 3928); ]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_format]]></c> module, for a
- full description of the different format directives. The following
- example is more complex:</p>
- <code type="none"><![CDATA[
+ <p>For a complete description of the different format directives, see
+ the <seealso marker="erl_format"><c>erl_format</c></seealso> module.</p>
+
+ <p>The following example is more complex:</p>
+
+ <code type="none"><![CDATA[
ETERM *ep;
ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
"madonna",
21,
erl_format("[{adr,~s,~i}]", "E-street", 42));
erl_free_compound(ep); ]]></code>
- <p>As in previous examples, it is your responsibility to free the
- memory allocated for Erlang terms. In this example,
- <c><![CDATA[erl_free_compound()]]></c> ensures that the complete term pointed to
- by <c><![CDATA[ep]]></c> is released. This is necessary, because the pointer from
- the second call to <c><![CDATA[erl_format()]]></c> is lost. </p>
- <p>The following
- example shows a slightly different solution:</p>
- <code type="none"><![CDATA[
+ <p>As in the previous examples, it is your responsibility to free the
+ memory allocated for Erlang terms. In this example,
+ <c>erl_free_compound()</c> ensures that the complete term
+ pointed to by <c>ep</c> is released. This is necessary
+ because the pointer from the second call to <c>erl_format</c> is lost.</p>
+
+ <p>The following example shows a slightly different solution:</p>
+
+ <code type="none"><![CDATA[
ETERM *ep,*ep2;
ep2 = erl_format("[{adr,~s,~i}]","E-street",42);
ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
"madonna", 21, ep2);
erl_free_term(ep);
erl_free_term(ep2); ]]></code>
+
<p>In this case, you free the two terms independently. The order in
- which you free the terms <c><![CDATA[ep]]></c> and <c><![CDATA[ep2]]></c> is not important,
- because the Erl_Interface library uses reference counting to
- determine when it is safe to actually remove objects. </p>
- <p>If you are not sure whether you have freed the terms properly, you
+ which you free the terms <c>ep</c> and <c>ep2</c>
+ is not important,
+ because the <c>Erl_Interface</c> library uses reference counting to
+ determine when it is safe to remove objects.</p>
+
+ <p>If you are unsure whether you have freed the terms properly, you
can use the following function to see the status of the fixed term
allocator:</p>
+
<code type="none"><![CDATA[
long allocated, freed;
@@ -196,36 +266,49 @@ printf("length of freelist: %ld\n",freed);
/* really free the freelist */
erl_eterm_release();
]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_malloc]]></c> module for more
- information.</p>
+
+ <p>For more information, see the
+ <seealso marker="erl_malloc"><c>erl_malloc</c></seealso> module.</p>
</section>
<section>
<title>Pattern Matching</title>
- <p>An Erlang pattern is a term that may contain unbound variables or
- <c><![CDATA["do not care"]]></c> symbols. Such a pattern can be matched against a
+ <p>An Erlang pattern is a term that can contain unbound variables or
+ <c>"do not care"</c> symbols. Such a pattern can be matched
+ against a
term and, if the match is successful, any unbound variables in the
pattern will be bound as a side effect. The content of a bound
- variable can then be retrieved.</p>
- <code type="none"><![CDATA[
+ variable can then be retrieved:</p>
+ <code type="none"><![CDATA[
ETERM *pattern;
pattern = erl_format("{madonna,Age,_}"); ]]></code>
- <p><c><![CDATA[erl_match()]]></c> is used to perform pattern matching. It takes a
+
+ <p>The <seealso marker="erl_format#erl_match">
+ <c>erl_format:erl_match</c></seealso> function
+ performs pattern matching. It takes a
pattern and a term and tries to match them. As a side effect any unbound
- variables in the pattern will be bound. In the following example, we
- create a pattern with a variable <em>Age</em> which appears at two
+ variables in the pattern will be bound. In the following example, a
+ pattern is created with a variable <c>Age</c>, which is included at two
positions in the tuple. The pattern match is performed as follows:</p>
- <list type="ordered">
- <item><c><![CDATA[erl_match()]]></c> will bind the contents of
- <em>Age</em> to <em>21</em> the first time it reaches the variable</item>
- <item>the second occurrence of <em>Age</em> will cause a test for
- equality between the terms since <em>Age</em> is already bound to
- <em>21</em>. Since <em>Age</em> is bound to 21, the equality test will
- succeed and the match continues until the end of the pattern.</item>
- <item>if the end of the pattern is reached, the match succeeds and you
- can retrieve the contents of the variable</item>
+
+ <list type="bulleted">
+ <item>
+ <p><c>erl_match</c> binds the contents of <c>Age</c> to <c>21</c>
+ the first time it reaches the variable.</p>
+ </item>
+ <item>
+ <p>The second occurrence of <c>Age</c> causes a test for
+ equality between the terms, as <c>Age</c> is already bound to
+ <c>21</c>. As <c>Age</c> is bound to <c>21</c>, the equality test
+ succeeds and the match continues until the end of the pattern.</p>
+ </item>
+ <item>
+ <p>If the end of the pattern is reached, the match succeeds and you
+ can retrieve the contents of the variable.</p>
+ </item>
</list>
+
<code type="none"><![CDATA[
ETERM *pattern,*term;
pattern = erl_format("{madonna,Age,Age}");
@@ -239,99 +322,136 @@ if (erl_match(pattern, term)) {
}
erl_free_term(pattern);
erl_free_term(term); ]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_match()]]></c> function for
- more information.</p>
+
+ <p>For more information, see the
+ <seealso marker="erl_format#erl_match">
+ <c>erl_format:erl_match</c></seealso> function.</p>
</section>
<section>
<title>Connecting to a Distributed Erlang Node</title>
- <p>In order to connect to a distributed Erlang node you need to first
- initialize the connection routine with <c><![CDATA[erl_connect_init()]]></c>,
- which stores information such as the host name, node name, and IP
+ <p>To connect to a distributed Erlang node, you must first
+ initialize the connection routine with
+ <seealso marker="erl_connect#erl_connect_init">
+ <c>erl_connect:erl_connect_init</c></seealso>,
+ which stores information, such as the hostname, node name, and IP
address for later use:</p>
+
<code type="none"><![CDATA[
int identification_number = 99;
int creation=1;
char *cookie="a secret cookie string"; /* An example */
erl_connect_init(identification_number, cookie, creation); ]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information.</p>
+
+ <p>For more information, see the
+ <seealso marker="erl_connect"><c>erl_connect</c></seealso> module.</p>
+
<p>After initialization, you set up the connection to the Erlang node.
- Use <c><![CDATA[erl_connect()]]></c> to specify the Erlang node you want to
- connect to. The following example sets up the connection and should
- result in a valid socket file descriptor:</p>
+ To specify the Erlang node you want to connect to, use
+ <c>erl_connect()</c>. The following example sets up the
+ connection and is to result in a valid socket file descriptor:</p>
+
<code type="none"><![CDATA[
int sockfd;
char *nodename="[email protected]"; /* An example */
if ((sockfd = erl_connect(nodename)) < 0)
erl_err_quit("ERROR: erl_connect failed"); ]]></code>
- <p><c><![CDATA[erl_err_quit()]]></c> prints the specified string and terminates
- the program. Refer to the Reference Manual, the <c><![CDATA[erl_error()]]></c>
- function for more information.</p>
+
+ <p><c>erl_err_quit()</c> prints the specified string and
+ terminates the program. For more information, see the
+ <seealso marker="erl_error"><c>erl_error</c></seealso> module.</p>
</section>
<section>
<title>Using EPMD</title>
- <p><c><![CDATA[Epmd]]></c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes
- register with <c><![CDATA[epmd]]></c> on the localhost to indicate to other nodes that
- they exist and can accept connections. <c><![CDATA[Epmd]]></c> maintains a register of
+ <p><seealso marker="erts:epmd"><c>erts:epmd</c></seealso>
+ is the Erlang Port Mapper Daemon. Distributed
+ Erlang nodes register with <c>epmd</c> on the local host to
+ indicate to other nodes that they exist and can accept connections.
+ <c>epmd</c> maintains a register of
node and port number information, and when a node wishes to connect to
- another node, it first contacts <c><![CDATA[epmd]]></c> in order to find out the correct
- port number to connect to.</p>
- <p>When you use <c><![CDATA[erl_connect()]]></c> to connect to an Erlang node, a
- connection is first made to <c><![CDATA[epmd]]></c> and, if the node is known, a
+ another node, it first contacts <c>epmd</c> to find the
+ correct port number to connect to.</p>
+
+ <p>When you use
+ <seealso marker="erl_connect"><c>erl_connect</c></seealso>
+ to connect to an Erlang node, a connection is first made to
+ <c>epmd</c> and, if the node is known, a
connection is then made to the Erlang node.</p>
- <p>C nodes can also register themselves with <c><![CDATA[epmd]]></c> if they want other
+
+ <p>C nodes can also register themselves with <c>epmd</c>
+ if they want other
nodes in the system to be able to find and connect to them.</p>
- <p>Before registering with <c><![CDATA[epmd]]></c>, you need to first create a listen socket
- and bind it to a port. Then:</p>
+
+ <p>Before registering with <c>epmd</c>, you must first
+ create a listen socket and bind it to a port. Then:</p>
+
<code type="none"><![CDATA[
int pub;
pub = erl_publish(port); ]]></code>
- <p><c><![CDATA[pub]]></c> is a file descriptor now connected to <c><![CDATA[epmd]]></c>. <c><![CDATA[Epmd]]></c>
- monitors the other end of the connection, and if it detects that the
- connection has been closed, the node will be unregistered. So, if you
- explicitly close the descriptor or if your node fails, it will be
- unregistered from <c><![CDATA[epmd]]></c>.</p>
- <p>Be aware that on some systems (such as VxWorks), a failed node will
- not be detected by this mechanism since the operating system does not
+
+ <p><c>pub</c> is a file descriptor now connected to
+ <c>epmd</c>. <c>epmd</c>
+ monitors the other end of the connection. If it detects that the
+ connection has been closed, the node becomes unregistered. So, if you
+ explicitly close the descriptor or if your node fails, it becomes
+ unregistered from <c>epmd</c>.</p>
+
+ <p>Notice that on some systems (such as VxWorks), a failed node is
+ not detected by this mechanism, as the operating system does not
automatically close descriptors that were left open when the node
- failed. If a node has failed in this way, <c><![CDATA[epmd]]></c> will prevent you from
- registering a new node with the old name, since it thinks that the old
+ failed. If a node has failed in this way, <c>epmd</c>
+ prevents you from
+ registering a new node with the old name, as it thinks that the old
name is still in use. In this case, you must unregister the name
explicitly:</p>
+
<code type="none"><![CDATA[
erl_unpublish(node); ]]></code>
- <p>This will cause <c><![CDATA[epmd]]></c> to close the connection from the far end. Note
+
+ <p>This causes <c>epmd</c> to close the connection from the
+ far end. Notice
that if the name was in fact still in use by a node, the results of
this operation are unpredictable. Also, doing this does not cause the
- local end of the connection to close, so resources may be consumed.</p>
+ local end of the connection to close, so resources can be consumed.</p>
</section>
<section>
<title>Sending and Receiving Erlang Messages</title>
<p>Use one of the following two functions to send messages:</p>
+
<list type="bulleted">
- <item><c><![CDATA[erl_send()]]></c></item>
- <item><c><![CDATA[erl_reg_send()]]></c></item>
+ <item><seealso marker="erl_connect#erl_send">
+ <c>erl_connect:erl_send</c></seealso></item>
+ <item><seealso marker="erl_connect#erl_reg_send">
+ <c>erl_connect:erl_reg_send</c></seealso></item>
</list>
- <p>As in Erlang, it is possible to send messages to a
- <em>Pid</em> or to a registered name. It is easier to send a
- message to a registered name because it avoids the problem of finding
- a suitable <em>Pid</em>.</p>
+
+ <p>As in Erlang, messages can be sent to a
+ pid or to a registered name. It is easier to send a
+ message to a registered name, as it avoids the problem of finding
+ a suitable pid.</p>
+
<p>Use one of the following two functions to receive messages:</p>
+
<list type="bulleted">
- <item><c><![CDATA[erl_receive()]]></c></item>
- <item><c><![CDATA[erl_receive_msg()]]></c></item>
+ <item><seealso marker="erl_connect#erl_receive">
+ <c>erl_connect:erl_receive</c></seealso></item>
+ <item><seealso marker="erl_connect#erl_receive_msg">
+ <c>erl_connect:erl_receive_msg</c></seealso></item>
</list>
- <p><c><![CDATA[erl_receive()]]></c> receives the message into a buffer, while
- <c><![CDATA[erl_receive_msg()]]></c> decodes the message into an Erlang term. </p>
+
+ <p><c>erl_receive()</c> receives the message into a buffer,
+ while <c>erl_receive_msg()</c> decodes the message into an
+ Erlang term.</p>
<section>
<title>Example of Sending Messages</title>
- <p>In the following example, <c><![CDATA[{Pid, hello_world}]]></c> is
- sent to a registered process <c><![CDATA[my_server]]></c>. The message is encoded
- by <c><![CDATA[erl_send()]]></c>:</p>
+ <p>In the following example, <c>{Pid, hello_world}</c> is
+ sent to a registered process <c>my_server</c>. The message
+ is encoded by <c>erl_send()</c>:</p>
+
<code type="none"><![CDATA[
extern const char *erl_thisnodename(void);
extern short erl_thiscreation(void);
@@ -345,16 +465,19 @@ emsg = erl_mk_tuple(arr, 2);
erl_reg_send(sockfd, "my_server", emsg);
erl_free_term(emsg); ]]></code>
+
<p>The first element of the tuple that is sent is your own
- <em>Pid</em>. This enables <c><![CDATA[my_server]]></c> to reply. Refer to the
- Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information
- about send primitives.</p>
+ pid. This enables <c>my_server</c> to reply.
+ For more information about the primitives, see the
+ <seealso marker="erl_connect"><c>erl_connect</c></seealso> module.</p>
</section>
<section>
<title>Example of Receiving Messages</title>
- <p>In this example <c><![CDATA[{Pid, Something}]]></c> is received. The
- received Pid is then used to return <c><![CDATA[{goodbye,Pid}]]></c></p>
+ <p>In this example, <c>{Pid, Something}</c> is received. The
+ received pid is then used to return
+ <c>{goodbye,Pid}</c>.</p>
+
<code type="none"><![CDATA[
ETERM *arr[2], *answer;
int sockfd,rc;
@@ -370,22 +493,25 @@ if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) {
erl_free_term(emsg.msg);
erl_free_term(emsg.to);
} ]]></code>
- <p>In order to provide robustness, a distributed Erlang node
- occasionally polls all its connected neighbours in an attempt to
- detect failed nodes or communication links. A node which receives such
- a message is expected to respond immediately with an <c><![CDATA[ERL_TICK]]></c> message.
- This is done automatically by <c><![CDATA[erl_receive()]]></c>, however when this
- has occurred <c><![CDATA[erl_receive]]></c> returns <c><![CDATA[ERL_TICK]]></c> to the caller
- without storing a message into the <c><![CDATA[ErlMessage]]></c> structure.</p>
+
+ <p>To provide robustness, a distributed Erlang node
+ occasionally polls all its connected neighbors in an attempt to
+ detect failed nodes or communication links. A node that receives such
+ a message is expected to respond immediately with an
+ <c>ERL_TICK</c> message. This is done automatically by
+ <c>erl_receive()</c>. However, when this has occurred,
+ <c>erl_receive</c> returns <c>ERL_TICK</c> to
+ the caller without storing a message into the
+ <c>ErlMessage</c> structure.</p>
+
<p>When a message has been received, it is the caller's responsibility
- to free the received message <c><![CDATA[emsg.msg]]></c> as well as <c><![CDATA[emsg.to]]></c>
- or <c><![CDATA[emsg.from]]></c>, depending on the type of message received.</p>
- <p>Refer to the Reference Manual for additional information about the
- following modules:</p>
- <list type="bulleted">
- <item><c><![CDATA[erl_connect]]></c></item>
- <item><c><![CDATA[erl_eterm]]></c>.</item>
- </list>
+ to free the received message <c>emsg.msg</c> and
+ <c>emsg.to</c> or <c>emsg.from</c>,
+ depending on the type of message received.</p>
+
+ <p>For more information, see the
+ <seealso marker="erl_connect"><c>erl_connect</c></seealso> and
+ <seealso marker="erl_eterm"><c>erl_eterm</c></seealso> modules.</p>
</section>
</section>
@@ -394,10 +520,12 @@ if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) {
<p>An Erlang node acting as a client to another Erlang node
typically sends a request and waits for a reply. Such a request is
included in a function call at a remote node and is called a remote
- procedure call. The following example shows how the
- Erl_Interface library supports remote procedure calls:</p>
- <code type="none"><![CDATA[
+ procedure call.</p>
+ <p>The following example shows how the
+ <c>Erl_Interface</c> library supports remote procedure calls:</p>
+
+ <code type="none"><![CDATA[
char modname[]=THE_MODNAME;
ETERM *reply,*ep;
ep = erl_format("[~a,[]]", modname);
@@ -409,26 +537,34 @@ if (!erl_match(ep, reply))
erl_err_msg("<ERROR> compiler errors !\n");
erl_free_term(ep);
erl_free_term(reply); ]]></code>
- <p><c><![CDATA[c:c/1]]></c> is called to compile the specified module on the
- remote node. <c><![CDATA[erl_match()]]></c> checks that the compilation was
- successful by testing for the expected <c><![CDATA[ok]]></c>.</p>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for
- more information about <c><![CDATA[erl_rpc()]]></c>, and its companions
- <c><![CDATA[erl_rpc_to()]]></c> and <c><![CDATA[erl_rpc_from()]]></c>.</p>
+
+ <p><c>c:c/1</c> is called to compile the specified module on
+ the remote node. <c>erl_match()</c> checks that the
+ compilation was
+ successful by testing for the expected <c>ok</c>.</p>
+
+ <p>For more information about <c>erl_rpc()</c> and its
+ companions <c>erl_rpc_to()</c> and
+ <c>erl_rpc_from()</c>, see the
+ <seealso marker="erl_connect"><c>erl_connect</c></seealso> module.</p>
</section>
<section>
<title>Using Global Names</title>
- <p>A C node has access to names registered through the Erlang Global
- module. Names can be looked up, allowing the C node to send messages
+ <p>A C node has access to names registered through the
+ <seealso marker="kernel:global"><c>global</c></seealso>
+ module in Kernel. Names can be looked up, allowing the C node to send messages
to named Erlang services. C nodes can also register global names,
allowing them to provide named services to Erlang processes or other C
- nodes. </p>
- <p>Erl_Interface does not provide a native implementation of the global
- service. Instead it uses the global services provided by a "nearby"
- Erlang node. In order to use the services described in this section,
+ nodes.</p>
+
+ <p><c>Erl_Interface</c> does not provide a native implementation of the
+ global service. Instead it uses the global services provided by a "nearby"
+ Erlang node. To use the services described in this section,
it is necessary to first open a connection to an Erlang node.</p>
+
<p>To see what names there are:</p>
+
<code type="none"><![CDATA[
char **names;
int count;
@@ -441,71 +577,102 @@ if (names)
printf("%s\n",names[i]);
free(names); ]]></code>
- <p><c><![CDATA[erl_global_names()]]></c> allocates and returns a buffer containing
- all the names known to global. <c><![CDATA[count]]></c> will be initialized to
- indicate how many names are in the array. The array of strings in
- names is terminated by a NULL pointer, so it is not necessary to use
- <c><![CDATA[count]]></c> to determine when the last name is reached.</p>
+
+ <p><seealso marker="erl_global#erl_global_names">
+ <c>erl_global:erl_global_names</c></seealso>
+ allocates and returns a buffer containing
+ all the names known to the <c>global</c> module in <c>Kernel</c>.
+ <c>count</c> is initialized to
+ indicate the number of names in the array. The array of strings in names
+ is terminated by a <c>NULL</c> pointer, so it is not necessary to use
+ <c>count</c> to determine when the last name is reached.</p>
+
<p>It is the caller's responsibility to free the array.
- <c><![CDATA[erl_global_names()]]></c> allocates the array and all of the strings
- using a single call to <c><![CDATA[malloc()]]></c>, so <c><![CDATA[free(names)]]></c> is all
- that is necessary.</p>
+ <c>erl_global_names</c> allocates the array and all the strings
+ using a single call to <c>malloc()</c>, so
+ <c>free(names)</c> is all that is necessary.</p>
+
<p>To look up one of the names:</p>
+
<code type="none"><![CDATA[
ETERM *pid;
char node[256];
pid = erl_global_whereis(fd,"schedule",node); ]]></code>
- <p>If <c><![CDATA["schedule"]]></c> is known to global, an Erlang pid is returned
- that can be used to send messages to the schedule service.
- Additionally, <c><![CDATA[node]]></c> will be initialized to contain the name of
+
+ <p>If <c>"schedule"</c> is known to the
+ <c>global</c> module in <c>Kernel</c>, an Erlang pid is
+ returned that can be used to send messages to the schedule service.
+ Also, <c>node</c> is initialized to contain the name of
the node where the service is registered, so that you can make a
- connection to it by simply passing the variable to <c><![CDATA[erl_connect()]]></c>.</p>
+ connection to it by simply passing the variable to
+ <seealso marker="erl_connect"><c>erl_connect</c></seealso>.</p>
+
<p>Before registering a name, you should already have registered your
- port number with <c><![CDATA[epmd]]></c>. This is not strictly necessary, but if you
+ port number with <c>epmd</c>. This is not strictly necessary,
+ but if you
neglect to do so, then other nodes wishing to communicate with your
- service will be unable to find or connect to your process.</p>
+ service cannot find or connect to your process.</p>
+
<p>Create a pid that Erlang processes can use to communicate with your
service:</p>
+
<code type="none"><![CDATA[
ETERM *pid;
pid = erl_mk_pid(thisnode,14,0,0);
erl_global_register(fd,servicename,pid); ]]></code>
- <p>After registering the name, you should use <c><![CDATA[erl_accept()]]></c> to wait for
- incoming connections.</p>
- <p>Do not forget to free <c><![CDATA[pid]]></c> later with <c><![CDATA[erl_free_term()]]></c>!</p>
+
+ <p>After registering the name, use
+ <seealso marker="erl_connect#erl_accept">
+ <c>erl_connect:erl_accept</c></seealso>
+ to wait for incoming connections.</p>
+
+ <note>
+ <p>Remember to free <c>pid</c> later with
+ <seealso marker="erl_malloc#erl_free_term">
+ <c>erl_malloc:erl_free_term</c></seealso>.</p>
+ </note>
+
<p>To unregister a name:</p>
+
<code type="none"><![CDATA[
erl_global_unregister(fd,servicename); ]]></code>
</section>
<section>
- <title>The Registry</title>
+ <title>Using the Registry</title>
<p>This section describes the use of the registry, a simple mechanism
for storing key-value pairs in a C-node, as well as backing them up or
- restoring them from a Mnesia table on an Erlang node. More detailed
- information about the individual API functions can be found in the
- Reference Manual.</p>
- <p>Keys are strings, i.e. 0-terminated arrays of characters, and values
- are arbitrary objects. Although integers and floating point numbers
+ restoring them from an <c>Mnesia</c> table on an Erlang node. For more
+ detailed information about the individual API functions, see the
+ <seealso marker="registry"><c>registry</c></seealso> module.</p>
+
+ <p>Keys are strings, that is, <c>NULL</c>-terminated arrays of characters, and
+ values are arbitrary objects. Although integers and floating point numbers
are treated specially by the registry, you can store strings or binary
objects of any type as pointers.</p>
- <p>To start, you need to open a registry:</p>
+
+ <p>To start, open a registry:</p>
+
<code type="none"><![CDATA[
ei_reg *reg;
reg = ei_reg_open(45); ]]></code>
- <p>The number 45 in the example indicates the approximate number of
+
+ <p>The number <c>45</c> in the example indicates the approximate number of
objects that you expect to store in the registry. Internally the
registry uses hash tables with collision chaining, so there is no
absolute upper limit on the number of objects that the registry can
- contain, but if performance or memory usage are important, then you
- should choose a number accordingly. The registry can be resized later.</p>
+ contain, but if performance or memory usage is important, then you
+ are to choose a number accordingly. The registry can be resized later.</p>
+
<p>You can open as many registries as you like (if memory permits).</p>
- <p>Objects are stored and retrieved through set and get functions. In
- the following examples you see how to store integers, floats, strings
+
+ <p>Objects are stored and retrieved through set and get functions.
+ The following example shows how to store integers, floats, strings,
and arbitrary binary objects:</p>
+
<code type="none"><![CDATA[
struct bonk *b = malloc(sizeof(*b));
char *name = malloc(7);
@@ -519,13 +686,16 @@ ei_reg_setsval(reg,"name",name);
b->l = 42;
b->m = 12;
ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]></code>
- <p>If you attempt to store an object in the registry and there is an
- existing object with the same key, the new value will replace the old
+
+ <p>If you try to store an object in the registry and there is an
+ existing object with the same key, the new value replaces the old
one. This is done regardless of whether the new object and the old one
have the same type, so you can, for example, replace a string with an
- integer. If the existing value is a string or binary, it will be freed
+ integer. If the existing value is a string or binary, it is freed
before the new value is assigned.</p>
+
<p>Stored values are retrieved from the registry as follows:</p>
+
<code type="none"><![CDATA[
long i;
double f;
@@ -537,77 +707,100 @@ i = ei_reg_getival(reg,"age");
f = ei_reg_getfval(reg,"height");
s = ei_reg_getsval(reg,"name");
b = ei_reg_getpval(reg,"jox",&size); ]]></code>
- <p>In all of the above examples, the object must exist and it must be of
+
+ <p>In all the above examples, the object must exist and it must be of
the right type for the specified operation. If you do not know the
- type of a given object, you can ask:</p>
+ type of an object, you can ask:</p>
+
<code type="none"><![CDATA[
struct ei_reg_stat buf;
ei_reg_stat(reg,"name",&buf); ]]></code>
- <p>Buf will be initialized to contain object attributes.</p>
+
+ <p>Buf is initialized to contain object attributes.</p>
+
<p>Objects can be removed from the registry:</p>
+
<code type="none"><![CDATA[
ei_reg_delete(reg,"name"); ]]></code>
+
<p>When you are finished with a registry, close it to remove all the
objects and free the memory back to the system:</p>
+
<code type="none"><![CDATA[
ei_reg_close(reg); ]]></code>
<section>
<title>Backing Up the Registry to Mnesia</title>
- <p>The contents of a registry can be backed up to Mnesia on a "nearby"
- Erlang node. You need to provide an open connection to the Erlang node
- (see <c><![CDATA[erl_connect()]]></c>). Also, Mnesia 3.0 or later must be running
+ <p>The contents of a registry can be backed up to
+ <seealso marker="mnesia:mnesia"><c>Mnesia</c></seealso> on a "nearby" Erlang
+ node. You must provide an open connection to the Erlang node
+ (see <seealso marker="erl_connect"><c>erl_connect</c></seealso>).
+ Also, <c>Mnesia</c> 3.0 or later must be running
on the Erlang node before the backup is initiated:</p>
+
<code type="none"><![CDATA[
ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code>
- <p>The example above will backup the contents of the registry to the
- specified Mnesia table <c><![CDATA["mtab"]]></c>. Once a registry has been backed
- up to Mnesia in this manner, additional backups will only affect
- objects that have been modified since the most recent backup, i.e.
- objects that have been created, changed or deleted. The backup
- operation is done as a single atomic transaction, so that the entire
- backup will be performed or none of it will.</p>
- <p>In the same manner, a registry can be restored from a Mnesia table:</p>
+
+ <p>This example back up the contents of the registry to the
+ specified <c>Mnesia</c> table <c>"mtab"</c>.
+ Once a registry has been backed
+ up to <c>Mnesia</c> like this, more backups only affect
+ objects that have been modified since the most recent backup, that is,
+ objects that have been created, changed, or deleted. The backup
+ operation is done as a single atomic transaction, so that either the
+ entire backup is performed or none of it.</p>
+
+ <p>Likewise, a registry can be restored from a <c>Mnesia</c> table:</p>
+
<code type="none"><![CDATA[
ei_reg_restore(fd, reg, "mtab"); ]]></code>
- <p>This will read the entire contents of <c><![CDATA["mtab"]]></c> into the specified
- registry. After the restore, all of the objects in the registry will
- be marked as unmodified, so a subsequent backup will only affect
+
+ <p>This reads the entire contents of <c>"mtab"</c> into the
+ specified registry. After the restore, all the objects in the registry
+ are marked as unmodified, so a later backup only affects
objects that you have modified since the restore.</p>
- <p>Note that if you restore to a non-empty registry, objects in the
- table will overwrite objects in the registry with the same keys. Also,
+
+ <p>Notice that if you restore to a non-empty registry, objects in the
+ table overwrite objects in the registry with the same keys. Also,
the <em>entire</em> contents of the registry is marked as unmodified
after the restore, including any modified objects that were not
- overwritten by the restore operation. This may not be your intention.</p>
+ overwritten by the restore operation. This may not be your
+ intention.</p>
</section>
<section>
<title>Storing Strings and Binaries</title>
<p>When string or binary objects are stored in the registry it is
- important that a number of simple guidelines are followed. </p>
+ important that some simple guidelines are followed.</p>
+
<p>Most importantly, the object must have been created with a single call
- to <c><![CDATA[malloc()]]></c> (or similar), so that it can later be removed by a
- single call to <c><![CDATA[free()]]></c>. Objects will be freed by the registry
+ to <c>malloc()</c> (or similar), so that it can later be
+ removed by a single call to <c>free()</c>.
+ Objects are freed by the registry
when it is closed, or when you assign a new value to an object that
previously contained a string or binary.</p>
- <p>You should also be aware that if you store binary objects that are
- context-dependent (e.g. containing pointers or open file descriptors),
- they will lose their meaning if they are backed up to a Mnesia table
- and subsequently restored in a different context.</p>
+
+ <p>Notice that if you store binary objects that are context-dependent
+ (for example, containing pointers or open file descriptors),
+ they lose their meaning if they are backed up to a <c>Mnesia</c> table
+ and later restored in a different context.</p>
+
<p>When you retrieve a stored string or binary value from the registry,
the registry maintains a pointer to the object and you are passed a
copy of that pointer. You should never free an object retrieved in
this manner because when the registry later attempts to free it, a
- runtime error will occur that will likely cause the C-node to crash.</p>
+ runtime error occurs that likely causes the C-node to crash.</p>
+
<p>You are free to modify the contents of an object retrieved this way.
- However when you do so, the registry will not be aware of the changes
- you make, possibly causing it to be missed the next time you make a
- Mnesia backup of the registry contents. This can be avoided if you
- mark the object as dirty after any such changes with
- <c><![CDATA[ei_reg_markdirty()]]></c>, or pass appropriate flags to
- <c><![CDATA[ei_reg_dump()]]></c>.</p>
+ However, when you do so, the registry is not aware of your changes,
+ possibly causing it to be missed the next time you make an
+ <c>Mnesia</c> backup of the registry contents. This can be avoided if
+ you mark the object as dirty after any such changes with
+ <seealso marker="registry#ei_reg_markdirty">
+ <c>registry:ei_reg_markdirty</c></seealso>, or pass appropriate flags to
+ <seealso marker="registry#ei_reg_dump">
+ <c>registry:ei_reg_dump</c></seealso>.</p>
</section>
</section>
</chapter>
-
diff --git a/lib/erl_interface/doc/src/erl_call.xml b/lib/erl_interface/doc/src/erl_call.xml
index 46015621ac..73b9b13e4d 100644
--- a/lib/erl_interface/doc/src/erl_call.xml
+++ b/lib/erl_interface/doc/src/erl_call.xml
@@ -4,14 +4,14 @@
<comref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -28,135 +28,146 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>97-05-16</date>
+ <date>1997-05-16</date>
<rev>B</rev>
- <file>erl_call.sgml</file>
+ <file>erl_call.xml</file>
</header>
<com>erl_call</com>
- <comsummary>Call/Start a Distributed Erlang Node</comsummary>
+ <comsummary>Call/start a distributed Erlang node.</comsummary>
<description>
- <p><c><![CDATA[erl_call]]></c> makes it possible to start and/or communicate with
- a distributed Erlang node. It is built upon the <c><![CDATA[erl_interface]]></c>
- library as an example application. Its purpose is to use an Unix shell script to interact with a distributed Erlang node. It performs all
- communication with the Erlang <em>rex server</em>, using the standard Erlang RPC facility. It does not require any special
- software to be run at the Erlang target node.</p>
+ <p><c>erl_call</c> makes it possible to start and/or
+ communicate with a distributed Erlang node. It is built upon the
+ <c>Erl_Interface</c> library as an example application.
+ Its purpose is to use a Unix shell script to interact with a distributed
+ Erlang node. It performs all communication with the Erlang
+ <em>rex server</em>, using the standard Erlang RPC facility. It does not
+ require any special software to be run at the Erlang target node.</p>
+
<p>The main use is to either start a distributed Erlang node
or to make an ordinary function call. However, it is also
- possible to pipe an Erlang module to <c><![CDATA[erl_call]]></c> and have it
- compiled, or to pipe a sequence of Erlang expressions to be evaluated
+ possible to pipe an Erlang module to <c>erl_call</c> and have
+ it compiled, or to pipe a sequence of Erlang expressions to be evaluated
(similar to the Erlang shell).</p>
- <p>Options, which cause <c><![CDATA[stdin]]></c> to be read, can be used with
- advantage
- as scripts from within (Unix) shell scripts. Another
- nice use of <c><![CDATA[erl_call]]></c> could be from (http) CGI-bin scripts.</p>
+
+ <p>Options, which cause <c>stdin</c> to be read, can be used
+ with advantage,
+ as scripts from within (Unix) shell scripts. Another nice use
+ of <c>erl_call</c> could be from (HTTP) CGI-bin scripts.</p>
</description>
+
<funcs>
<func>
<name>erl_call &lt;options></name>
- <fsummary>Start/Call Erlang</fsummary>
+ <fsummary>Start/call Erlang.</fsummary>
<desc>
- <p>Each option flag is described below with its name, type and
- meaning. </p>
+ <p>Starts/calls Erlang.</p>
+ <p>Each option flag is described below with its name, type, and
+ meaning.</p>
<taglist>
- <tag>-a [Mod [Fun [Args]]]]</tag>
+ <tag><c>-a [Mod [Fun [Args]]]]</c></tag>
<item>
- <p>(<em>optional</em>): Applies the specified function
- and returns the result. <c><![CDATA[Mod]]></c> must be specified, however
- <c>start</c> and <c>[]</c> are assumed for unspecified <c><![CDATA[Fun]]></c> and <c><![CDATA[Args]]></c>, respectively. <c><![CDATA[Args]]></c> should
- be in the same format as for <c><![CDATA[erlang:apply/3]]></c>. Note
- that this flag takes exactly one argument, so quoting
- may be necessary in order to group <c><![CDATA[Mod]]></c>, <c><![CDATA[Fun]]></c>
- and <c><![CDATA[Args]]></c>, in a manner dependent on the behavior
- of your command shell.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Applies the specified function
+ and returns the result. <c>Mod</c> must be specified.
+ However, <c>start</c> and <c>[]</c> are assumed for unspecified
+ <c>Fun</c> and <c>Args</c>, respectively.
+ <c>Args</c> is to be in the same format as for
+ <seealso marker="erts:erlang#apply/3">
+ <c>erlang:apply/3</c></seealso> in <c>ERTS</c>.</p>
+ <p>Notice that this flag takes exactly one argument, so quoting
+ can be necessary to group <c>Mod</c>,
+ <c>Fun</c>, and <c>Args</c> in a manner
+ dependent on the behavior of your command shell.</p>
</item>
- <tag>-c Cookie</tag>
+ <tag><c>-c Cookie</c></tag>
<item>
- <p>(<em>optional</em>): Use this option to specify a certain cookie. If no cookie is specified, the <c><![CDATA[~/.erlang.cookie]]></c> file is read and its content are used as cookie. The Erlang node we want to communicate with must have the same cookie.</p>
+ <p>(<em>Optional.</em>) Use this option to specify a certain cookie.
+ If no cookie is specified, the <c>~/.erlang.cookie</c>
+ file is read and its content is used as cookie. The Erlang node
+ we want to communicate with must have the same cookie.</p>
</item>
- <tag>-d</tag>
+ <tag><c>-d</c></tag>
<item>
- <p>(<em>optional</em>): Debug mode. This causes all IO to be output
- to the file <c><![CDATA[~/.erl_call.out.Nodename]]></c>, where <c><![CDATA[Nodename]]></c>
+ <p>(<em>Optional.</em>) Debug mode. This causes all I/O to be output
+ to the <c>~/.erl_call.out.Nodename</c> file, where
+ <c>Nodename</c>
is the node name of the Erlang node in question.</p>
- <p></p>
</item>
- <tag>-e</tag>
+ <tag><c>-e</c></tag>
<item>
- <p>(<em>optional</em>): Reads a sequence of Erlang expressions, separated
- by '<em>,</em>' and ended with a '<em>.</em>', from <c><![CDATA[stdin]]></c> until
- EOF (Control-D). Evaluates the expressions and returns the result from
- the last expression. Returns <c><![CDATA[{ok,Result}]]></c> if successful.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Reads a sequence of Erlang expressions,
+ separated by comma (,) and ended with a full stop (.), from
+ <c>stdin</c> until EOF (Control-D). Evaluates the
+ expressions and returns the result from the last expression.
+ Returns <c>{ok,Result}</c> on success.</p>
</item>
- <tag>-h HiddenName</tag>
+ <tag><c>-h HiddenName</c></tag>
<item>
- <p>(<em>optional</em>): Specifies the name of the hidden node
- that <c><![CDATA[erl_call]]></c> represents.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Specifies the name of the hidden node
+ that <c>erl_call</c> represents.</p>
</item>
- <tag>-m</tag>
+ <tag><c>-m</c></tag>
<item>
- <p>(<em>optional</em>): Reads an Erlang module from <c><![CDATA[stdin]]></c> and
- compiles it.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Reads an Erlang module from
+ <c>stdin</c> and compiles it.</p>
</item>
- <tag>-n Node</tag>
+ <tag><c>-n Node</c></tag>
<item>
- <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required):
- Has the same meaning as <c><![CDATA[-name]]></c> and can still be used for
- backwards compatibility reasons.</p>
- <p></p>
+ <p>(One of <c>-n, -name, -sname</c> is required.)
+ Has the same meaning as <c>-name</c> and can still be
+ used for backward compatibility reasons.</p>
</item>
- <tag>-name Node</tag>
+ <tag><c>-name Node</c></tag>
<item>
- <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): <c><![CDATA[Node]]></c> is the name of the node to be
- started or communicated with. It is assumed that
- <c><![CDATA[Node]]></c> is started with <c><![CDATA[erl -name]]></c>, which means that fully
- qualified long node names are used.
- If the <c><![CDATA[-s]]></c> option is given, an Erlang node will (if necessary)
- be started with <c><![CDATA[erl -name]]></c>.</p>
- <p></p>
+ <p>(One of <c>-n, -name, -sname</c> is required.)
+ <c>Node</c> is the name of the node to be
+ started or communicated with. It is assumed that
+ <c>Node</c> is started with
+ <c>erl -name</c>, which means that fully
+ qualified long node names are used. If option
+ <c>-s</c> is specified, an Erlang node will (if
+ necessary) be started with <c>erl -name</c>.</p>
</item>
- <tag>-q</tag>
+ <tag><c>-q</c></tag>
<item>
- <p>(<em>optional</em>): Halts the Erlang node specified
- with the -n switch. This switch overrides the -s switch.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Halts the Erlang node specified
+ with switch <c>-n</c>. This switch overrides switch <c>-s</c>.</p>
</item>
- <tag>-r</tag>
+ <tag><c>-r</c></tag>
<item>
- <p>(<em>optional</em>): Generates a random name of the hidden node
- that <c><![CDATA[erl_call]]></c> represents.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Generates a random name of the hidden node
+ that <c>erl_call</c> represents.</p>
</item>
- <tag>-s</tag>
+ <tag><c>-s</c></tag>
<item>
- <p>(<em>optional</em>): Starts a distributed Erlang node if necessary.
- This means that in a sequence of calls, where the '<c><![CDATA[-s]]></c>'
- and '<c><![CDATA[-n Node]]></c>' are constant, only the first call will start
- the Erlang node. This makes the rest of the communication
- very fast. This flag is currently only available on the Unix platform.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Starts a distributed Erlang node if
+ necessary. This means that in a sequence of calls, where
+ '<c>-s</c>' and '<c>-n Node</c>' are
+ constant, only the first call starts the Erlang node. This makes
+ the rest of the communication very fast. This flag is currently
+ only available on Unix-like platforms (Linux, Mac OS X, Solaris,
+ and so on).</p>
</item>
- <tag>-sname Node</tag>
+ <tag><c>-sname Node</c></tag>
<item>
- <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): <c><![CDATA[Node]]></c> is the name of the node to
- be started or communicated with. It is assumed that <c><![CDATA[Node]]></c> is started with <c><![CDATA[erl -sname]]></c> which means that short node names are used.
- If <c><![CDATA[-s]]></c> option is given, an Erlang node will be started (if necessary) with <c><![CDATA[erl -sname]]></c>.</p>
- <p></p>
+ <p>(One of <c>-n, -name, -sname</c> is required.)
+ <c>Node</c> is the name of the node to be started
+ or communicated with. It is assumed that <c>Node</c>
+ is started with <c>erl -sname</c>, which means that
+ short node names are used. If option <c>-s</c> is
+ specified, an Erlang node is started (if necessary) with
+ <c>erl -sname</c>.</p>
</item>
- <tag>-v</tag>
+ <tag><c>-v</c></tag>
<item>
- <p>(<em>optional</em>): Prints a lot of <c><![CDATA[verbose]]></c> information.
- This is only useful for the developer and maintainer of <c><![CDATA[erl_call]]></c>.</p>
- <p></p>
+ <p>(<em>Optional.</em>) Prints a lot of <c>verbose</c>
+ information. This is only useful for the developer and maintainer
+ of <c>erl_call</c>.</p>
</item>
- <tag>-x ErlScript</tag>
+ <tag><c>-x ErlScript</c></tag>
<item>
- <p>(<em>optional</em>): Specifies another name of the Erlang start-up script
- to be used. If not specified, the standard <c><![CDATA[erl]]></c> start-up script
- is used.</p>
+ <p>(<em>Optional.</em>) Specifies another name of the Erlang
+ startup script to be used. If not specified, the standard
+ <c>erl</c> startup script is used.</p>
</item>
</taglist>
</desc>
@@ -165,20 +176,29 @@
<section>
<title>Examples</title>
- <p>Starts an Erlang node and calls <c><![CDATA[erlang:time/0]]></c>.</p>
+ <p>To start an Erlang node and call <c>erlang:time/0</c>:</p>
+
<code type="none"><![CDATA[
erl_call -s -a 'erlang time' -n madonna
{18,27,34}
]]></code>
- <p>Terminates an Erlang node by calling <c><![CDATA[erlang:halt/0]]></c>.</p>
+
+ <p>To terminate an Erlang node by calling
+ <c>erlang:halt/0</c>:</p>
+
<code type="none"><![CDATA[
erl_call -s -a 'erlang halt' -n madonna
]]></code>
- <p>An apply with several arguments.</p>
+
+ <p>To apply with many arguments:</p>
+
<code type="none"><![CDATA[
-erl_call -s -a 'lists map [{math,sqrt},[1,4,9,16,25]]' -n madonna
+erl_call -s -a 'lists seq [1,10]' -n madonna
]]></code>
- <p>Evaluates a couple of expressions. <em>The input ends with EOF (Control-D)</em>.</p>
+
+ <p>To evaluate some expressions
+ (<em>the input ends with EOF (Control-D)</em>):</p>
+
<code type="none"><![CDATA[
erl_call -s -e -n madonna
statistics(runtime),
@@ -189,10 +209,14 @@ Y=2,
^D
{ok,{3,0}}
]]></code>
- <p>Compiles a module and runs it. <em>Again, the input ends with EOF (Control-D)</em>. (In the example shown, the output has been formatted afterwards).</p>
+
+ <p>To compile a module and run it (<em>again, the input ends with EOF
+ (Control-D)</em>):</p>
+ <p>(In the example, the output has been formatted afterwards.)</p>
+
<code type="none"><![CDATA[
-erl_call -s -m -a lolita -n madonna
--module(lolita).
+erl_call -s -m -a procnames -n madonna
+-module(procnames).
-compile(export_all).
start() ->
P = processes(),
@@ -238,4 +262,3 @@ start() ->
]]></code>
</section>
</comref>
-
diff --git a/lib/erl_interface/doc/src/erl_connect.xml b/lib/erl_interface/doc/src/erl_connect.xml
index 0fad98cd17..76ef6588c2 100644
--- a/lib/erl_interface/doc/src/erl_connect.xml
+++ b/lib/erl_interface/doc/src/erl_connect.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_connect</title>
@@ -28,127 +28,110 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>980703</date>
+ <date>1998-07-03</date>
<rev>A</rev>
- <file>erl_connect.sgml</file>
+ <file>erl_connect.xml</file>
</header>
<lib>erl_connect</lib>
- <libsummary>Communicate with Distributed Erlang</libsummary>
+ <libsummary>Communicate with distributed Erlang.</libsummary>
<description>
<p>This module provides support for communication between distributed
- Erlang nodes and C nodes, in a manner that is transparent to Erlang
+ Erlang nodes and C-nodes, in a manner that is transparent to Erlang
processes.</p>
- <p>A C node appears to Erlang as a
- <em>hidden node</em>.
+
+ <p>A C-node appears to Erlang as a <em>hidden node</em>.
That is, Erlang processes that know the name of the
- C node are able to communicate with it in a normal manner, but
- the node name will not appear in the listing provided by the
- Erlang function <c><![CDATA[nodes/0]]></c>.</p>
+ C-node can communicate with it in a normal manner, but
+ the node name does not appear in the listing provided by
+ <seealso marker="erts:erlang#nodes/0"><c>erlang:nodes/0</c></seealso>
+ in <c>ERTS</c>.</p>
</description>
+
<funcs>
<func>
- <name><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name>
- <name><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name>
- <fsummary>Initialize communication</fsummary>
+ <name><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name>
+ <fsummary>Accept a connection.</fsummary>
<type>
- <v>int number;</v>
- <v>char *cookie;</v>
- <v>short creation;</v>
- <v>char *host,*alive,*node;</v>
- <v>struct in_addr *addr;</v>
+ <v>int listensock;</v>
+ <v>ErlConnect *conp;</v>
</type>
<desc>
- <p>These functions initialize the <c><![CDATA[erl_connect]]></c>
- module. In particular, they are used to identify the name of the
- C-node from which they are called. One of these functions must
- be called before any of the other functions in the erl_connect
- module are used.</p>
- <p><c><![CDATA[erl_connect_xinit()]]></c> stores for later use information about
- the node's host name <c><![CDATA[host]]></c>, alive name <c><![CDATA[alive]]></c>, node
- name <c><![CDATA[node]]></c>, IP address <c><![CDATA[addr]]></c>, cookie <c><![CDATA[cookie]]></c>,
- and creation number <c><![CDATA[creation]]></c>. <c><![CDATA[erl_connect_init()]]></c>
- provides an alternative interface which does not require as much
- information from the caller. Instead, <c><![CDATA[erl_connect_init()]]></c>
- uses <c><![CDATA[gethostbyname()]]></c> to obtain default values.
- </p>
- <p>If you use <c><![CDATA[erl_connect_init()]]></c> your node will have a
- short name, i.e., it will not be fully qualified. If you need to
- use fully qualified (a.k.a. long) names, use
- <c><![CDATA[erl_connect_xinit()]]></c> instead.
- </p>
- <p><c><![CDATA[host]]></c> is the name of the host on which the node is running.</p>
- <p><c><![CDATA[alive]]></c> is the alivename of the node.</p>
- <p><c><![CDATA[node]]></c> is the name of the node. The nodename should
- be of the form <em>alivename@hostname</em>.</p>
- <p><c><![CDATA[addr]]></c> is the 32-bit IP address of <c><![CDATA[host]]></c>.</p>
- <p><c><![CDATA[cookie]]></c> is the authorization string required for access
- to the remote node. If NULL the user HOME directory is
- searched for a cookie file <c><![CDATA[.erlang.cookie]]></c>. The path to
- the home directory is retrieved from the environment variable
- <c><![CDATA[HOME]]></c> on Unix and from the <c><![CDATA[HOMEDRIVE]]></c> and
- <c><![CDATA[HOMEPATH]]></c> variables on Windows. Refer to the <c><![CDATA[auth]]></c>
- module for more details.</p>
- <p><c><![CDATA[creation]]></c> helps identify a particular instance of a C
- node. In particular, it can help prevent us from receiving
- messages sent to an earlier process with the same registered
- name.</p>
- <p>A C node acting as a server will be assigned a creation number
- when it calls <c><![CDATA[erl_publish()]]></c>.</p>
- <p><c><![CDATA[number]]></c> is used by <c><![CDATA[erl_connect_init()]]></c> to
- construct the actual node name. In the second example shown
- below, <em>"[email protected]"</em> will be the resulting node
- name.</p>
- <p>Example 1:</p>
- <code type="none"><![CDATA[
-struct in_addr addr;
-addr = inet_addr("150.236.14.75");
-if (!erl_connect_xinit("chivas",
- "madonna",
- &addr;
- "samplecookiestring..."),
- 0)
- erl_err_quit("<ERROR> when initializing !");
- ]]></code>
- <p>Example 2:</p>
+ <p>This function is used by a server process to accept a
+ connection from a client process.</p>
+ <list type="bulleted">
+ <item><c>listensock</c> is an open socket descriptor on
+ which <c>listen()</c> has previously been called.</item>
+ <item><c>conp</c> is a pointer to an
+ <c>ErlConnect</c> struct, described as follows:</item>
+ </list>
<code type="none"><![CDATA[
-if (!erl_connect_init(17, "samplecookiestring...", 0))
- erl_err_quit("<ERROR> when initializing !");
+typedef struct {
+ char ipadr[4];
+ char nodename[MAXNODELEN];
+} ErlConnect;
]]></code>
+ <p>On success, <c>conp</c> is filled in with the address and
+ node name of the connecting client and a file descriptor is
+ returned. On failure, <c>ERL_ERROR</c> is returned and
+ <c>erl_errno</c> is set to <c>EIO</c>.</p>
</desc>
</func>
+
+ <func>
+ <name><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name>
+ <fsummary>Close a connection to an Erlang node.</fsummary>
+ <type>
+ <v>int fd;</v>
+ </type>
+ <desc>
+ <p>Closes an open connection to an Erlang node.</p>
+ <p><c>Fd</c> is a file descriptor obtained from
+ <c>erl_connect()</c> or
+ <c>erl_xconnect()</c>.</p>
+ <p>Returns <c>0</c> on success. If the call fails, a non-zero value
+ is returned, and the reason for the error can be obtained with the
+ appropriate platform-dependent call.</p>
+ </desc>
+ </func>
+
<func>
<name><ret>int</ret><nametext>erl_connect(node)</nametext></name>
<name><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name>
- <fsummary>Establishe a connection to an Erlang node</fsummary>
+ <fsummary>Establish a connection to an Erlang node.</fsummary>
<type>
<v>char *node, *alive;</v>
<v>struct in_addr *addr;</v>
</type>
<desc>
- <p>These functions set up a connection to an Erlang node.</p>
- <p><c><![CDATA[erl_xconnect()]]></c> requires the IP address of the remote
- host and the alive name of the remote node
- to be specified. <c><![CDATA[erl_connect()]]></c> provides an alternative
+ <p>Sets up a connection to an Erlang node.</p>
+ <p><c>erl_xconnect()</c> requires the IP address of the
+ remote host and the alivename of the remote node to be
+ specified. <c>erl_connect()</c> provides an alternative
interface, and determines the information from the node name
provided.</p>
- <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the remote host.</p>
- <p><c><![CDATA[alive]]></c> is the alivename of the remote node.</p>
- <p><c><![CDATA[node]]></c> is the name of the remote node.</p>
- <p>These functions return an open file descriptor on success, or
- a negative value indicating that an error occurred --- in
- which case they will set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <list type="bulleted">
+ <item><c>addr</c> is the 32-bit IP address of the remote
+ host.</item>
+ <item><c>alive</c> is the alivename of the remote node.
+ </item>
+ <item><c>node</c> is the name of the remote node.</item>
+ </list>
+ <p>Returns an open file descriptor on success, otherwise a negative
+ value. In the latter case <c>erl_errno</c> is set to one
+ of:</p>
<taglist>
- <tag><c><![CDATA[EHOSTUNREACH]]></c></tag>
- <item>The remote host <c><![CDATA[node]]></c> is unreachable</item>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>EHOSTUNREACH</c></tag>
+ <item>The remote host <c>node</c> is unreachable.</item>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
</taglist>
- <p>Additionally, <c><![CDATA[errno]]></c> values from
- <c><![CDATA[socket]]></c><em>(2)</em> and <c><![CDATA[connect]]></c><em>(2)</em>
- system calls may be propagated into <c><![CDATA[erl_errno]]></c>.</p>
+ <p>Also, <c>errno</c> values from
+ <c>socket</c><em>(2)</em> and
+ <c>connect</c><em>(2)</em>
+ system calls can be propagated into <c>erl_errno</c>.</p>
+ <p><em>Example:</em></p>
<code type="none"><![CDATA[
#define NODE "[email protected]"
#define ALIVE "madonna"
@@ -164,59 +147,177 @@ erl_xconnect( &addr , ALIVE );
]]></code>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name>
- <fsummary>Close a connection to an Erlang node</fsummary>
+ <name><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name>
+ <name><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name>
+ <fsummary>Initialize communication.</fsummary>
<type>
- <v>int fd;</v>
+ <v>int number;</v>
+ <v>char *cookie;</v>
+ <v>short creation;</v>
+ <v>char *host,*alive,*node;</v>
+ <v>struct in_addr *addr;</v>
+ </type>
+ <desc>
+ <p>Initializes the <c>erl_connect</c> module.
+ In particular, these functions are used to identify the name of the
+ C-node from which they are called. One of these functions must
+ be called before any of the other functions in the <c>erl_connect</c>
+ module are used.</p>
+ <p><c>erl_connect_xinit()</c> stores for later use
+ information about:</p>
+ <list type="bulleted">
+ <item>Hostname of the node, <c>host</c></item>
+ <item>Alivename, <c>alive</c></item>
+ <item>Node name, <c>node</c></item>
+ <item>IP address, <c>addr</c></item>
+ <item>Cookie, <c>cookie</c></item>
+ <item>Creation number, <c>creation</c></item>
+ </list>
+ <p><c>erl_connect_init()</c>
+ provides an alternative interface that does not require as much
+ information from the caller. Instead,
+ <c>erl_connect_init()</c>
+ uses <c>gethostbyname()</c> to obtain default values.</p>
+ <p>If you use <c>erl_connect_init()</c>, your node will
+ have a short name, that is, it will not be fully qualified. If you
+ need to use fully qualified (long) names, use
+ <c>erl_connect_xinit()</c> instead.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>host</c> is the name of the host on which the node
+ is running.</p>
+ </item>
+ <item>
+ <p><c>alive</c> is the alivename of the node.</p>
+ </item>
+ <item>
+ <p><c>node</c> is the node name. It is to
+ be of the form <em>alivename@hostname</em>.</p>
+ </item>
+ <item>
+ <p><c>addr</c> is the 32-bit IP address of
+ <c>host</c>.</p>
+ </item>
+ <item>
+ <p><c>cookie</c> is the authorization string required
+ for access to the remote node. If <c>NULL</c>, the user
+ <c>HOME</c> directory is searched for a cookie file
+ <c>.erlang.cookie</c>. The path to
+ the home directory is retrieved from environment variable
+ <c>HOME</c> on Unix and from the
+ <c>HOMEDRIVE</c> and
+ <c>HOMEPATH</c> variables on Windows. For more
+ details, see the <seealso marker="kernel:auth">
+ <c>auth</c></seealso> module in Kernel.</p>
+ </item>
+ <item>
+ <p><c>creation</c> helps identifying a particular
+ instance of a C-node. In particular, it can help prevent us from
+ receiving messages sent to an earlier process with the same
+ registered name.</p>
+ </item>
+ </list>
+ <p>A C-node acting as a server is assigned a creation number
+ when it calls <c>erl_publish()</c>.</p>
+ <p><c>number</c> is used by
+ <c>erl_connect_init()</c> to
+ construct the actual node name. In Example 2
+ below, <em>"[email protected]"</em> is the resulting node name.</p>
+ <p><em>Example 1:</em></p>
+ <code type="none"><![CDATA[
+struct in_addr addr;
+addr = inet_addr("150.236.14.75");
+if (!erl_connect_xinit("chivas",
+ "madonna",
+ &addr;
+ "samplecookiestring..."),
+ 0)
+ erl_err_quit("<ERROR> when initializing !");
+ ]]></code>
+ <p><em>Example 2:</em></p>
+ <code type="none"><![CDATA[
+if (!erl_connect_init(17, "samplecookiestring...", 0))
+ erl_err_quit("<ERROR> when initializing !");
+ ]]></code>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>erl_publish(port)</nametext></name>
+ <fsummary>Publish a node name.</fsummary>
+ <type>
+ <v>int port;</v>
</type>
<desc>
- <p>This function closes an open connection to an Erlang node.</p>
- <p><c><![CDATA[Fd]]></c> is a file descriptor obtained from
- <c><![CDATA[erl_connect()]]></c> or <c><![CDATA[erl_xconnect()]]></c>.</p>
- <p>On success, 0 is returned. If the call fails, a non-zero value
- is returned, and the reason for
- the error can be obtained with the appropriate platform-dependent
- call.</p>
+ <p>This function is used by a server process to register
+ with the local name server EPMD, thereby allowing
+ other processes to send messages by using the registered name.
+ Before calling this function, the process should
+ have called <c>bind()</c> and <c>listen()</c>
+ on an open socket.</p>
+ <p><c>port</c> is the local name to register, and is to be
+ the same as the port number that was previously bound to the
+ socket.</p>
+ <p>To unregister with EPMD, simply close the returned descriptor.</p>
+ <p>On success, a descriptor connecting the calling process to EPMD is
+ returned. On failure, <c>-1</c> is returned and
+ <c>erl_errno</c> is set to:</p>
+ <taglist>
+ <tag><c>EIO</c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ <p>Also, <c>errno</c> values from
+ <c>socket</c><em>(2)</em>
+ and <c>connect</c><em>(2)</em> system calls can be
+ propagated into <c>erl_errno</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name>
- <fsummary>Receive a message</fsummary>
+ <fsummary>Receive a message.</fsummary>
<type>
<v>int fd;</v>
<v>char *bufp;</v>
<v>int bufsize;</v>
</type>
<desc>
- <p>This function receives a message consisting of a sequence
+ <p>Receives a message consisting of a sequence
of bytes in the Erlang external format.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected
- message. </p>
- <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p>
- <p>If a <em>tick</em> occurs, i.e., the Erlang node on the
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>bufp</c> is a buffer large enough to hold the
+ expected message.</item>
+ <item><c>bufsize</c> indicates the size of
+ <c>bufp</c>.</item>
+ </list>
+ <p>If a <em>tick</em> occurs, that is, the Erlang node on the
other end of the connection has polled this node to see if it
- is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> and
- no message will be placed in the buffer. Also,
- <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[EAGAIN]]></c>.</p>
+ is still alive, the function returns <c>ERL_TICK</c> and
+ no message is placed in the buffer. Also,
+ <c>erl_errno</c> is set to <c>EAGAIN</c>.</p>
<p>On success, the message is placed in the specified buffer
and the function returns the number of bytes actually read. On
- failure, the function returns a negative value and will set
- <c><![CDATA[erl_errno]]></c> to one of:</p>
+ failure, the function returns a negative value and sets
+ <c>erl_errno</c> to one of:</p>
<taglist>
- <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <tag><c>EAGAIN</c></tag>
<item>Temporary error: Try again.</item>
- <tag><c><![CDATA[EMSGSIZE]]></c></tag>
- <item>Buffer too small.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>EMSGSIZE</c></tag>
+ <item>Buffer is too small.</item>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
</taglist>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name>
- <fsummary>Receive and decodes a message</fsummary>
+ <fsummary>Receive and decode a message.</fsummary>
<type>
<v>int fd;</v>
<v>unsigned char *bufp;</v>
@@ -224,14 +325,20 @@ erl_xconnect( &addr , ALIVE );
<v>ErlMessage *emsg;</v>
</type>
<desc>
- <p>This function receives the message into the specified buffer,
- and decodes into the <c><![CDATA[(ErlMessage *) emsg]]></c>.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected message.</p>
- <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p>
- <p><c><![CDATA[emsg]]></c> is a pointer to an <c><![CDATA[ErlMessage]]></c> structure,
- into which the message will be decoded. <c><![CDATA[ErlMessage]]></c> is
- defined as follows:</p>
+ <p>Receives the message into the specified buffer
+ and decodes into <c>(ErlMessage *) emsg</c>.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>bufp</c> is a buffer large enough to hold the
+ expected message.</item>
+ <item><c>bufsize</c> indicates the size of
+ <c>bufp</c>.</item>
+ <item>><c>emsg</c> is a pointer to an
+ <c>ErlMessage</c> structure
+ into which the message will be decoded.
+ <c>ErlMessage</c> is defined as follows:</item>
+ </list>
<code type="none"><![CDATA[
typedef struct {
int type;
@@ -242,144 +349,100 @@ typedef struct {
} ErlMessage;
]]></code>
<note>
- <p>The definition of <c><![CDATA[ErlMessage]]></c> has changed since
- earlier versions of Erl_Interface.</p>
+ <p>The definition of <c>ErlMessage</c> has changed since
+ earlier versions of <c>Erl_Interface</c>.</p>
</note>
- <p><c><![CDATA[type]]></c> identifies the type of message, one of
- <c><![CDATA[ERL_SEND]]></c>, <c><![CDATA[ERL_REG_SEND]]></c>, <c><![CDATA[ERL_LINK]]></c>,
- <c><![CDATA[ERL_UNLINK]]></c> and <c><![CDATA[ERL_EXIT]]></c>.
- </p>
- <p>If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_SEND]]></c>
- this indicates that an ordinary send operation has taken
- place, and <c><![CDATA[emsg->to]]></c> contains the Pid of the
- recipient. If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_REG_SEND]]></c> then a
- registered send operation took place, and <c><![CDATA[emsg->from]]></c>
- contains the Pid of the sender. In both cases, the actual
- message will be in <c><![CDATA[emsg->msg]]></c>.
- </p>
- <p>If <c><![CDATA[type]]></c> contains one of <c><![CDATA[ERL_LINK]]></c> or
- <c><![CDATA[ERL_UNLINK]]></c>, then <c><![CDATA[emsg->to]]></c> and <c><![CDATA[emsg->from]]></c>
- contain the pids of the sender and recipient of the link or unlink.
- <c><![CDATA[emsg->msg]]></c> is not used in these cases.
- </p>
- <p>If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_EXIT]]></c>, then this
- indicates that a link has been broken. In this case,
- <c><![CDATA[emsg->to]]></c> and <c><![CDATA[emsg->from]]></c> contain the pids of the
- linked processes, and <c><![CDATA[emsg->msg]]></c> contains the reason for
- the exit.
- </p>
+ <p><c>type</c> identifies the type of message, one of the
+ following:</p>
+ <taglist>
+ <tag><c>ERL_SEND</c></tag>
+ <item>
+ <p>An ordinary send operation has occurred and
+ <c>emsg->to</c> contains the pid of the recipient.
+ The message is in <c>emsg->msg</c>.</p>
+ </item>
+ <tag><c>ERL_REG_SEND</c></tag>
+ <item>
+ <p>A registered send operation has occurred and
+ <c>emsg->from</c> contains the pid of the sender.
+ The message is in <c>emsg->msg</c>.</p>
+ </item>
+ <tag><c>ERL_LINK</c> or <c>ERL_UNLINK</c>
+ </tag>
+ <item>
+ <p><c>emsg->to</c> and <c>emsg->from</c>
+ contain the pids of the sender and recipient of the link or
+ unlink. <c>emsg->msg</c> is not used.</p>
+ </item>
+ <tag><c>ERL_EXIT</c></tag>
+ <item>
+ <p>A link is broken. <c>emsg->to</c> and
+ <c>emsg->from</c> contain the pids of the linked
+ processes, and <c>emsg->msg</c> contains the reason
+ for the exit.</p>
+ </item>
+ </taglist>
<note>
<p>It is the caller's responsibility to release the
- memory pointed to by <c><![CDATA[emsg->msg]]></c>, <c><![CDATA[emsg->to]]></c> and
- <c><![CDATA[emsg->from]]></c>.</p>
+ memory pointed to by <c>emsg->msg</c>,
+ <c>emsg->to</c>, and
+ <c>emsg->from</c>.</p>
</note>
- <p>If a <em>tick</em> occurs, i.e., the Erlang node on the
+ <p>If a <em>tick</em> occurs, that is, the Erlang node on the
other end of the connection has polled this node to see if it
- is still alive, the function will return <c><![CDATA[ERL_TICK]]></c>
+ is still alive, the function returns <c>ERL_TICK</c>
indicating that the tick has been received and responded to,
- but no message will be placed in the buffer. In this case you
- should call <c><![CDATA[erl_receive_msg()]]></c> again.</p>
- <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the
- <c><![CDATA[Emsg]]></c> struct will be initialized as described above, or
- <c><![CDATA[ERL_TICK]]></c>, in which case no message is returned. On
- failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set
- <c><![CDATA[erl_errno]]></c> to one of:</p>
+ but no message is placed in the buffer. In this case you
+ are to call <c>erl_receive_msg()</c> again.</p>
+ <p>On success, the function returns <c>ERL_MSG</c> and the
+ <c>Emsg</c> struct is initialized as described above, or
+ <c>ERL_TICK</c>, in which case no message is returned. On
+ failure, the function returns <c>ERL_ERROR</c> and sets
+ <c>erl_errno</c> to one of:</p>
<taglist>
- <tag><c><![CDATA[EMSGSIZE]]></c></tag>
- <item>Buffer too small.</item>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
- <item>I/O error.</item>
- </taglist>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name>
- <fsummary>Receive and decodes a message</fsummary>
- <type>
- <v>int fd;</v>
- <v>unsigned char **bufpp;</v>
- <v>int *bufsizep;</v>
- <v>ErlMessage *emsg;</v>
- </type>
- <desc>
- <p>This function is similar to <c><![CDATA[erl_receive_msg]]></c>. The
- difference is that <c><![CDATA[erl_xreceive_msg]]></c> expects the buffer to
- have been allocated by <c><![CDATA[malloc]]></c>, and reallocates it if the received
- message does not fit into the original buffer. For that reason,
- both buffer and buffer length are given as pointers - their values
- may change by the call.
- </p>
- <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the
- <c><![CDATA[Emsg]]></c> struct will be initialized as described above, or
- <c><![CDATA[ERL_TICK]]></c>, in which case no message is returned. On
- failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set
- <c><![CDATA[erl_errno]]></c> to one of:</p>
- <taglist>
- <tag><c><![CDATA[EMSGSIZE]]></c></tag>
- <item>Buffer too small.</item>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
- <item>I/O error.</item>
- </taglist>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name>
- <fsummary>Send a message</fsummary>
- <type>
- <v>int fd;</v>
- <v>ETERM *to, *msg;</v>
- </type>
- <desc>
- <p>This function sends an Erlang term to a process.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[to]]></c> is an Erlang term containing the Pid of the
- intended recipient of the message.</p>
- <p><c><![CDATA[msg]]></c> is the Erlang term to be sent.</p>
- <p>The function returns 1 if successful, otherwise 0 --- in
- which case it will set <c><![CDATA[erl_errno]]></c> to one of:</p>
- <taglist>
- <tag><c><![CDATA[EINVAL]]></c></tag>
- <item>Invalid argument: <c><![CDATA[to]]></c> is not a valid Erlang pid.</item>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>EMSGSIZE</c></tag>
+ <item>Buffer is too small.</item>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
</taglist>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name>
- <fsummary>Send a message to a registered name</fsummary>
+ <fsummary>Send a message to a registered name.</fsummary>
<type>
<v>int fd;</v>
<v>char *to;</v>
<v>ETERM *msg;</v>
</type>
<desc>
- <p>This function sends an Erlang term to a registered process.</p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[to]]></c> is a string containing the registered name of
- the intended recipient of the message.</p>
- <p><c><![CDATA[msg]]></c> is the Erlang term to be sent.</p>
- <p>The function returns 1 if successful, otherwise 0 --- in
- which case it will set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <p>Sends an Erlang term to a registered process.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>to</c> is a string containing the registered name
+ of the intended recipient of the message.</item>
+ <item><c>msg</c> is the Erlang term to be sent.</item>
+ </list>
+ <p>Returns <c>1</c> on success, otherwise <c>0</c>. In
+ the latter case <c>erl_errno</c> is set to one of:</p>
<taglist>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
</taglist>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name>
- <name><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name>
<name><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name>
- <fsummary>Remote Procedure Call</fsummary>
+ <name><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name>
+ <fsummary>Remote Procedure Call.</fsummary>
<type>
<v>int fd, timeout;</v>
<v>char *mod, *fun;</v>
@@ -387,158 +450,178 @@ typedef struct {
<v>ErlMessage *emsg;</v>
</type>
<desc>
- <p>These functions support calling Erlang functions on remote nodes.
- <c><![CDATA[erl_rpc_to()]]></c> sends an rpc request to a remote node and
- <c><![CDATA[erl_rpc_from()]]></c> receives the results of such a call.
- <c><![CDATA[erl_rpc()]]></c> combines the functionality of these two functions
- by sending an rpc request and waiting for the results. See also
- <c><![CDATA[rpc:call/4]]></c>. </p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
- <p><c><![CDATA[timeout]]></c> is the maximum time (in ms) to wait for
- results. Specify <c><![CDATA[ERL_NO_TIMEOUT]]></c> to wait forever.
- When erl_rpc() calls erl_rpc_from(), the call will never
- timeout.</p>
- <p><c><![CDATA[mod]]></c> is the name of the module containing the function
- to be run on the remote node.</p>
- <p><c><![CDATA[fun]]></c> is the name of the function to run.</p>
- <p><c><![CDATA[args]]></c> is an Erlang list, containing the arguments to be
- passed to the function. </p>
- <p><c><![CDATA[emsg]]></c> is a message containing the result of the
- function call.</p>
- <p>The actual message returned by the rpc server
- is a 2-tuple <c><![CDATA[{rex,Reply}]]></c>. If you are using
- <c><![CDATA[erl_rpc_from()]]></c> in your code then this is the message you
- will need to parse. If you are using <c><![CDATA[erl_rpc()]]></c> then the
+ <p>Supports calling Erlang functions on remote nodes.
+ <c>erl_rpc_to()</c> sends an RPC request to a remote node
+ and <c>erl_rpc_from()</c> receives the results of such a
+ call. <c>erl_rpc()</c> combines the functionality of
+ these two functions by sending an RPC request and waiting for the
+ results. See also <seealso marker="kernel:rpc#call/4">
+ <c>rpc:call/4</c></seealso> in <c>Kernel</c>.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>timeout</c> is the maximum time (in milliseconds)
+ to wait for
+ results. To wait forever, specify <c>ERL_NO_TIMEOUT</c>.
+ When <c>erl_rpc()</c> calls <c>erl_rpc_from()</c>, the call will
+ never timeout.</item>
+ <item><c>mod</c> is the name of the module containing the
+ function to be run on the remote node.</item>
+ <item><c>fun</c> is the name of the function to run.
+ </item>
+ <item><c>args</c> is an Erlang list, containing the
+ arguments to be passed to the function.</item>
+ <item><c>emsg</c> is a message containing the result of
+ the function call.</item>
+ </list>
+ <p>The actual message returned by the RPC server
+ is a 2-tuple <c>{rex,Reply}</c>. If you use
+ <c>erl_rpc_from()</c> in your code, this is the message
+ you will need to parse. If you use <c>erl_rpc()</c>, the
tuple itself is parsed for you, and the message returned to your
- program is the erlang term containing <c><![CDATA[Reply]]></c> only. Replies
- to rpc requests are always ERL_SEND messages.
- </p>
+ program is the Erlang term containing <c>Reply</c> only.
+ Replies to RPC requests are always <c>ERL_SEND</c> messages.</p>
<note>
<p>It is the caller's responsibility to free the returned
- <c><![CDATA[ETERM]]></c> structure as well as the memory pointed to by
- <c><![CDATA[emsg->msg]]></c> and <c><![CDATA[emsg->to]]></c>. </p>
+ <c>ETERM</c> structure and the memory pointed to by
+ <c>emsg->msg</c> and <c>emsg->to</c>.</p>
</note>
- <p><c><![CDATA[erl_rpc()]]></c> returns the remote function's return value (or
- <c><![CDATA[NULL]]></c> if it failed). <c><![CDATA[erl_rpc_to()]]></c> returns 0 on
- success, and a negative number on failure. <c><![CDATA[erl_rcp_from()]]></c>
- returns <c><![CDATA[ERL_MSG]]></c> when successful (with <c><![CDATA[Emsg]]></c> now
- containing the reply tuple), and one of <c><![CDATA[ERL_TICK]]></c>,
- <c><![CDATA[ERL_TIMEOUT]]></c> and <c><![CDATA[ERL_ERROR]]></c> otherwise. When failing,
- all three functions set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <p><c>erl_rpc()</c> returns the remote function's return
+ value on success, otherwise <c>NULL</c>.</p>
+ <p><c>erl_rpc_to()</c> returns <c>0</c> on
+ success, otherwise a negative number.</p>
+ <p><c>erl_rcp_from()</c> returns <c>ERL_MSG</c>
+ on success (with <c>Emsg</c> now
+ containing the reply tuple), otherwise one of
+ <c>ERL_TICK</c>, <c>ERL_TIMEOUT</c>, or
+ <c>ERL_ERROR</c>.</p>
+ <p>When failing,
+ all three functions set <c>erl_errno</c> to one of:</p>
<taglist>
- <tag><c><![CDATA[ENOMEM]]></c></tag>
- <item>No more memory available.</item>
- <tag><c><![CDATA[EIO]]></c></tag>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
<item>I/O error.</item>
- <tag><c><![CDATA[ETIMEDOUT]]></c></tag>
- <item>Timeout expired.</item>
- <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <tag><c>ETIMEDOUT</c></tag>
+ <item>Timeout has expired.</item>
+ <tag><c>EAGAIN</c></tag>
<item>Temporary error: Try again.</item>
</taglist>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>erl_publish(port)</nametext></name>
- <fsummary>Publish a node name</fsummary>
+ <name><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name>
+ <fsummary>Send a message.</fsummary>
<type>
- <v>int port;</v>
+ <v>int fd;</v>
+ <v>ETERM *to, *msg;</v>
</type>
<desc>
- <p>These functions are used by a server process to register
- with the local name server <em>epmd</em>, thereby allowing
- other processes to send messages by using the registered name.
- Before calling either of these functions, the process should
- have called <c><![CDATA[bind()]]></c> and <c><![CDATA[listen()]]></c> on an open socket.</p>
- <p><c><![CDATA[port]]></c> is the local name to register, and should be the
- same as the port number that was previously bound to the socket.</p>
- <p>To unregister with epmd, simply close the returned
- descriptor.
- </p>
- <p>On success, the functions return a descriptor connecting the
- calling process to epmd. On failure, they return -1 and set
- <c><![CDATA[erl_errno]]></c> to:</p>
+ <p>Sends an Erlang term to a process.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>to</c> is an Erlang term containing the pid of
+ the intended recipient of the message.</item>
+ <item>><c>msg</c> is the Erlang term to be sent.</item>
+ </list>
+ <p>Returns <c>1</c> on success, otherwise <c>0</c>. In
+ the latter case <c>erl_errno</c> is set to one of:</p>
<taglist>
- <tag><c><![CDATA[EIO]]></c></tag>
- <item>I/O error</item>
+ <tag><c>EINVAL</c></tag>
+ <item>Invalid argument: <c>to</c> is not a valid Erlang
+ pid.</item>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
+ <item>I/O error.</item>
</taglist>
- <p>Additionally, <c><![CDATA[errno]]></c> values from <c><![CDATA[socket]]></c><em>(2)</em>
- and <c><![CDATA[connect]]></c><em>(2)</em> system calls may be propagated
- into <c><![CDATA[erl_errno]]></c>.
- </p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name>
- <fsummary>Accept a connection</fsummary>
- <type>
- <v>int listensock;</v>
- <v>ErlConnect *conp;</v>
- </type>
- <desc>
- <p>This function is used by a server process to accept a
- connection from a client process.</p>
- <p><c><![CDATA[listensock]]></c> is an open socket descriptor on which
- <c><![CDATA[listen()]]></c> has previously been called.</p>
- <p><c><![CDATA[conp]]></c> is a pointer to an <c><![CDATA[ErlConnect]]></c> struct,
- described as follows:</p>
- <code type="none"><![CDATA[
-typedef struct {
- char ipadr[4];
- char nodename[MAXNODELEN];
-} ErlConnect;
- ]]></code>
- <p>On success, <c><![CDATA[conp]]></c> is filled in with the address and
- node name of the connecting client and a file descriptor is
- returned. On failure, <c><![CDATA[ERL_ERROR]]></c> is returned and
- <c><![CDATA[erl_errno]]></c> is set to <c><![CDATA[EIO]]></c>.</p>
</desc>
</func>
+
<func>
- <name><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name>
- <name><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name>
- <name><ret>const char *</ret><nametext>erl_thishostname()</nametext></name>
<name><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name>
+ <name><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name>
<name><ret>short</ret><nametext>erl_thiscreation()</nametext></name>
- <fsummary>Retrieve some values</fsummary>
+ <name><ret>const char *</ret><nametext>erl_thishostname()</nametext></name>
+ <name><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name>
+ <fsummary>Retrieve some values.</fsummary>
<desc>
- <p>These functions can be used to retrieve information about
- the C Node. These values are initially set with
- <c><![CDATA[erl_connect_init()]]></c> or <c><![CDATA[erl_connect_xinit()]]></c>.</p>
+ <p>Retrieves information about
+ the C-node. These values are initially set with
+ <c>erl_connect_init()</c> or
+ <c>erl_connect_xinit()</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name>
- <fsummary>Forcefully unpublish a node name</fsummary>
+ <fsummary>Forcefully unpublish a node name.</fsummary>
<type>
<v>char *alive;</v>
</type>
<desc>
<p>This function can be called by a process to unregister a
- specified node from epmd on the localhost. This is however usually not
- allowed, unless epmd was started with the -relaxed_command_check
- flag, which it normally isn't.</p>
-
- <p>To unregister a node you have published, you should instead
- close the descriptor that was returned by
- <c><![CDATA[ei_publish()]]></c>.</p>
-
+ specified node from EPMD on the local host. This is, however, usually
+ not allowed, unless EPMD was started with flag
+ <c>-relaxed_command_check</c>, which it normally is not.</p>
+ <p>To unregister a node you have published, you should instead
+ close the descriptor that was returned by
+ <c>ei_publish()</c>.</p>
<warning>
- <p>This function is deprecated and will be removed in a future
- release.</p>
+ <p>This function is deprecated and will be removed in a future
+ release.</p>
</warning>
- <p><c><![CDATA[alive]]></c> is the name of the node to unregister, i.e., the
- first component of the nodename, without the <c><![CDATA[@hostname]]></c>.</p>
- <p>If the node was successfully unregistered from epmd, the
- function returns 0. Otherwise, it returns -1 and sets
- <c><![CDATA[erl_errno]]></c> is to <c><![CDATA[EIO]]></c>.</p>
+ <p><c>alive</c> is the name of the node to unregister, that
+ is, the first component of the node name, without
+ <c>@hostname</c>.</p>
+ <p>If the node was successfully unregistered from EPMD, <c>0</c> is
+ returned, otherwise <c>-1</c> is returned and
+ <c>erl_errno</c> is set to <c>EIO</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name>
+ <fsummary>Receive and decode a message.</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>unsigned char **bufpp;</v>
+ <v>int *bufsizep;</v>
+ <v>ErlMessage *emsg;</v>
+ </type>
+ <desc>
+ <p>Similar to <c>erl_receive_msg</c>. The difference is
+ that <c>erl_xreceive_msg</c> expects the buffer to
+ have been allocated by <c>malloc</c>, and reallocates it
+ if the received
+ message does not fit into the original buffer. Therefore
+ both buffer and buffer length are given as pointers; their values
+ can change by the call.</p>
+ <p>On success, the function returns <c>ERL_MSG</c> and the
+ <c>Emsg</c> struct is initialized as described above, or
+ <c>ERL_TICK</c>, in which case no message is returned. On
+ failure, the function returns <c>ERL_ERROR</c> and sets
+ <c>erl_errno</c> to one of:</p>
+ <taglist>
+ <tag><c>EMSGSIZE</c></tag>
+ <item>Buffer is too small.</item>
+ <tag><c>ENOMEM</c></tag>
+ <item>No more memory is available.</item>
+ <tag><c>EIO</c></tag>
+ <item>I/O error.</item>
+ </taglist>
</desc>
</func>
+
<func>
- <name><ret>struct hostent</ret><nametext>*erl_gethostbyname(name)</nametext></name>
<name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr(addr, length, type)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name>
<name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name>
- <fsummary>Name lookup functions</fsummary>
+ <name><ret>struct hostent</ret><nametext>*erl_gethostbyname(name)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name>
+
+ <fsummary>Name lookup functions.</fsummary>
<type>
<v>const char *name;</v>
<v>const char *addr;</v>
@@ -550,7 +633,7 @@ typedef struct {
<v>int *h_errnop;</v>
</type>
<desc>
- <p>These are convenience functions for some common name lookup functions.</p>
+ <p>Convenience functions for some common name lookup functions.</p>
</desc>
</func>
</funcs>
@@ -558,13 +641,13 @@ typedef struct {
<section>
<title>Debug Information</title>
<p>If a connection attempt fails, the following can be checked:</p>
+
<list type="bulleted">
- <item><c><![CDATA[erl_errno]]></c></item>
- <item>that the right cookie was used</item>
- <item>that <em>epmd</em> is running</item>
- <item>the remote Erlang node on the other side is running the same
- version of Erlang as the <c><![CDATA[erl_interface]]></c> library.</item>
+ <item><c>erl_errno</c></item>
+ <item>That the correct cookie was used</item>
+ <item>That EPMD is running</item>
+ <item>That the remote Erlang node on the other side is running the same
+ version of Erlang as the <c>erl_interface</c> library</item>
</list>
</section>
</cref>
-
diff --git a/lib/erl_interface/doc/src/erl_error.xml b/lib/erl_interface/doc/src/erl_error.xml
index abe84780e1..8139c9b343 100644
--- a/lib/erl_interface/doc/src/erl_error.xml
+++ b/lib/erl_interface/doc/src/erl_error.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_error</title>
@@ -28,61 +28,66 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>961014</date>
+ <date>1996-10-14</date>
<rev>A</rev>
- <file>erl_error.sgml</file>
+ <file>erl_error.xml</file>
</header>
<lib>erl_error</lib>
- <libsummary>Error Print Routines</libsummary>
+ <libsummary>Error print routines.</libsummary>
<description>
<p>This module contains some error printing routines taken
- from <em>Advanced Programming in the UNIX Environment</em>
- by W. Richard Stevens. </p>
+ from "Advanced Programming in the UNIX Environment"
+ by W. Richard Stevens.</p>
+
<p>These functions are all called in the same manner as
- <c><![CDATA[printf()]]></c>, i.e. with a string containing format specifiers
- followed by a list of corresponding arguments. All output from
- these functions is to <c><![CDATA[stderr]]></c>.</p>
+ <c>printf()</c>, that is, with a string containing format
+ specifiers followed by a list of corresponding arguments. All output from
+ these functions is to <c>stderr</c>.</p>
</description>
+
<funcs>
<func>
<name><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name>
- <fsummary>Non-fatal error, and not system call error</fsummary>
+ <fsummary>Non-fatal error, and not system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
</type>
<desc>
<p>The message provided by the caller is printed. This
- function is simply a wrapper for <c><![CDATA[fprintf()]]></c>.</p>
+ function is simply a wrapper for <c>fprintf()</c>.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name>
- <fsummary>Fatal error, but not system call error</fsummary>
+ <fsummary>Fatal error, but not system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
</type>
<desc>
<p>Use this function when a fatal error has occurred that
- is not due to a system call. The message provided by the
- caller is printed and the process terminates with an exit
- value of 1. The function does not return.</p>
+ is not because of a system call. The message provided by the
+ caller is printed and the process terminates with exit
+ value <c>1</c>. This function does not return.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name>
- <fsummary>Non-fatal system call error</fsummary>
+ <fsummary>Non-fatal system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
</type>
<desc>
<p>Use this function after a failed system call. The message
provided by the caller is printed followed by a string
- describing the reason for failure. </p>
+ describing the reason for failure.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name>
- <fsummary>Fatal system call error</fsummary>
+ <fsummary>Fatal system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
</type>
@@ -90,7 +95,7 @@
<p>Use this function after a failed system call. The message
provided by the caller is printed followed by a string
describing the reason for failure, and the process
- terminates with an exit value of 1. The function does not
+ terminates with exit value <c>1</c>. This function does not
return.</p>
</desc>
</func>
@@ -98,40 +103,43 @@
<section>
<title>Error Reporting</title>
- <p>Most functions in erl_interface report failures to the caller by
- returning some otherwise meaningless value (typically <c><![CDATA[NULL]]></c>
+ <p>Most functions in <c>Erl_Interface</c> report failures to the caller by
+ returning some otherwise meaningless value (typically
+ <c>NULL</c>
or a negative number). As this only tells you that things did not
- go well, you will have to examine the error code in
- <c><![CDATA[erl_errno]]></c> if you want to find out more about the failure.</p>
+ go well, examine the error code in <c>erl_errno</c> if you
+ want to find out more about the failure.</p>
</section>
+
<funcs>
<func>
<name><ret>volatile int</ret><nametext>erl_errno</nametext></name>
- <fsummary>The variable <c><![CDATA[erl_errno]]></c>contains the erl_interface error number. You can change the value if you wish. </fsummary>
+ <fsummary>Variable <c>erl_errno</c> contains the
+ Erl_Interface error number. You can change the value if you wish.
+ </fsummary>
<desc>
- <p><c><![CDATA[erl_errno]]></c> is initially (at program startup) zero and
- is then set by many erl_interface functions on failure to a
- non-zero error code to indicate what kind of error it
- encountered. A successful function call might change
- <c><![CDATA[erl_errno]]></c> (by calling some other function that
- fails), but no function will ever set it to zero. This means
- that you cannot use <c><![CDATA[erl_errno]]></c> to see <em>if</em> a
+ <p><c>erl_errno</c> is initially (at program startup) zero
+ and is then set by many <c>Erl_Interface</c> functions on failure to
+ a non-zero error code to indicate what kind of error it
+ encountered. A successful function call can change
+ <c>erl_errno</c> (by calling some other function that
+ fails), but no function does never set it to zero. This means
+ that you cannot use <c>erl_errno</c> to see <em>if</em> a
function call failed. Instead, each function reports failure
in its own way (usually by returning a negative number or
- <c><![CDATA[NULL]]></c>), in which case you can examine <c><![CDATA[erl_errno]]></c>
- for details.</p>
- <p><c><![CDATA[erl_errno]]></c> uses the error codes defined in your
- system's <c><![CDATA[<errno.h>]]></c>.</p>
+ <c>NULL</c>), in which case you can examine
+ <c>erl_errno</c> for details.</p>
+ <p><c>erl_errno</c> uses the error codes defined in your
+ system's <c>&lt;errno.h&gt;</c>.</p>
<note>
- <p>Actually, <c><![CDATA[erl_errno]]></c> is a "modifiable lvalue" (just
- like ISO C defines <c><![CDATA[errno]]></c> to be) rather than a
- variable. This means it might be implemented as a macro
- (expanding to, e.g., <c><![CDATA[*_erl_errno()]]></c>). For reasons of
- thread- (or task-)safety, this is exactly what we do on most
- platforms.</p>
+ <p><c>erl_errno</c> is a "modifiable lvalue" (just
+ like ISO C defines <c>errno</c> to be) rather than a
+ variable. This means it can be implemented as a macro
+ (expanding to, for example, <c>*_erl_errno()</c>).
+ For reasons of thread safety (or task safety), this is exactly what
+ we do on most platforms.</p>
</note>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml
index 800f8a3207..9a05196a70 100644
--- a/lib/erl_interface/doc/src/erl_eterm.xml
+++ b/lib/erl_interface/doc/src/erl_eterm.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_eterm</title>
@@ -28,131 +28,145 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>980703</date>
+ <date>1998-07-03</date>
<rev>A</rev>
- <file>erl_eterm.sgml</file>
+ <file>erl_eterm.xml</file>
</header>
<lib>erl_eterm</lib>
- <libsummary>Functions for Erlang Term Construction</libsummary>
+ <libsummary>Functions for Erlang term construction.</libsummary>
<description>
- <p>This module contains functions for creating and manipulating
- Erlang terms. </p>
+ <p>This module provides functions for creating and manipulating
+ Erlang terms.</p>
+
<p>An Erlang term is represented by a C structure of type
- <c><![CDATA[ETERM]]></c>. Applications should not reference any fields in this
- structure directly, because it may be changed in future releases
+ <c>ETERM</c>. Applications should not reference any fields
+ in this structure directly, as it can be changed in future releases
to provide faster and more compact term storage. Instead,
- applications should us the macros and functions provided. </p>
- <p>The following macros each take a single ETERM pointer as an
- argument. They return a non-zero value if the test is true, and 0
- otherwise:</p>
+ applications should use the macros and functions provided.</p>
+
+ <p>Each of the following macros takes a single <c>ETERM</c> pointer as an
+ argument. The macros return a non-zero value if the test is true,
+ otherwise <c>0</c>.</p>
+
<taglist>
- <tag><c><![CDATA[ERL_IS_INTEGER(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is an integer.</item>
- <tag><c><![CDATA[ERL_IS_UNSIGNED_INTEGER(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is an integer.</item>
- <tag><c><![CDATA[ERL_IS_FLOAT(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a floating point number.</item>
- <tag><c><![CDATA[ERL_IS_ATOM(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is an atom.</item>
- <tag><c><![CDATA[ERL_IS_PID(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a Pid (process identifier).</item>
- <tag><c><![CDATA[ERL_IS_PORT(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a port.</item>
- <tag><c><![CDATA[ERL_IS_REF(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a reference.</item>
- <tag><c><![CDATA[ERL_IS_TUPLE(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a tuple.</item>
- <tag><c><![CDATA[ERL_IS_BINARY(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a binary.</item>
- <tag><c><![CDATA[ERL_IS_LIST(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a list with zero or more elements.</item>
- <tag><c><![CDATA[ERL_IS_EMPTY_LIST(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is an empty list.</item>
- <tag><c><![CDATA[ERL_IS_CONS(t)]]></c></tag>
- <item>True if <c><![CDATA[t]]></c> is a list with at least one element.</item>
+ <tag><c>ERL_IS_INTEGER(t)</c></tag>
+ <item>True if <c>t</c> is an integer.</item>
+ <tag><c>ERL_IS_UNSIGNED_INTEGER(t)</c></tag>
+ <item>True if <c>t</c> is an integer.</item>
+ <tag><c>ERL_IS_FLOAT(t)</c></tag>
+ <item>True if <c>t</c> is a floating point number.</item>
+ <tag><c>ERL_IS_ATOM(t)</c></tag>
+ <item>True if <c>t</c> is an atom.</item>
+ <tag><c>ERL_IS_PID(t)</c></tag>
+ <item>True if <c>t</c> is a pid (process identifier).</item>
+ <tag><c>ERL_IS_PORT(t)</c></tag>
+ <item>True if <c>t</c> is a port.</item>
+ <tag><c>ERL_IS_REF(t)</c></tag>
+ <item>True if <c>t</c> is a reference.</item>
+ <tag><c>ERL_IS_TUPLE(t)</c></tag>
+ <item>True if <c>t</c> is a tuple.</item>
+ <tag><c>ERL_IS_BINARY(t)</c></tag>
+ <item>True if <c>t</c> is a binary.</item>
+ <tag><c>ERL_IS_LIST(t)</c></tag>
+ <item>True if <c>t</c> is a list with zero or more
+ elements.</item>
+ <tag><c>ERL_IS_EMPTY_LIST(t)</c></tag>
+ <item>True if <c>t</c> is an empty list.</item>
+ <tag><c>ERL_IS_CONS(t)</c></tag>
+ <item>True if <c>t</c> is a list with at least one
+ element.</item>
</taglist>
+
<p>The following macros can be used for retrieving parts of Erlang
- terms. None of these do any type checking; results are undefined
- if you pass an ETERM* containing the wrong type. For example,
- passing a tuple to ERL_ATOM_PTR() will likely result in garbage.
- </p>
+ terms. None of these do any type checking. Results are undefined
+ if you pass an <c>ETERM*</c> containing the wrong type. For example,
+ passing a tuple to <c>ERL_ATOM_PTR()</c> likely results in garbage.</p>
+
<taglist>
- <tag><c><![CDATA[char *ERL_ATOM_PTR(t)]]></c></tag>
- <item/>
- <tag><c><![CDATA[char *ERL_ATOM_PTR_UTF8(t)]]></c></tag>
- <item>A string representing atom <c><![CDATA[t]]></c>.
- </item>
- <tag><c><![CDATA[int ERL_ATOM_SIZE(t)]]></c></tag>
- <item/>
- <tag><c><![CDATA[int ERL_ATOM_SIZE_UTF8(t)]]></c></tag>
- <item>The length (in bytes) of atom t.</item>
- <tag><c><![CDATA[void *ERL_BIN_PTR(t)]]></c></tag>
- <item>A pointer to the contents of <c><![CDATA[t]]></c></item>
- <tag><c><![CDATA[int ERL_BIN_SIZE(t)]]></c></tag>
- <item>The length (in bytes) of binary object <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_INT_VALUE(t)]]></c></tag>
- <item>The integer of <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[unsigned int ERL_INT_UVALUE(t)]]></c></tag>
- <item>The unsigned integer value of <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[double ERL_FLOAT_VALUE(t)]]></c></tag>
- <item>The floating point value of <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[ETERM *ERL_PID_NODE(t)]]></c></tag>
- <item/>
- <tag><c><![CDATA[ETERM *ERL_PID_NODE_UTF8(t)]]></c></tag>
- <item>The Node in pid <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_PID_NUMBER(t)]]></c></tag>
- <item>The sequence number in pid <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_PID_SERIAL(t)]]></c></tag>
- <item>The serial number in pid <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_PID_CREATION(t)]]></c></tag>
- <item>The creation number in pid <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_PORT_NUMBER(t)]]></c></tag>
- <item>The sequence number in port <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_PORT_CREATION(t)]]></c></tag>
- <item>The creation number in port <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[ETERM *ERL_PORT_NODE(t)]]></c></tag>
- <item/>
- <tag><c><![CDATA[ETERM *ERL_PORT_NODE_UTF8(t)]]></c></tag>
- <item>The node in port <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_REF_NUMBER(t)]]></c></tag>
- <item>The first part of the reference number in ref <c><![CDATA[t]]></c>. Use
- only for compatibility.</item>
- <tag><c><![CDATA[int ERL_REF_NUMBERS(t)]]></c></tag>
- <item>Pointer to the array of reference numbers in ref <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_REF_LEN(t)]]></c></tag>
- <item>The number of used reference numbers in ref <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_REF_CREATION(t)]]></c></tag>
- <item>The creation number in ref <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[int ERL_TUPLE_SIZE(t)]]></c></tag>
- <item>The number of elements in tuple <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[ETERM *ERL_CONS_HEAD(t)]]></c></tag>
- <item>The head element of list <c><![CDATA[t]]></c>.</item>
- <tag><c><![CDATA[ETERM *ERL_CONS_TAIL(t)]]></c></tag>
- <item>A List representing the tail elements of list <c><![CDATA[t]]></c>.</item>
+ <tag><c>char *ERL_ATOM_PTR(t)</c></tag>
+ <item></item>
+ <tag><c>char *ERL_ATOM_PTR_UTF8(t)</c></tag>
+ <item>A string representing atom <c>t</c>.</item>
+ <tag><c>int ERL_ATOM_SIZE(t)</c></tag>
+ <item></item>
+ <tag><c>int ERL_ATOM_SIZE_UTF8(t)</c></tag>
+ <item>The length (in bytes) of atom <c>t</c>.</item>
+ <tag><c>void *ERL_BIN_PTR(t)</c></tag>
+ <item>A pointer to the contents of <c>t</c>.</item>
+ <tag><c>int ERL_BIN_SIZE(t)</c></tag>
+ <item>The length (in bytes) of binary object <c>t</c>.</item>
+ <tag><c>int ERL_INT_VALUE(t)</c></tag>
+ <item>The integer of <c>t</c>.</item>
+ <tag><c>unsigned int ERL_INT_UVALUE(t)</c></tag>
+ <item>The unsigned integer value of <c>t</c>.</item>
+ <tag><c>double ERL_FLOAT_VALUE(t)</c></tag>
+ <item>The floating point value of <c>t</c>.</item>
+ <tag><c>ETERM *ERL_PID_NODE(t)</c></tag>
+ <item></item>
+ <tag><c>ETERM *ERL_PID_NODE_UTF8(t)</c></tag>
+ <item>The node in pid <c>t</c>.</item>
+ <tag><c>int ERL_PID_NUMBER(t)</c></tag>
+ <item>The sequence number in pid <c>t</c>.</item>
+ <tag><c>int ERL_PID_SERIAL(t)</c></tag>
+ <item>The serial number in pid <c>t</c>.</item>
+ <tag><c>int ERL_PID_CREATION(t)</c></tag>
+ <item>The creation number in pid <c>t</c>.</item>
+ <tag><c>int ERL_PORT_NUMBER(t)</c></tag>
+ <item>The sequence number in port <c>t</c>.</item>
+ <tag><c>int ERL_PORT_CREATION(t)</c></tag>
+ <item>The creation number in port <c>t</c>.</item>
+ <tag><c>ETERM *ERL_PORT_NODE(t)</c></tag>
+ <item></item>
+ <tag><c>ETERM *ERL_PORT_NODE_UTF8(t)</c></tag>
+ <item>The node in port <c>t</c>.</item>
+ <tag><c>int ERL_REF_NUMBER(t)</c></tag>
+ <item>The first part of the reference number in ref <c>t</c>.
+ Use only for compatibility.</item>
+ <tag><c>int ERL_REF_NUMBERS(t)</c></tag>
+ <item>Pointer to the array of reference numbers in ref
+ <c>t</c>.</item>
+ <tag><c>int ERL_REF_LEN(t)</c></tag>
+ <item>The number of used reference numbers in ref
+ <c>t</c>.</item>
+ <tag><c>int ERL_REF_CREATION(t)</c></tag>
+ <item>The creation number in ref <c>t</c>.</item>
+ <tag><c>int ERL_TUPLE_SIZE(t)</c></tag>
+ <item>The number of elements in tuple <c>t</c>.</item>
+ <tag><c>ETERM *ERL_CONS_HEAD(t)</c></tag>
+ <item>The head element of list <c>t</c>.</item>
+ <tag><c>ETERM *ERL_CONS_TAIL(t)</c></tag>
+ <item>A list representing the tail elements of list
+ <c>t</c>.</item>
</taglist>
</description>
+
<funcs>
<func>
<name><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name>
- <fsummary>Prepends a term to the head of a list.</fsummary>
+ <fsummary>Prepend a term to the head of a list.</fsummary>
<type>
<v>ETERM *head;</v>
<v>ETERM *tail;</v>
</type>
<desc>
- <p>This function concatenates two Erlang terms, prepending
- <c><![CDATA[head]]></c> onto <c><![CDATA[tail]]></c> and thereby creating a <c><![CDATA[cons]]></c> cell.
- To make a proper list, <c><![CDATA[tail]]></c> should always be a
- list or an empty list. Note that NULL is not a valid list.</p>
- <p><c><![CDATA[head]]></c> is the new term to be added.</p>
- <p><c><![CDATA[tail]]></c> is the existing list to which <c><![CDATA[head]]></c> will
- be concatenated.</p>
+ <p>Concatenates two Erlang terms, prepending <c>head</c>
+ onto <c>tail</c> and thereby creating a
+ <c>cons</c> cell.
+ To make a proper list, <c>tail</c> is always to be a list
+ or an empty list. Notice that <c>NULL</c> is not a valid list.</p>
+ <list type="bulleted">
+ <item><c>head</c> is the new term to be added.</item>
+ <item><c>tail</c> is the existing list to which
+ <c>head</c> is concatenated.</item>
+ </list>
<p>The function returns a new list.</p>
- <p><c><![CDATA[ERL_CONS_HEAD(list)]]></c> and <c><![CDATA[ERL_CONS_TAIL(list)]]></c>
+ <p><c>ERL_CONS_HEAD(list)</c> and
+ <c>ERL_CONS_TAIL(list)</c>
can be used to retrieve the head and tail components
- from the list. <c><![CDATA[erl_hd(list)]]></c> and <c><![CDATA[erl_tl(list)]]></c> will do
+ from the list. <c>erl_hd(list)</c> and
+ <c>erl_tl(list)</c> do
the same thing, but check that the argument really is a list.</p>
- <p>For example:</p>
+ <p><em>Example:</em></p>
<code type="none"><![CDATA[
ETERM *list,*anAtom,*anInt;
anAtom = erl_mk_atom("madonna");
@@ -165,79 +179,102 @@ erl_free_compound(list);
]]></code>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name>
- <fsummary>Creates a copy of an Erlang term</fsummary>
+ <fsummary>Create a copy of an Erlang term.</fsummary>
<type>
<v>ETERM *term;</v>
</type>
<desc>
- <p>This function creates and returns a copy of the Erlang term
- <c><![CDATA[term]]></c>.</p>
+ <p>Creates and returns a copy of the Erlang term
+ <c>term</c>.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name>
- <fsummary>Extracts an element from an Erlang tuple</fsummary>
+ <fsummary>Extract an element from an Erlang tuple.</fsummary>
<type>
<v>int position;</v>
<v>ETERM *tuple;</v>
</type>
<desc>
- <p>This function extracts a specified element from an Erlang
- tuple. </p>
- <p><c><![CDATA[position]]></c> specifies which element to retrieve from
- <c><![CDATA[tuple]]></c>. The elements are numbered starting from 1.</p>
- <p><c><![CDATA[tuple]]></c> is an Erlang term containing at least
- <c><![CDATA[position]]></c> elements.</p>
- <p>The function returns a new Erlang term corresponding to the
- requested element, or NULL if <c><![CDATA[position]]></c> was greater than
- the arity of <c><![CDATA[tuple]]></c>.</p>
+ <p>Extracts a specified element from an Erlang tuple.</p>
+ <list type="bulleted">
+ <item><c>position</c> specifies which element to retrieve
+ from <c>tuple</c>. The elements are numbered starting
+ from 1.</item>
+ <item><c>tuple</c> is an Erlang term containing at least
+ <c>position</c> elements.</item>
+ </list>
+ <p>Returns a new Erlang term corresponding to the requested element, or
+ <c>NULL</c> if <c>position</c> was greater
+ than the arity of <c>tuple</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name>
+ <fsummary>Extract the first element from a list.</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>Extracts the first element from a list.</p>
+ <p><c>list</c> is an Erlang term containing a list.</p>
+ <p>Returns an Erlang term corresponding to the head
+ head element in the list, or a <c>NULL</c> pointer if
+ <c>list</c> was not a list.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name>
- <fsummary>Initialization routine</fsummary>
+ <fsummary>Initialization routine.</fsummary>
<type>
<v>void *NULL;</v>
<v>int 0;</v>
</type>
<desc>
- <marker id="erl_init"></marker>
- <p>This function must be called before any of the others in
- the <c><![CDATA[erl_interface]]></c> library in order to initialize the
- library functions. The arguments must be specified as
- <c><![CDATA[erl_init(NULL,0)]]></c>.</p>
+ <p>This function must be called before any of the others in the
+ <c>Erl_Interface</c> library to initialize the
+ library functions. The arguments must be specified as
+ <c>erl_init(NULL,0)</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name>
- <fsummary>Extracts the first element from a list</fsummary>
+ <name><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name>
+ <fsummary>Return the length of an I/O list.</fsummary>
<type>
<v>ETERM *list;</v>
</type>
<desc>
- <p>Extracts the first element from a list.</p>
- <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p>
- <p>The function returns an Erlang term corresponding to the
- head element in the list, or a NULL pointer if <c><![CDATA[list]]></c> was
- not a list.</p>
+ <p>Returns the length of an I/O list.</p>
+ <p><c>list</c> is an Erlang term containing an I/O list.</p>
+ <p>Returns the length of <c>list</c>, or
+ <c>-1</c> if <c>list</c> is not an I/O list.</p>
+ <p>For the definition of an I/O list, see
+ <seealso marker="#erl_iolist_to_binary">
+ <c>erl_iolist_to_binary</c></seealso>.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name>
- <fsummary>Converts an IO list to a binary</fsummary>
+ <fsummary>Convert an I/O list to a binary.</fsummary>
<type>
<v>ETERM *list;</v>
</type>
<desc>
- <p>This function converts an IO list to a binary term.</p>
- <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p>
- <p>This function an Erlang binary term, or NULL if <c><![CDATA[list]]></c>
- was not an IO list. </p>
- <p>Informally, an IO list is a deep list of characters and
- binaries which can be sent to an Erlang port. In BNF, an IO
- list is formally defined as follows: </p>
+ <p>Converts an I/O list to a binary term.</p>
+ <p><c>list</c> is an Erlang term containing a list.</p>
+ <p>Returns an Erlang binary term, or <c>NULL</c> if
+ <c>list</c> was not an I/O list.</p>
+ <p>Informally, an I/O list is a deep list of characters and
+ binaries that can be sent to an Erlang port. In BNF, an I/O
+ list is formally defined as follows:</p>
<code type="none"><![CDATA[
iolist ::= []
| Binary
@@ -250,158 +287,164 @@ iohead ::= Binary
]]></code>
</desc>
</func>
+
<func>
<name><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name>
- <fsummary>Converts an IO list to a zero terminated string</fsummary>
+ <fsummary>Convert an I/O list to a <c>NULL</c>-terminated string.</fsummary>
<type>
<v>ETERM *list;</v>
</type>
<desc>
- <p>This function converts an IO list to a '\0' terminated C
- string. </p>
- <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. The IO
- list must not contain the integer 0, since C strings may not
+ <p>Converts an I/O list to a <c>NULL</c>-terminated C string.</p>
+ <p><c>list</c> is an Erlang term containing an I/O list.
+ The I/O list must not contain the integer 0, as C strings may not
contain this value except as a terminating marker.</p>
- <p>This function returns a pointer to a dynamically allocated
- buffer containing a string. If <c><![CDATA[list]]></c> is not an IO list,
- or if <c><![CDATA[list]]></c> contains the integer 0, NULL is returned. It
- is the caller's responsibility free the allocated buffer
- with <c><![CDATA[erl_free()]]></c>. </p>
- <p>Refer to <c><![CDATA[erl_iolist_to_binary()]]></c> for the definition of an
- IO list. </p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name>
- <fsummary>Return the length of an IO list</fsummary>
- <type>
- <v>ETERM *list;</v>
- </type>
- <desc>
- <p>Returns the length of an IO list.
- </p>
- <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. </p>
- <p>The function returns the length of <c><![CDATA[list]]></c>, or -1 if
- <c><![CDATA[list]]></c> is not an IO list.</p>
- <p>Refer to <c><![CDATA[erl_iolist_to_binary()]]></c> for the definition of
- an IO list. </p>
+ <p>Returns a pointer to a dynamically allocated
+ buffer containing a string. If <c>list</c> is not an I/O
+ list, or if <c>list</c> contains the integer 0,
+ <c>NULL</c> is returned. It
+ is the caller's responsibility to free the allocated buffer
+ with <c>erl_free()</c>.</p>
+ <p>For the definition of an I/O list, see
+ <seealso marker="#erl_iolist_to_binary">
+ <c>erl_iolist_to_binary</c></seealso>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_length(list)</nametext></name>
- <fsummary>Determines the length of a list</fsummary>
+ <fsummary>Determine the length of a list.</fsummary>
<type>
<v>ETERM *list;</v>
</type>
<desc>
<p>Determines the length of a proper list.</p>
- <p><c><![CDATA[list]]></c> is an Erlang term containing proper list. In a
- proper list, all tails except the last point to another list
+ <p><c>list</c> is an Erlang term containing a proper list.
+ In a proper list, all tails except the last point to another list
cell, and the last tail points to an empty list.</p>
- <p>Returns -1 if <c><![CDATA[list]]></c> is not a proper list.</p>
+ <p>Returns <c>-1</c> if <c>list</c> is not a proper
+ list.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name>
- <fsummary>Creates an atom</fsummary>
+ <fsummary>Create an atom.</fsummary>
<type>
<v>const char *string;</v>
</type>
<desc>
<p>Creates an atom.</p>
- <p><c><![CDATA[string]]></c> is the sequence of characters that will be
+ <p><c>string</c> is the sequence of characters that will be
used to create the atom.</p>
- <p>Returns an Erlang term containing an atom. Note that it is
- the callers responsibility to make sure that <c><![CDATA[string]]></c>
+ <p>Returns an Erlang term containing an atom. Notice that it is
+ the caller's responsibility to ensure that <c>string</c>
contains a valid name for an atom.</p>
- <p><c><![CDATA[ERL_ATOM_PTR(atom)]]></c> and <c><![CDATA[ERL_ATOM_PTR_UTF8(atom)]]></c>
- can be used to retrieve the atom name (as a null terminated string). <c><![CDATA[ERL_ATOM_SIZE(atom)]]></c>
- and <c><![CDATA[ERL_ATOM_SIZE_UTF8(atom)]]></c> returns the length of the atom name.</p>
- <note><p>Note that the UTF8 variants were introduced in Erlang/OTP releases R16
- and the string returned by <c>ERL_ATOM_PTR(atom)</c> was not null terminated on older releases.</p>
+ <p><c>ERL_ATOM_PTR(atom)</c> and
+ <c>ERL_ATOM_PTR_UTF8(atom)</c>
+ can be used to retrieve the atom name (as a <c>NULL</c>-terminated string).
+ <c>ERL_ATOM_SIZE(atom)</c>
+ and <c>ERL_ATOM_SIZE_UTF8(atom)</c> return the length
+ of the atom name.</p>
+ <note>
+ <p>The UTF-8 variants were introduced in Erlang/OTP R16 and the
+ string returned by <c>ERL_ATOM_PTR(atom)</c> was not
+ <c>NULL</c>-terminated on older releases.</p>
</note>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name>
- <fsummary>Creates a binary object</fsummary>
+ <fsummary>Create a binary object.</fsummary>
<type>
<v>char *bptr;</v>
<v>int size;</v>
</type>
<desc>
- <p>This function produces an Erlang binary object from a
+ <p>Produces an Erlang binary object from a
buffer containing a sequence of bytes.</p>
- <p><c><![CDATA[bptr]]></c> is a pointer to a buffer containing data to be converted.</p>
- <p><c><![CDATA[size]]></c> indicates the length of <c><![CDATA[bptr]]></c>.</p>
- <p>The function returns an Erlang binary object.</p>
- <p><c><![CDATA[ERL_BIN_PTR(bin)]]></c> retrieves a pointer to
- the binary data. <c><![CDATA[ERL_BIN_SIZE(bin)]]></c> retrieves the
- size. </p>
+ <list type="bulleted">
+ <item><c>bptr</c> is a pointer to a buffer containing
+ data to be converted.</item>
+ <item><c>size</c> indicates the length of
+ <c>bptr</c>.</item>
+ </list>
+ <p>Returns an Erlang binary object.</p>
+ <p><c>ERL_BIN_PTR(bin)</c> retrieves a pointer to
+ the binary data. <c>ERL_BIN_SIZE(bin)</c> retrieves the
+ size.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name>
- <fsummary>Creates an empty Erlang list</fsummary>
+ <fsummary>Create an empty Erlang list.</fsummary>
<desc>
- <p>This function creates and returns an empty Erlang list.
- Note that NULL is not used to represent an empty list;
+ <p>Creates and returns an empty Erlang list.
+ Notice that <c>NULL</c> is not used to represent an empty list;
Use this function instead.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name>
- <fsummary>Creates an Erlang string</fsummary>
+ <fsummary>Create an Erlang string.</fsummary>
<type>
<v>char *string;</v>
<v>int len;</v>
</type>
<desc>
- <p>This function creates a list from a sequence of bytes.</p>
- <p><c><![CDATA[string]]></c> is a buffer containing a sequence of
- bytes. The buffer does not need to be zero-terminated.</p>
- <p><c><![CDATA[len]]></c> is the length of <c><![CDATA[string]]></c>.</p>
- <p>The function returns an Erlang list object corresponding to
- the character sequence in <c><![CDATA[string]]></c>.</p>
+ <p>Creates a list from a sequence of bytes.</p>
+ <list type="bulleted">
+ <item><c>string</c> is a buffer containing a sequence of
+ bytes. The buffer does not need to be <c>NULL</c>-terminated.</item>
+ <item><c>len</c> is the length of
+ <c>string</c>.</item>
+ </list>
+ <p>Returns an Erlang list object corresponding to
+ the character sequence in <c>string</c>.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name>
- <fsummary>Creates an Erlang float</fsummary>
+ <fsummary>Create an Erlang float.</fsummary>
<type>
<v>double f;</v>
</type>
<desc>
<p>Creates an Erlang float.</p>
- <p><c><![CDATA[f]]></c> is a value to be converted to an Erlang float.</p>
- <p></p>
- <p>The function returns an Erlang float object with the value
- specified in <c><![CDATA[f]]></c> or <c><![CDATA[NULL]]></c> if
- <c><![CDATA[f]]></c> is not finite.
- </p>
- <p><c><![CDATA[ERL_FLOAT_VALUE(t)]]></c> can be used to retrieve the
- value from an Erlang float.</p>
+ <p><c>f</c> is a value to be converted to an Erlang
+ float.</p>
+ <p>Returns an Erlang float object with the value
+ specified in <c>f</c> or <c>NULL</c> if
+ <c>f</c> is not finite.</p>
+ <p><c>ERL_FLOAT_VALUE(t)</c> can be used to retrieve the
+ value from an Erlang float.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name>
- <fsummary>Creates an Erlang integer</fsummary>
+ <fsummary>Create an Erlang integer.</fsummary>
<type>
<v>int n;</v>
</type>
<desc>
<p>Creates an Erlang integer.</p>
- <p><c><![CDATA[n]]></c> is a value to be converted to an Erlang integer.</p>
- <p></p>
- <p>The function returns an Erlang integer object with the
- value specified in <c><![CDATA[n]]></c>.</p>
- <p><c><![CDATA[ERL_INT_VALUE(t)]]></c> can be used to retrieve the value
+ <p><c>n</c> is a value to be converted to an Erlang
+ integer.</p>
+ <p>Returns an Erlang integer object with the
+ value specified in <c>n</c>.</p>
+ <p><c>ERL_INT_VALUE(t)</c> can be used to retrieve the
value from an Erlang integer.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name>
- <fsummary>Creates a list from an array</fsummary>
+ <fsummary>Create a list from an array.</fsummary>
<type>
<v>ETERM **array;</v>
<v>int arrsize;</v>
@@ -409,280 +452,316 @@ iohead ::= Binary
<desc>
<p>Creates an Erlang list from an array of Erlang terms, such
that each element in the list corresponds to one element in
- the array. </p>
- <p><c><![CDATA[array]]></c> is an array of Erlang terms.</p>
- <p><c><![CDATA[arrsize]]></c> is the number of elements in <c><![CDATA[array]]></c>.</p>
+ the array.</p>
+ <list type="bulleted">
+ <item><c>array</c> is an array of Erlang terms.</item>
+ <item><c>arrsize</c> is the number of elements in
+ <c>array</c>.</item>
+ </list>
<p>The function creates an Erlang list object, whose length
- <c><![CDATA[arrsize]]></c> and whose elements are taken from the terms in
- <c><![CDATA[array]]></c>.</p>
+ <c>arrsize</c> and whose elements are taken from the
+ terms in <c>array</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name>
- <fsummary>Creates a process identifier</fsummary>
+ <name><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name>
+ <fsummary>Create an Erlang reference.</fsummary>
<type>
<v>const char *node;</v>
- <v>unsigned int number;</v>
- <v>unsigned int serial;</v>
+ <v>unsigned int n1, n2, n3;</v>
<v>unsigned int creation;</v>
</type>
<desc>
- <p>This function creates an Erlang process identifier. The
- resulting pid can be used by Erlang processes wishing to
- communicate with the C node.</p>
- <p><c><![CDATA[node]]></c> is the name of the C node.</p>
- <p><c><![CDATA[number]]></c>, <c><![CDATA[serial]]></c> and <c><![CDATA[creation]]></c> are
- arbitrary numbers. Note though, that these are limited in
- precision, so only the low 15, 3 and 2 bits of these numbers
- are actually used.</p>
- <p>The function returns an Erlang pid object.</p>
- <p><c><![CDATA[ERL_PID_NODE(pid)]]></c>, <c><![CDATA[ERL_PID_NUMBER(pid)]]></c>,
- <c><![CDATA[ERL_PID_SERIAL(pid)]]></c> and <c><![CDATA[ERL_PID_CREATION(pid)]]></c>
- can be used to retrieve the four values used to create the pid.</p>
+ <p>Creates an Erlang reference, with 82 bits.</p>
+ <list type="bulleted">
+ <item><c>node</c> is the name of the C-node.</item>
+ <item><c>n1</c>, <c>n2</c>, and
+ <c>n3</c> can be seen as one big number
+ <c>n1*2^64+n2*2^32+n3</c>, which is to be chosen
+ uniquely for each reference created for a given C-node.</item>
+ <item><c>creation</c> is an arbitrary number.</item>
+ </list>
+ <p>Notice that <c>n3</c> and <c>creation</c>
+ are limited in precision, so only the low 18 and 2 bits of these
+ numbers are used.</p>
+ <p>Returns an Erlang reference object.</p>
+ <p><c>ERL_REF_NODE(ref)</c>,
+ <c>ERL_REF_NUMBERS(ref)</c>,
+ <c>ERL_REF_LEN(ref)</c>, and
+ <c>ERL_REF_CREATION(ref)</c> can be used to retrieve the
+ values used to create the reference.</p>
</desc>
</func>
+
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name>
- <fsummary>Creates a port identifier</fsummary>
+ <name><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name>
+ <fsummary>Create a process identifier.</fsummary>
<type>
<v>const char *node;</v>
<v>unsigned int number;</v>
+ <v>unsigned int serial;</v>
<v>unsigned int creation;</v>
</type>
<desc>
- <p>This function creates an Erlang port identifier. </p>
- <p><c><![CDATA[node]]></c> is the name of the C node.</p>
- <p><c><![CDATA[number]]></c> and <c><![CDATA[creation]]></c> are arbitrary numbers.
- Note though, that these are limited in
- precision, so only the low 18 and 2 bits of these numbers
- are actually used.</p>
- <p>The function returns an Erlang port object.</p>
- <p><c><![CDATA[ERL_PORT_NODE(port)]]></c>, <c><![CDATA[ERL_PORT_NUMBER(port)]]></c>
- and <c><![CDATA[ERL_PORT_CREATION]]></c> can be used to retrieve the three
- values used to create the port. </p>
+ <p>Creates an Erlang process identifier (pid). The
+ resulting pid can be used by Erlang processes wishing to
+ communicate with the C-node.</p>
+ <list type="bulleted">
+ <item><c>node</c> is the name of the C-node.</item>
+ <item><c>number</c>, <c>serial</c>, and
+ <c>creation</c> are
+ arbitrary numbers. Notice that these are limited in
+ precision, so only the low 15, 3, and 2 bits of these numbers
+ are used.</item>
+ </list>
+ <p>Returns an Erlang pid object.</p>
+ <p><c>ERL_PID_NODE(pid)</c>,
+ <c>ERL_PID_NUMBER(pid)</c>,
+ <c>ERL_PID_SERIAL(pid)</c>, and
+ <c>ERL_PID_CREATION(pid)</c>
+ can be used to retrieve the four values used to create the pid.</p>
</desc>
</func>
+
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name>
- <fsummary>Creates an old Erlang reference</fsummary>
+ <name><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name>
+ <fsummary>Create a port identifier.</fsummary>
<type>
<v>const char *node;</v>
<v>unsigned int number;</v>
<v>unsigned int creation;</v>
</type>
<desc>
- <p>This function creates an old Erlang reference, with
- only 18 bits - use <c><![CDATA[erl_mk_long_ref]]></c> instead.</p>
- <p><c><![CDATA[node]]></c> is the name of the C node.</p>
- <p><c><![CDATA[number]]></c> should be chosen uniquely for each reference
- created for a given C node.</p>
- <p><c><![CDATA[creation]]></c> is an arbitrary number.</p>
- <p>Note that <c><![CDATA[number]]></c> and <c><![CDATA[creation]]></c> are limited in
- precision, so only the low 18 and 2 bits of these numbers
- are actually used.
- </p>
- <p>The function returns an Erlang reference object.</p>
- <p><c><![CDATA[ERL_REF_NODE(ref)]]></c>, <c><![CDATA[ERL_REF_NUMBER(ref)]]></c>, and
- <c><![CDATA[ERL_REF_CREATION(ref)]]></c> to retrieve the three values used
- to create the reference. </p>
+ <p>Creates an Erlang port identifier.</p>
+ <list type="bulleted">
+ <item><c>node</c> is the name of the C-node.</item>
+ <item><c>number</c> and <c>creation</c> are
+ arbitrary numbers. Notice that these are limited in
+ precision, so only the low 18 and 2 bits of these numbers
+ are used.</item>
+ </list>
+ <p>Returns an Erlang port object.</p>
+ <p><c>ERL_PORT_NODE(port)</c>,
+ <c>ERL_PORT_NUMBER(port)</c>,
+ and <c>ERL_PORT_CREATION</c> can be used to retrieve the
+ three values used to create the port.</p>
</desc>
</func>
+
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name>
- <fsummary>Creates an Erlang reference</fsummary>
+ <name><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name>
+ <fsummary>Create an old Erlang reference.</fsummary>
<type>
<v>const char *node;</v>
- <v>unsigned int n1, n2, n3;</v>
+ <v>unsigned int number;</v>
<v>unsigned int creation;</v>
</type>
<desc>
- <p>This function creates an Erlang reference, with 82 bits.</p>
- <p><c><![CDATA[node]]></c> is the name of the C node.</p>
- <p><c><![CDATA[n1]]></c>, <c><![CDATA[n2]]></c> and <c><![CDATA[n3]]></c> can be seen as one big number
- <c><![CDATA[n1*2^64+n2*2^32+n3]]></c> which should be chosen uniquely for
- each reference
- created for a given C node.</p>
- <p><c><![CDATA[creation]]></c> is an arbitrary number.</p>
- <p>Note that <c><![CDATA[n3]]></c> and <c><![CDATA[creation]]></c> are limited in
- precision, so only the low 18 and 2 bits of these numbers
- are actually used.
- </p>
- <p>The function returns an Erlang reference object.</p>
- <p><c><![CDATA[ERL_REF_NODE(ref)]]></c>, <c><![CDATA[ERL_REF_NUMBERS(ref)]]></c>,
- <c><![CDATA[ERL_REF_LEN(ref)]]></c> and
- <c><![CDATA[ERL_REF_CREATION(ref)]]></c> to retrieve the values used
- to create the reference. </p>
+ <p>Creates an old Erlang reference, with
+ only 18 bits - use <c>erl_mk_long_ref</c> instead.</p>
+ <list type="bulleted">
+ <item><c>node</c> is the name of the C-node.</item>
+ <item><c>number</c> is to be chosen uniquely for each
+ reference created for a given C-node.</item>
+ <item><c>creation</c> is an arbitrary number.</item>
+ </list>
+ <p>Notice that <c>number</c> and <c>creation</c>
+ are limited in precision, so only the low 18 and 2 bits of these
+ numbers are used.</p>
+ <p>Returns an Erlang reference object.</p>
+ <p><c>ERL_REF_NODE(ref)</c>,
+ <c>ERL_REF_NUMBER(ref)</c>, and
+ <c>ERL_REF_CREATION(ref)</c> can be used to retrieve the
+ three values used to create the reference.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name>
- <fsummary>Creates a string</fsummary>
+ <fsummary>Create a string.</fsummary>
<type>
<v>char *string;</v>
</type>
<desc>
- <p>This function creates a list from a zero terminated string.</p>
- <p><c><![CDATA[string]]></c> is the zero-terminated sequence of characters
- (i.e. a C string) from which the list will be created.</p>
- <p>The function returns an Erlang list.</p>
+ <p>Creates a list from a <c>NULL</c>-terminated string.</p>
+ <p><c>string</c> is a <c>NULL</c>-terminated sequence of
+ characters
+ (that is, a C string) from which the list will be created.</p>
+ <p>Returns an Erlang list.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name>
- <fsummary>Creates an Erlang tuple from an array</fsummary>
+ <fsummary>Create an Erlang tuple from an array.</fsummary>
<type>
<v>ETERM **array;</v>
<v>int arrsize;</v>
</type>
<desc>
<p>Creates an Erlang tuple from an array of Erlang terms.</p>
- <p><c><![CDATA[array]]></c> is an array of Erlang terms.</p>
- <p><c><![CDATA[arrsize]]></c> is the number of elements in <c><![CDATA[array]]></c>.</p>
+ <list type="bulleted">
+ <item><c>array</c> is an array of Erlang terms.</item>
+ <item><c>arrsize</c> is the number of elements in
+ <c>array</c>.</item>
+ </list>
<p>The function creates an Erlang tuple, whose arity is
- <c><![CDATA[size]]></c> and whose elements are taken from the terms in
- <c><![CDATA[array]]></c>.</p>
- <p>To retrieve the size of a tuple, either use the
- <c><![CDATA[erl_size]]></c> function (which checks the type of the checked
- term and works for a binary as well as for a tuple), or the
- <c><![CDATA[ERL_TUPLE_SIZE(tuple)]]></c> returns the arity of a tuple.
- <c><![CDATA[erl_size()]]></c> will do the same thing, but it checks that
- the argument really is a tuple.
- <c><![CDATA[erl_element(index,tuple)]]></c> returns the element
- corresponding to a given position in the tuple. </p>
+ <c>size</c> and whose elements are taken from the terms
+ in <c>array</c>.</p>
+ <p>To retrieve the size of a tuple, either use function
+ <c>erl_size</c> (which checks the type of the
+ checked term and works for a binary as well as for a tuple) or
+ <c>ERL_TUPLE_SIZE(tuple)</c> returns the arity of a tuple.
+ <c>erl_size()</c> does the same thing, but it checks
+ that the argument is a tuple.
+ <c>erl_element(index,tuple)</c> returns the element
+ corresponding to a given position in the tuple.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name>
- <fsummary>Creates an unsigned integer</fsummary>
+ <fsummary>Create an unsigned integer.</fsummary>
<type>
<v>unsigned int n;</v>
</type>
<desc>
<p>Creates an Erlang unsigned integer.</p>
- <p><c><![CDATA[n]]></c> is a value to be converted to an Erlang
+ <p><c>n</c> is a value to be converted to an Erlang
unsigned integer.</p>
- <p></p>
- <p>The function returns an Erlang unsigned integer object with
- the value specified in <c><![CDATA[n]]></c>.</p>
- <p><c><![CDATA[ERL_INT_UVALUE(t)]]></c> can be used to retrieve the
+ <p>Returns an Erlang unsigned integer object with
+ the value specified in <c>n</c>.</p>
+ <p><c>ERL_INT_UVALUE(t)</c> can be used to retrieve the
value from an Erlang unsigned integer.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name>
- <fsummary>Creates an Erlang variable</fsummary>
+ <fsummary>Create an Erlang variable.</fsummary>
<type>
<v>char *name;</v>
</type>
<desc>
- <p>This function creates an unbound Erlang variable. The
- variable can later be bound through pattern matching or assignment.</p>
- <p><c><![CDATA[name]]></c> specifies a name for the variable.</p>
- <p>The function returns an Erlang variable object with the
- name <c><![CDATA[name]]></c>. </p>
+ <p>Creates an unbound Erlang variable. The variable can later be bound
+ through pattern matching or assignment.</p>
+ <p><c>name</c> specifies a name for the variable.</p>
+ <p>Returns an Erlang variable object with the
+ name <c>name</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name>
- <fsummary>Prints an Erlang term</fsummary>
+ <fsummary>Print an Erlang term.</fsummary>
<type>
<v>FILE *stream;</v>
<v>ETERM *term;</v>
</type>
<desc>
- <p>This function prints the specified Erlang term to the given
- output stream.</p>
- <p><c><![CDATA[stream]]></c> indicates where the function should send its
- output.</p>
- <p><c><![CDATA[term]]></c> is the Erlang term to print.</p>
- <p>The function returns the number of characters written, or a
- negative value if there was an error.</p>
+ <p>Prints the specified Erlang term to the specified output stream.</p>
+ <list type="bulleted">
+ <item><c>stream</c> indicates where the function is to
+ send its output.</item>
+ <item><c>term</c> is the Erlang term to print.</item>
+ </list>
+ <p>Returns the number of characters written on success, otherwise a
+ negative value.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name>
- <fsummary>Set the erl_interface library in compatibility mode</fsummary>
+ <fsummary>Set the Erl_Interface library in compatibility mode.</fsummary>
<type>
<v>unsigned release_number;</v>
</type>
<desc>
- <marker id="erl_set_compat_rel"></marker>
- <p>By default, the <c><![CDATA[erl_interface]]></c> library is only guaranteed
- to be compatible with other Erlang/OTP components from the same
- release as the <c><![CDATA[erl_interface]]></c> library itself. For example,
- <c><![CDATA[erl_interface]]></c> from the OTP R10 release is not compatible
- with an Erlang emulator from the OTP R9 release by default.</p>
- <p>A call to <c><![CDATA[erl_set_compat_rel(release_number)]]></c> sets the
- <c><![CDATA[erl_interface]]></c> library in compatibility mode of release
- <c><![CDATA[release_number]]></c>. Valid range of <c><![CDATA[release_number]]></c>
+ <p>By default, the <c>Erl_Interface</c> library is only
+ guaranteed to be compatible with other Erlang/OTP components from the
+ same release as the <c>Erl_Interface</c> library itself.
+ For example, <c>Erl_Interface</c> from Erlang/OTP R10
+ is not compatible
+ with an Erlang emulator from Erlang/OTP R9 by default.</p>
+ <p>A call to <c>erl_set_compat_rel(release_number)</c> sets
+ the <c>Erl_Interface</c> library in compatibility mode of
+ release <c>release_number</c>. Valid range of
+ <c>release_number</c>
is [7, current release]. This makes it possible to
communicate with Erlang/OTP components from earlier releases.</p>
<note>
<p>If this function is called, it may only be called once
- directly after the call to the
- <seealso marker="#erl_init">erl_init()</seealso> function.</p>
+ directly after the call to function
+ <seealso marker="#erl_init">erl_init()</seealso>.</p>
</note>
<warning>
<p>You may run into trouble if this feature is used
- carelessly. Always make sure that all communicating
+ carelessly. Always ensure that all communicating
components are either from the same Erlang/OTP release, or
from release X and release Y where all components
from release Y are in compatibility mode of release X.</p>
</warning>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_size(term)</nametext></name>
- <fsummary>Return the arity of a tuple or binary</fsummary>
+ <fsummary>Return the arity of a tuple or binary.</fsummary>
<type>
<v>ETERM *term;</v>
</type>
<desc>
- <p>Returns the arity of an Erlang tuple, or the
- number of bytes in an Erlang binary object. </p>
- <p><c><![CDATA[term]]></c> is an Erlang tuple or an Erlang binary object.</p>
- <p>The function returns the size of <c><![CDATA[term]]></c> as described
- above, or -1 if <c><![CDATA[term]]></c> is not one of the two supported
- types. </p>
+ <p>Returns either the arity of an Erlang tuple or the
+ number of bytes in an Erlang binary object.</p>
+ <p><c>term</c> is an Erlang tuple or an Erlang binary
+ object.</p>
+ <p>Returns the size of <c>term</c> as described
+ above, or <c>-1</c> if <c>term</c> is not one of the two
+ supported types.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name>
- <fsummary>Extracts the tail from a list</fsummary>
+ <fsummary>Extract the tail from a list.</fsummary>
<type>
<v>ETERM *list;</v>
</type>
<desc>
<p>Extracts the tail from a list.</p>
- <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p>
- <p>The function returns an Erlang list corresponding to the
- original list minus the first element, or NULL pointer if
- <c><![CDATA[list]]></c> was not a list.</p>
+ <p><c>list</c> is an Erlang term containing a list.</p>
+ <p>Returns an Erlang list corresponding to the
+ original list minus the first element, or <c>NULL</c> pointer if
+ <c>list</c> was not a list.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name>
- <fsummary>Extracts the content of a variable</fsummary>
+ <fsummary>Extract the content of a variable.</fsummary>
<type>
<v>ETERM *term;</v>
<v>char *name;</v>
</type>
<desc>
- <p>This function returns the contents of the specified
- variable in an Erlang term.
- </p>
- <p><c><![CDATA[term]]></c> is an Erlang term. In order for this function
- to succeed, <c><![CDATA[term]]></c> must be an Erlang variable with the
- specified name, or it must be an Erlang list or tuple
- containing a variable with the specified name. Other Erlang
- types cannot contain variables.</p>
- <p><c><![CDATA[name]]></c> is the name of an Erlang variable.</p>
+ <p>Returns the contents of the specified variable in an Erlang term.</p>
+ <list type="bulleted">
+ <item><c>term</c> is an Erlang term. In order for this
+ function to succeed,
+ <c>term</c> must either be an Erlang variable with
+ the specified name, or it must be an Erlang list or tuple
+ containing a variable with the specified name. Other Erlang
+ types cannot contain variables.</item>
+ <item><c>name</c> is the name of an Erlang variable.
+ </item>
+ </list>
<p>Returns the Erlang object corresponding to the value of
- <c><![CDATA[name]]></c> in <c><![CDATA[term]]></c>. If no variable with the name
- <c><![CDATA[name]]></c> was found in <c><![CDATA[term]]></c>, or if <c><![CDATA[term]]></c> is
- not a valid Erlang term, NULL is returned.</p>
+ <c>name</c> in <c>term</c>. If no variable
+ with the name <c>name</c> is found in
+ <c>term</c>, or if <c>term</c> is
+ not a valid Erlang term, <c>NULL</c> is returned.</p>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml
index 6e3ac4f0c9..5b8b7b5e78 100644
--- a/lib/erl_interface/doc/src/erl_format.xml
+++ b/lib/erl_interface/doc/src/erl_format.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_format</title>
@@ -28,51 +28,42 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>961016</date>
+ <date>1996-10-16</date>
<rev>A</rev>
- <file>erl_format.sgml</file>
+ <file>erl_format.xml</file>
</header>
<lib>erl_format</lib>
- <libsummary>Create and Match Erlang Terms</libsummary>
+ <libsummary>Create and match Erlang terms.</libsummary>
<description>
- <p>This module contains two routines - one general function for
+ <p>This module contains two routines: one general function for
creating Erlang terms and one for pattern matching Erlang terms.</p>
</description>
+
<funcs>
<func>
- <name><ret>ETERM *</ret><nametext>erl_format(FormatStr, ... )</nametext></name>
- <fsummary>Creates an Erlang term</fsummary>
+ <name><ret>ETERM *</ret><nametext>erl_format(FormatStr, ...)</nametext></name>
+ <fsummary>Create an Erlang term.</fsummary>
<type>
<v>char *FormatStr;</v>
</type>
<desc>
- <p>This is a general function for creating Erlang terms using
+ <p>A general function for creating Erlang terms using
a format specifier and a corresponding set of arguments, much
- in the way <c><![CDATA[printf()]]></c> works.</p>
- <p><c><![CDATA[FormatStr]]></c> is a format specification string. The set
- of valid format specifiers is as follows:</p>
+ in the way <c>printf()</c> works.</p>
+ <p><c>FormatStr</c> is a format specification string.
+ The valid format specifiers are as follows:</p>
<list type="bulleted">
- <item>
- <p>~i - Integer</p>
- </item>
- <item>
- <p>~f - Floating point</p>
- </item>
- <item>
- <p>~a - Atom</p>
- </item>
- <item>
- <p>~s - String</p>
- </item>
- <item>
- <p>~w - Arbitrary Erlang term</p>
- </item>
+ <item><c>~i</c> - Integer</item>
+ <item><c>~f</c> - Floating point</item>
+ <item><c>~a</c> - Atom</item>
+ <item><c>~s</c> - String</item>
+ <item><c>~w</c> - Arbitrary Erlang term</item>
</list>
- <p>For each format specifier that appears in <c><![CDATA[FormatStr]]></c>,
+ <p>For each format specifier included in <c>FormatStr</c>,
there must be a corresponding argument following
- <c><![CDATA[FormatStr]]></c>. An Erlang term is built according to the
- <c><![CDATA[FormatStr]]></c> with values and Erlang terms substituted from
- the corresponding arguments and according to the individual
+ <c>FormatStr</c>. An Erlang term is built according to
+ <c>FormatStr</c> with values and Erlang terms substituted
+ from the corresponding arguments, and according to the individual
format specifiers. For example:</p>
<code type="none"><![CDATA[
erl_format("[{name,~a},{age,~i},{data,~w}]",
@@ -80,34 +71,40 @@ erl_format("[{name,~a},{age,~i},{data,~w}]",
21,
erl_format("[{adr,~s,~i}]","E-street",42));
]]></code>
- <p>This will create an <c><![CDATA[(ETERM *)]]></c> structure corresponding
- to the Erlang term:
- <c><![CDATA[[{name,madonna},{age,21},{data,[{adr,"E-street",42}]}]]]></c></p>
- <p>The function returns an Erlang term, or NULL if
- <c><![CDATA[FormatStr]]></c> does not describe a valid Erlang term.</p>
+ <p>This creates an <c>(ETERM *)</c> structure corresponding
+ to the Erlang term
+ <c>[{name,madonna},{age,21},{data,[{adr,"E-street",42}]}]</c></p>
+ <p>The function returns an Erlang term, or <c>NULL</c> if
+ <c>FormatStr</c> does not describe a valid Erlang
+ term.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name>
- <fsummary>Performs pattern matching</fsummary>
+ <fsummary>Perform pattern matching.</fsummary>
<type>
<v>ETERM *Pattern,*Term;</v>
</type>
<desc>
<p>This function is used to perform pattern matching similar
- to that done in Erlang. Refer to an Erlang manual for matching
- rules and more examples.</p>
- <p><c><![CDATA[Pattern]]></c> is an Erlang term, possibly containing unbound
- variables. </p>
- <p><c><![CDATA[Term]]></c> is an Erlang term that we wish to match against
- <c><![CDATA[Pattern]]></c>.</p>
- <p><c><![CDATA[Term]]></c> and <c><![CDATA[Pattern]]></c> are compared, and any
- unbound variables in <c><![CDATA[Pattern]]></c> are bound to corresponding
- values in <c><![CDATA[Term]]></c>. </p>
- <p>If <c><![CDATA[Term]]></c> and <c><![CDATA[Pattern]]></c> can be matched, the
- function returns a non-zero value and binds any unbound
- variables in <c><![CDATA[Pattern]]></c>. If <c><![CDATA[Term]]></c> <c><![CDATA[Pattern]]></c> do
- not match, the function returns 0. For example:</p>
+ to that done in Erlang. For matching rules and more examples, see
+ section <seealso marker="doc/reference_manual:patterns">
+ Pattern Matching</seealso> in the Erlang Reference Manual.</p>
+ <list type="bulleted">
+ <item><c>Pattern</c> is an Erlang term, possibly
+ containing unbound variables.</item>
+ <item><c>Term</c> is an Erlang term that we wish to match
+ against <c>Pattern</c>.</item>
+ </list>
+ <p><c>Term</c> and <c>Pattern</c> are compared
+ and any unbound variables in <c>Pattern</c> are bound to
+ corresponding values in <c>Term</c>.</p>
+ <p>If <c>Term</c> and <c>Pattern</c> can be
+ matched, the function returns a non-zero value and binds any unbound
+ variables in <c>Pattern</c>. If <c>Term</c>
+ and <c>Pattern</c> do
+ not match, <c>0</c> is returned. For example:</p>
<code type="none"><![CDATA[
ETERM *term, *pattern, *pattern2;
term1 = erl_format("{14,21}");
@@ -132,11 +129,10 @@ if (erl_match(pattern2, term2)) {
...
}
]]></code>
- <p><c><![CDATA[erl_var_content()]]></c> can be used to retrieve the
+ <p><c>erl_var_content()</c> can be used to retrieve the
content of any variables bound as a result of a call to
- <c><![CDATA[erl_match()]]></c>.</p>
+ <c>erl_match()</c>.</p>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/doc/src/erl_global.xml b/lib/erl_interface/doc/src/erl_global.xml
index d6bfffc69d..2fa0045adf 100644
--- a/lib/erl_interface/doc/src/erl_global.xml
+++ b/lib/erl_interface/doc/src/erl_global.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_global</title>
@@ -28,115 +28,125 @@
<docno></docno>
<approved>Gordon Beaton</approved>
<checked>Gordon Beaton</checked>
- <date>980703</date>
+ <date>1998-07-03</date>
<rev>A</rev>
- <file>erl_global.sgml</file>
+ <file>erl_global.xml</file>
</header>
<lib>erl_global</lib>
- <libsummary>Access globally registered names</libsummary>
+ <libsummary>Access globally registered names.</libsummary>
<description>
<p>This module provides support for registering, looking
- up and unregistering names in the Erlang Global module. For more
- information, see the description of Global in the reference manual.</p>
- <p>Note that the functions below perform an RPC using an open file
- descriptor provided by the caller. This file descriptor must
- not be used for other traffic during the global operation or the
- function may receive unexpected data and fail.</p>
+ up, and unregistering names in the <c>global</c> module.
+ For more information, see
+ <seealso marker="kernel:global"><c>kernel:global</c></seealso>.</p>
+
+ <p>Notice that the functions below perform an RPC using an open file
+ descriptor provided by the caller. This file descriptor must
+ not be used for other traffic during the global operation, as the
+ function can then receive unexpected data and fail.</p>
</description>
+
<funcs>
<func>
<name><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name>
- <fsummary>Obtain list of Global names</fsummary>
+ <fsummary>Obtain list of global names.</fsummary>
<type>
<v>int fd;</v>
<v>int *count;</v>
</type>
<desc>
- <p>Retrieve a list of all known global names.
- </p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
- </p>
- <p><c><![CDATA[count]]></c> is the address of an integer, or NULL. If
- <c><![CDATA[count]]></c> is not NULL, it will be set by the function to
- the number of names found.
- </p>
+ <p>Retrieves a list of all known global names.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>count</c> is the address of an integer, or
+ <c>NULL</c>. If <c>count</c> is not <c>NULL</c>, it is
+ set by the function to the number of names found.</item>
+ </list>
<p>On success, the function returns an array of strings, each
- containing a single registered name, and sets <c><![CDATA[count]]></c> to
+ containing a single registered name, and sets
+ <c>count</c> to
the number of names found. The array is terminated
- by a single NULL pointer. On failure, the function returns
- NULL and <c><![CDATA[count]]></c> is not modified.
- </p>
+ by a single <c>NULL</c> pointer. On failure, the function returns
+ <c>NULL</c> and <c>count</c> is not modified.</p>
<note>
<p>It is the caller's responsibility to free the array
afterwards. It has been allocated by the function with a
- single call to <c><![CDATA[malloc()]]></c>, so a single <c><![CDATA[free()]]></c> is
- all that is necessary.</p>
+ single call to <c>malloc()</c>, so a single
+ <c>free()</c> is all that is necessary.</p>
</note>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name>
- <fsummary>Register a name in Global</fsummary>
+ <fsummary>Register a name in global.</fsummary>
<type>
<v>int fd;</v>
<v>const char *name;</v>
<v>ETERM *pid;</v>
</type>
<desc>
- <p>This function registers a name in Global.
- </p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
- </p>
- <p><c><![CDATA[name]]></c> is the name to register in Global.
- </p>
- <p><c><![CDATA[pid]]></c> is the pid that should be associated with
- <c><![CDATA[name]]></c>. This is the value that Global will return when
- processes request the location of <c><![CDATA[name]]></c>.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Registers a name in <c>global</c>.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>name</c> is the name to register in
+ <c>global</c>.</item>
+ <item><c>pid</c> is the pid that is to be associated with
+ <c>name</c>. This value is returned by <c>global</c>
+ when processes request the location of <c>name</c>.
+ </item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name>
- <fsummary>Unregister a name in Global</fsummary>
+ <fsummary>Unregister a name from global.</fsummary>
<type>
<v>int fd;</v>
<v>const char *name;</v>
</type>
<desc>
- <p>This function unregisters a name from Global.
- </p>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
- </p>
- <p><c><![CDATA[name]]></c> is the name to unregister from Global.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Unregisters a name from <c>global</c>.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>name</c> is the name to unregister from
+ <c>global</c>.</item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name>
- <fsummary>Look up a name in global</fsummary>
+ <fsummary>Look up a name in global.</fsummary>
<type>
<v>int fd;</v>
<v>const char *name;</v>
<v>char *node;</v>
</type>
<desc>
- <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
- </p>
- <p><c><![CDATA[name]]></c> is the name that is to be looked up in Global.
- </p>
- <p>If <c><![CDATA[node]]></c> is not NULL, it is a pointer to a buffer
- where the function can fill in the name of the node where
- <c><![CDATA[name]]></c> is found. <c><![CDATA[node]]></c> can be passed directly to
- <c><![CDATA[erl_connect()]]></c> if necessary.
- </p>
- <p>On success, the function returns an Erlang Pid containing the address
- of the given name, and node will be initialized to
- the nodename where <c><![CDATA[name]]></c> is found. On failure NULL will be
- returned and <c><![CDATA[node]]></c> will not be modified.</p>
+ <p>Looks up a name in <c>global</c>.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open descriptor to an Erlang
+ connection.</item>
+ <item><c>name</c> is the name that is to be looked up in
+ <c>global</c>.</item>
+ </list>
+ <p>If <c>node</c> is not <c>NULL</c>, it is a pointer to a
+ buffer where the function can fill in the name of the node where
+ <c>name</c> is found. <c>node</c> can be
+ passed directly to <c>erl_connect()</c> if necessary.</p>
+ <p>On success, the function returns an Erlang pid containing the address
+ of the specified name, and the node is initialized to
+ the node name where <c>name</c> is found. On failure,
+ <c>NULL</c> is returned and <c>node</c> is not
+ modified.</p>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/doc/src/erl_interface.xml b/lib/erl_interface/doc/src/erl_interface.xml
index a9d421bbeb..4e66655b39 100644
--- a/lib/erl_interface/doc/src/erl_interface.xml
+++ b/lib/erl_interface/doc/src/erl_interface.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>The Erl_Interface Library</title>
@@ -72,51 +72,51 @@ Eshell V4.7.4 (abort with ^G)
1> code:root_dir().
/usr/local/otp ]]></code>
<p>To compile your code, make sure that your C compiler knows where
- to find <c><![CDATA[erl_interface.h]]></c> by specifying an appropriate <c><![CDATA[-I]]></c>
- argument on the command line, or by adding it to the <c><![CDATA[CFLAGS]]></c>
- definition in your <c><![CDATA[Makefile]]></c>. The correct value for this path is
- <c><![CDATA[$OTPROOT/lib/erl_interface]]></c><em>Vsn</em><c><![CDATA[/include]]></c>, where <c><![CDATA[$OTPROOT]]></c> is the path
- reported by <c><![CDATA[code:root_dir/0]]></c> in the above example, and <em>Vsn</em> is
+ to find <c>erl_interface.h</c> by specifying an appropriate <c>-I</c>
+ argument on the command line, or by adding it to the <c>CFLAGS</c>
+ definition in your <c>Makefile</c>. The correct value for this path is
+ <c>$OTPROOT/lib/erl_interface</c><em>Vsn</em><c>/include</c>, where <c>$OTPROOT</c> is the path
+ reported by <c>code:root_dir/0</c> in the above example, and <em>Vsn</em> is
the version of the Erl_interface application, for example
- <c><![CDATA[erl_interface-3.2.3]]></c></p>
+ <c>erl_interface-3.2.3</c></p>
<code type="none"><![CDATA[
$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c ]]></code>
<p>When linking, you will need to specify the path to
- <c><![CDATA[liberl_interface.a]]></c> and <c><![CDATA[libei.a]]></c> with
- <c><![CDATA[-L$OTPROOT/lib/erl_interface-3.2.3/lib]]></c>, and you will need to specify the
- name of the libraries with <c><![CDATA[-lerl_interface -lei]]></c>. You can do
- this on the command line or by adding the flags to the <c><![CDATA[LDFLAGS]]></c>
- definition in your <c><![CDATA[Makefile]]></c>.</p>
+ <c>liberl_interface.a</c> and <c>libei.a</c> with
+ <c>-L$OTPROOT/lib/erl_interface-3.2.3/lib</c>, and you will need to specify the
+ name of the libraries with <c>-lerl_interface -lei</c>. You can do
+ this on the command line or by adding the flags to the <c>LDFLAGS</c>
+ definition in your <c>Makefile</c>.</p>
<code type="none"><![CDATA[
$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
lib myprog.o -lerl_interface -lei -o myprog ]]></code>
<p>Also, on some systems it may be necessary to link with some
- additional libraries (e.g. <c><![CDATA[libnsl.a]]></c> and <c><![CDATA[libsocket.a]]></c> on
- Solaris, or <c><![CDATA[wsock32.lib]]></c> on Windows) in order to use the
+ additional libraries (e.g. <c>libnsl.a</c> and <c>libsocket.a</c> on
+ Solaris, or <c>wsock32.lib</c> on Windows) in order to use the
communication facilities of Erl_Interface.</p>
<p>If you are using Erl_Interface functions in a threaded
application based on POSIX threads or Solaris threads, then
Erl_Interface needs access to some of the synchronization
facilities in your threads package, and you will need to specify
additional compiler flags in order to indicate which of the packages
- you are using. Define <c><![CDATA[_REENTRANT]]></c> and either <c><![CDATA[STHREADS]]></c> or
- <c><![CDATA[PTHREADS]]></c>. The default is to use POSIX threads if
- <c><![CDATA[_REENTRANT]]></c> is specified.</p>
+ you are using. Define <c>_REENTRANT</c> and either <c>STHREADS</c> or
+ <c>PTHREADS</c>. The default is to use POSIX threads if
+ <c>_REENTRANT</c> is specified.</p>
<p>Note that both single threaded and default versions of the Erl_interface
and Ei libraries are provided. (The single threaded versions are named
- <c><![CDATA[liberl_interface_st]]></c> and <c><![CDATA[libei_st]]></c>). Whether the default
+ <c>liberl_interface_st</c> and <c>libei_st</c>). Whether the default
versions of the libraries have support for threads or not is determined by if
the platform in question has support for POSIX or Solaris threads. To check this,
- have a look in the <c><![CDATA[eidefs.mk]]></c> file in the erl_interface src directory.</p>
+ have a look in the <c>eidefs.mk</c> file in the erl_interface src directory.</p>
</section>
<section>
<title>Initializing the erl_interface Library</title>
<p>Before calling any of the other Erl_Interface functions, you
- must call <c><![CDATA[erl_init()]]></c> exactly once to initialize the library.
- <c><![CDATA[erl_init()]]></c> takes two arguments, however the arguments are no
+ must call <c>erl_init()</c> exactly once to initialize the library.
+ <c>erl_init()</c> takes two arguments, however the arguments are no
longer used by Erl_Interface, and should therefore be specified
- as <c><![CDATA[erl_init(NULL,0)]]></c>.</p>
+ as <c>erl_init(NULL,0)</c>.</p>
</section>
<section>
@@ -129,7 +129,7 @@ $ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
number of C functions which create and manipulate Erlang data
structures. The library also contains an encode and a decode function.
The example below shows how to create and encode an Erlang tuple
- <c><![CDATA[{tobbe,3928}]]></c>:</p>
+ <c>{tobbe,3928}</c>:</p>
<code type="none"><![CDATA[
ETERM *arr[2], *tuple;
@@ -140,26 +140,26 @@ arr[0] = erl_mk_atom("tobbe");
arr[1] = erl_mk_integer(3928);
tuple = erl_mk_tuple(arr, 2);
i = erl_encode(tuple, buf); ]]></code>
- <p>Alternatively, you can use <c><![CDATA[erl_send()]]></c> and
- <c><![CDATA[erl_receive_msg]]></c>, which handle the encoding and decoding of
+ <p>Alternatively, you can use <c>erl_send()</c> and
+ <c>erl_receive_msg</c>, which handle the encoding and decoding of
messages transparently.</p>
<p>Refer to the Reference Manual for a complete description of the
following modules:</p>
<list type="bulleted">
- <item>the <c><![CDATA[erl_eterm]]></c> module for creating Erlang terms</item>
- <item>the <c><![CDATA[erl_marshal]]></c> module for encoding and decoding routines.</item>
+ <item>the <c>erl_eterm</c> module for creating Erlang terms</item>
+ <item>the <c>erl_marshal</c> module for encoding and decoding routines.</item>
</list>
</section>
<section>
<title>Building Terms and Patterns</title>
- <p>The previous example can be simplified by using
- <c><![CDATA[erl_format()]]></c> to create an Erlang term.</p>
+ <p>The previous example can be simplified by using
+ <c>erl_format()</c> to create an Erlang term.</p>
<code type="none"><![CDATA[
ETERM *ep;
ep = erl_format("{~a,~i}", "tobbe", 3928); ]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_format]]></c> module, for a
+ <p>Refer to the Reference Manual, the <c>erl_format</c> module, for a
full description of the different format directives. The following
example is more complex:</p>
<code type="none"><![CDATA[
@@ -171,10 +171,10 @@ ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
erl_format("[{adr,~s,~i}]", "E-street", 42));
erl_free_compound(ep); ]]></code>
<p>As in previous examples, it is your responsibility to free the
- memory allocated for Erlang terms. In this example,
- <c><![CDATA[erl_free_compound()]]></c> ensures that the complete term pointed to
- by <c><![CDATA[ep]]></c> is released. This is necessary, because the pointer from
- the second call to <c><![CDATA[erl_format()]]></c> is lost. </p>
+ memory allocated for Erlang terms. In this example,
+ <c>erl_free_compound()</c> ensures that the complete term pointed to
+ by <c>ep</c> is released. This is necessary, because the pointer from
+ the second call to <c>erl_format()</c> is lost. </p>
<p>The following
example shows a slightly different solution:</p>
<code type="none"><![CDATA[
@@ -186,7 +186,7 @@ ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
erl_free_term(ep);
erl_free_term(ep2); ]]></code>
<p>In this case, you free the two terms independently. The order in
- which you free the terms <c><![CDATA[ep]]></c> and <c><![CDATA[ep2]]></c> is not important,
+ which you free the terms <c>ep</c> and <c>ep2</c> is not important,
because the Erl_Interface library uses reference counting to
determine when it is safe to actually remove objects. </p>
<p>If you are not sure whether you have freed the terms properly, you
@@ -204,14 +204,14 @@ printf("length of freelist: %ld\
/* really free the freelist */
erl_eterm_release();
]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_malloc]]></c> module for more
+ <p>Refer to the Reference Manual, the <c>erl_malloc</c> module for more
information.</p>
</section>
<section>
<title>Pattern Matching</title>
<p>An Erlang pattern is a term that may contain unbound variables or
- <c><![CDATA["do not care"]]></c> symbols. Such a pattern can be matched against a
+ <c>"do not care"</c> symbols. Such a pattern can be matched against a
term and, if the match is successful, any unbound variables in the
pattern will be bound as a side effect. The content of a bound
variable can then be retrieved.</p>
@@ -219,13 +219,13 @@ erl_eterm_release();
ETERM *pattern;
pattern = erl_format("{madonna,Age,_}"); ]]></code>
- <p><c><![CDATA[erl_match()]]></c> is used to perform pattern matching. It takes a
+ <p><c>erl_match()</c> is used to perform pattern matching. It takes a
pattern and a term and tries to match them. As a side effect any unbound
variables in the pattern will be bound. In the following example, we
create a pattern with a variable <em>Age</em> which appears at two
positions in the tuple. The pattern match is performed as follows:</p>
<list type="ordered">
- <item><c><![CDATA[erl_match()]]></c> will bind the contents of
+ <item><c>erl_match()</c> will bind the contents of
<em>Age</em> to <em>21</em> the first time it reaches the variable</item>
<item>the second occurrence of <em>Age</em> will cause a test for
equality between the terms since <em>Age</em> is already bound to
@@ -248,14 +248,14 @@ if (erl_match(pattern, term)) {
}
erl_free_term(pattern);
erl_free_term(term); ]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_match()]]></c> function for
+ <p>Refer to the Reference Manual, the <c>erl_match()</c> function for
more information.</p>
</section>
<section>
<title>Connecting to a Distributed Erlang Node</title>
<p>In order to connect to a distributed Erlang node you need to first
- initialize the connection routine with <c><![CDATA[erl_connect_init()]]></c>,
+ initialize the connection routine with <c>erl_connect_init()</c>,
which stores information such as the host name, node name, and IP
address for later use:</p>
<code type="none"><![CDATA[
@@ -263,9 +263,9 @@ int identification_number = 99;
int creation=1;
char *cookie="a secret cookie string"; /* An example */
erl_connect_init(identification_number, cookie, creation); ]]></code>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information.</p>
+ <p>Refer to the Reference Manual, the <c>erl_connect</c> module for more information.</p>
<p>After initialization, you set up the connection to the Erlang node.
- Use <c><![CDATA[erl_connect()]]></c> to specify the Erlang node you want to
+ Use <c>erl_connect()</c> to specify the Erlang node you want to
connect to. The following example sets up the connection and should
result in a valid socket file descriptor:</p>
<code type="none"><![CDATA[
@@ -273,45 +273,45 @@ int sockfd;
char *nodename="[email protected]"; /* An example */
if ((sockfd = erl_connect(nodename)) < 0)
erl_err_quit("ERROR: erl_connect failed"); ]]></code>
- <p><c><![CDATA[erl_err_quit()]]></c> prints the specified string and terminates
- the program. Refer to the Reference Manual, the <c><![CDATA[erl_error()]]></c>
+ <p><c>erl_err_quit()</c> prints the specified string and terminates
+ the program. Refer to the Reference Manual, the <c>erl_error()</c>
function for more information.</p>
</section>
<section>
<title>Using EPMD</title>
- <p><c><![CDATA[Epmd]]></c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes
- register with <c><![CDATA[epmd]]></c> on the localhost to indicate to other nodes that
- they exist and can accept connections. <c><![CDATA[Epmd]]></c> maintains a register of
+ <p><c>Epmd</c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes
+ register with <c>epmd</c> on the localhost to indicate to other nodes that
+ they exist and can accept connections. <c>Epmd</c> maintains a register of
node and port number information, and when a node wishes to connect to
- another node, it first contacts <c><![CDATA[epmd]]></c> in order to find out the correct
+ another node, it first contacts <c>epmd</c> in order to find out the correct
port number to connect to.</p>
- <p>When you use <c><![CDATA[erl_connect()]]></c> to connect to an Erlang node, a
- connection is first made to <c><![CDATA[epmd]]></c> and, if the node is known, a
+ <p>When you use <c>erl_connect()</c> to connect to an Erlang node, a
+ connection is first made to <c>epmd</c> and, if the node is known, a
connection is then made to the Erlang node.</p>
- <p>C nodes can also register themselves with <c><![CDATA[epmd]]></c> if they want other
+ <p>C nodes can also register themselves with <c>epmd</c> if they want other
nodes in the system to be able to find and connect to them.</p>
- <p>Before registering with <c><![CDATA[epmd]]></c>, you need to first create a listen socket
+ <p>Before registering with <c>epmd</c>, you need to first create a listen socket
and bind it to a port. Then:</p>
<code type="none"><![CDATA[
int pub;
pub = erl_publish(port); ]]></code>
- <p><c><![CDATA[pub]]></c> is a file descriptor now connected to <c><![CDATA[epmd]]></c>. <c><![CDATA[Epmd]]></c>
+ <p><c>pub</c> is a file descriptor now connected to <c>epmd</c>. <c>Epmd</c>
monitors the other end of the connection, and if it detects that the
connection has been closed, the node will be unregistered. So, if you
explicitly close the descriptor or if your node fails, it will be
- unregistered from <c><![CDATA[epmd]]></c>.</p>
+ unregistered from <c>epmd</c>.</p>
<p>Be aware that on some systems (such as VxWorks), a failed node will
not be detected by this mechanism since the operating system does not
automatically close descriptors that were left open when the node
- failed. If a node has failed in this way, <c><![CDATA[epmd]]></c> will prevent you from
+ failed. If a node has failed in this way, <c>epmd</c> will prevent you from
registering a new node with the old name, since it thinks that the old
name is still in use. In this case, you must unregister the name
explicitly:</p>
<code type="none"><![CDATA[
erl_unpublish(node); ]]></code>
- <p>This will cause <c><![CDATA[epmd]]></c> to close the connection from the far end. Note
+ <p>This will cause <c>epmd</c> to close the connection from the far end. Note
that if the name was in fact still in use by a node, the results of
this operation are unpredictable. Also, doing this does not cause the
local end of the connection to close, so resources may be consumed.</p>
@@ -321,8 +321,8 @@ erl_unpublish(node); ]]></code>
<title>Sending and Receiving Erlang Messages</title>
<p>Use one of the following two functions to send messages:</p>
<list type="bulleted">
- <item><c><![CDATA[erl_send()]]></c></item>
- <item><c><![CDATA[erl_reg_send()]]></c></item>
+ <item><c>erl_send()</c></item>
+ <item><c>erl_reg_send()</c></item>
</list>
<p>As in Erlang, it is possible to send messages to a
<em>Pid</em> or to a registered name. It is easier to send a
@@ -330,17 +330,17 @@ erl_unpublish(node); ]]></code>
a suitable <em>Pid</em>.</p>
<p>Use one of the following two functions to receive messages:</p>
<list type="bulleted">
- <item><c><![CDATA[erl_receive()]]></c></item>
- <item><c><![CDATA[erl_receive_msg()]]></c></item>
+ <item><c>erl_receive()</c></item>
+ <item><c>erl_receive_msg()</c></item>
</list>
- <p><c><![CDATA[erl_receive()]]></c> receives the message into a buffer, while
- <c><![CDATA[erl_receive_msg()]]></c> decodes the message into an Erlang term. </p>
+ <p><c>erl_receive()</c> receives the message into a buffer, while
+ <c>erl_receive_msg()</c> decodes the message into an Erlang term. </p>
<section>
<title>Example of Sending Messages</title>
- <p>In the following example, <c><![CDATA[{Pid, hello_world}]]></c> is
- sent to a registered process <c><![CDATA[my_server]]></c>. The message is encoded
- by <c><![CDATA[erl_send()]]></c>:</p>
+ <p>In the following example, <c>{Pid, hello_world}</c> is
+ sent to a registered process <c>my_server</c>. The message is encoded
+ by <c>erl_send()</c>:</p>
<code type="none"><![CDATA[
extern const char *erl_thisnodename(void);
extern short erl_thiscreation(void);
@@ -355,15 +355,15 @@ emsg = erl_mk_tuple(arr, 2);
erl_reg_send(sockfd, "my_server", emsg);
erl_free_term(emsg); ]]></code>
<p>The first element of the tuple that is sent is your own
- <em>Pid</em>. This enables <c><![CDATA[my_server]]></c> to reply. Refer to the
- Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information
+ <em>Pid</em>. This enables <c>my_server</c> to reply. Refer to the
+ Reference Manual, the <c>erl_connect</c> module for more information
about send primitives.</p>
</section>
<section>
<title>Example of Receiving Messages</title>
- <p>In this example <c><![CDATA[{Pid, Something}]]></c> is received. The
- received Pid is then used to return <c><![CDATA[{goodbye,Pid}]]></c></p>
+ <p>In this example <c>{Pid, Something}</c> is received. The
+ received Pid is then used to return <c>{goodbye,Pid}</c></p>
<code type="none"><![CDATA[
ETERM *arr[2], *answer;
int sockfd,rc;
@@ -383,18 +383,18 @@ if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) {
<p>In order to provide robustness, a distributed Erlang node
occasionally polls all its connected neighbours in an attempt to
detect failed nodes or communication links. A node which receives such
- a message is expected to respond immediately with an <c><![CDATA[ERL_TICK]]></c> message.
- This is done automatically by <c><![CDATA[erl_receive()]]></c>, however when this
- has occurred <c><![CDATA[erl_receive]]></c> returns <c><![CDATA[ERL_TICK]]></c> to the caller
- without storing a message into the <c><![CDATA[ErlMessage]]></c> structure.</p>
+ a message is expected to respond immediately with an <c>ERL_TICK</c> message.
+ This is done automatically by <c>erl_receive()</c>, however when this
+ has occurred <c>erl_receive</c> returns <c>ERL_TICK</c> to the caller
+ without storing a message into the <c>ErlMessage</c> structure.</p>
<p>When a message has been received, it is the caller's responsibility
- to free the received message <c><![CDATA[emsg.msg]]></c> as well as <c><![CDATA[emsg.to]]></c>
- or <c><![CDATA[emsg.from]]></c>, depending on the type of message received.</p>
+ to free the received message <c>emsg.msg</c> as well as <c>emsg.to</c>
+ or <c>emsg.from</c>, depending on the type of message received.</p>
<p>Refer to the Reference Manual for additional information about the
following modules:</p>
<list type="bulleted">
- <item><c><![CDATA[erl_connect]]></c></item>
- <item><c><![CDATA[erl_eterm]]></c>.</item>
+ <item><c>erl_connect</c></item>
+ <item><c>erl_eterm</c>.</item>
</list>
</section>
</section>
@@ -421,12 +421,12 @@ if (!erl_match(ep, reply))
");
erl_free_term(ep);
erl_free_term(reply); ]]></code>
- <p><c><![CDATA[c:c/1]]></c> is called to compile the specified module on the
- remote node. <c><![CDATA[erl_match()]]></c> checks that the compilation was
- successful by testing for the expected <c><![CDATA[ok]]></c>.</p>
- <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for
- more information about <c><![CDATA[erl_rpc()]]></c>, and its companions
- <c><![CDATA[erl_rpc_to()]]></c> and <c><![CDATA[erl_rpc_from()]]></c>.</p>
+ <p><c>c:c/1</c> is called to compile the specified module on the
+ remote node. <c>erl_match()</c> checks that the compilation was
+ successful by testing for the expected <c>ok</c>.</p>
+ <p>Refer to the Reference Manual, the <c>erl_connect</c> module for
+ more information about <c>erl_rpc()</c>, and its companions
+ <c>erl_rpc_to()</c> and <c>erl_rpc_from()</c>.</p>
</section>
<section>
@@ -454,14 +454,14 @@ if (names)
",names[i]);
free(names); ]]></code>
- <p><c><![CDATA[erl_global_names()]]></c> allocates and returns a buffer containing
- all the names known to global. <c><![CDATA[count]]></c> will be initialized to
+ <p><c>erl_global_names()</c> allocates and returns a buffer containing
+ all the names known to global. <c>count</c> will be initialized to
indicate how many names are in the array. The array of strings in
names is terminated by a NULL pointer, so it is not necessary to use
- <c><![CDATA[count]]></c> to determine when the last name is reached.</p>
+ <c>count</c> to determine when the last name is reached.</p>
<p>It is the caller's responsibility to free the array.
- <c><![CDATA[erl_global_names()]]></c> allocates the array and all of the strings
- using a single call to <c><![CDATA[malloc()]]></c>, so <c><![CDATA[free(names)]]></c> is all
+ <c>erl_global_names()</c> allocates the array and all of the strings
+ using a single call to <c>malloc()</c>, so <c>free(names)</c> is all
that is necessary.</p>
<p>To look up one of the names:</p>
<code type="none"><![CDATA[
@@ -469,13 +469,13 @@ ETERM *pid;
char node[256];
pid = erl_global_whereis(fd,"schedule",node); ]]></code>
- <p>If <c><![CDATA["schedule"]]></c> is known to global, an Erlang pid is returned
+ <p>If <c>"schedule"</c> is known to global, an Erlang pid is returned
that can be used to send messages to the schedule service.
- Additionally, <c><![CDATA[node]]></c> will be initialized to contain the name of
+ Additionally, <c>node</c> will be initialized to contain the name of
the node where the service is registered, so that you can make a
- connection to it by simply passing the variable to <c><![CDATA[erl_connect()]]></c>.</p>
+ connection to it by simply passing the variable to <c>erl_connect()</c>.</p>
<p>Before registering a name, you should already have registered your
- port number with <c><![CDATA[epmd]]></c>. This is not strictly necessary, but if you
+ port number with <c>epmd</c>. This is not strictly necessary, but if you
neglect to do so, then other nodes wishing to communicate with your
service will be unable to find or connect to your process.</p>
<p>Create a pid that Erlang processes can use to communicate with your
@@ -485,9 +485,9 @@ ETERM *pid;
pid = erl_mk_pid(thisnode,14,0,0);
erl_global_register(fd,servicename,pid); ]]></code>
- <p>After registering the name, you should use <c><![CDATA[erl_accept()]]></c> to wait for
+ <p>After registering the name, you should use <c>erl_accept()</c> to wait for
incoming connections.</p>
- <p>Do not forget to free <c><![CDATA[pid]]></c> later with <c><![CDATA[erl_free_term()]]></c>!</p>
+ <p>Do not forget to free <c>pid</c> later with <c>erl_free_term()</c>!</p>
<p>To unregister a name:</p>
<code type="none"><![CDATA[
erl_global_unregister(fd,servicename); ]]></code>
@@ -500,7 +500,7 @@ erl_global_unregister(fd,servicename); ]]></code>
restoring them from a Mnesia table on an Erlang node. More detailed
information about the individual API functions can be found in the
Reference Manual.</p>
- <p>Keys are strings, i.e. 0-terminated arrays of characters, and values
+ <p>Keys are strings, i.e. <c>NULL</c>-terminated arrays of characters, and values
are arbitrary objects. Although integers and floating point numbers
are treated specially by the registry, you can store strings or binary
objects of any type as pointers.</p>
@@ -570,12 +570,12 @@ ei_reg_close(reg); ]]></code>
<title>Backing Up the Registry to Mnesia</title>
<p>The contents of a registry can be backed up to Mnesia on a "nearby"
Erlang node. You need to provide an open connection to the Erlang node
- (see <c><![CDATA[erl_connect()]]></c>). Also, Mnesia 3.0 or later must be running
+ (see <c>erl_connect()</c>). Also, Mnesia 3.0 or later must be running
on the Erlang node before the backup is initiated:</p>
<code type="none"><![CDATA[
ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code>
<p>The example above will backup the contents of the registry to the
- specified Mnesia table <c><![CDATA["mtab"]]></c>. Once a registry has been backed
+ specified Mnesia table <c>"mtab"</c>. Once a registry has been backed
up to Mnesia in this manner, additional backups will only affect
objects that have been modified since the most recent backup, i.e.
objects that have been created, changed or deleted. The backup
@@ -584,7 +584,7 @@ ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code>
<p>In the same manner, a registry can be restored from a Mnesia table:</p>
<code type="none"><![CDATA[
ei_reg_restore(fd, reg, "mtab"); ]]></code>
- <p>This will read the entire contents of <c><![CDATA["mtab"]]></c> into the specified
+ <p>This will read the entire contents of <c>"mtab"</c> into the specified
registry. After the restore, all of the objects in the registry will
be marked as unmodified, so a subsequent backup will only affect
objects that you have modified since the restore.</p>
@@ -600,8 +600,8 @@ ei_reg_restore(fd, reg, "mtab"); ]]></code>
<p>When string or binary objects are stored in the registry it is
important that a number of simple guidelines are followed. </p>
<p>Most importantly, the object must have been created with a single call
- to <c><![CDATA[malloc()]]></c> (or similar), so that it can later be removed by a
- single call to <c><![CDATA[free()]]></c>. Objects will be freed by the registry
+ to <c>malloc()</c> (or similar), so that it can later be removed by a
+ single call to <c>free()</c>. Objects will be freed by the registry
when it is closed, or when you assign a new value to an object that
previously contained a string or binary.</p>
<p>You should also be aware that if you store binary objects that are
@@ -618,9 +618,8 @@ ei_reg_restore(fd, reg, "mtab"); ]]></code>
you make, possibly causing it to be missed the next time you make a
Mnesia backup of the registry contents. This can be avoided if you
mark the object as dirty after any such changes with
- <c><![CDATA[ei_reg_markdirty()]]></c>, or pass appropriate flags to
- <c><![CDATA[ei_reg_dump()]]></c>.</p>
+ <c>ei_reg_markdirty()</c>, or pass appropriate flags to
+ <c>ei_reg_dump()</c>.</p>
</section>
</section>
</chapter>
-
diff --git a/lib/erl_interface/doc/src/erl_malloc.xml b/lib/erl_interface/doc/src/erl_malloc.xml
index 799c903b1a..c0eebc29e9 100644
--- a/lib/erl_interface/doc/src/erl_malloc.xml
+++ b/lib/erl_interface/doc/src/erl_malloc.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_malloc</title>
@@ -28,174 +28,177 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>980703</date>
+ <date>1998-07-03</date>
<rev>A</rev>
- <file>erl_malloc.sgml</file>
+ <file>erl_malloc.xml</file>
</header>
<lib>erl_malloc</lib>
- <libsummary>Memory Allocation Functions</libsummary>
+ <libsummary>Memory allocation functions.</libsummary>
<description>
<p>This module provides functions for allocating and deallocating
memory.</p>
</description>
+
<funcs>
<func>
<name><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name>
- <fsummary>Allocates an ETERM structure</fsummary>
+ <fsummary>Allocate an ETERM structure.</fsummary>
<type>
<v>unsigned char etype;</v>
</type>
<desc>
- <p>This function allocates an <c><![CDATA[(ETERM)]]></c> structure.
- Specify <c><![CDATA[etype]]></c> as one of the following constants:</p>
+ <p>Allocates an <c>(ETERM)</c> structure.</p>
+ <p>Specify <c>etype</c> as one of the following
+ constants:</p>
<list type="bulleted">
- <item>
- <p>ERL_INTEGER</p>
+ <item><c>ERL_INTEGER</c>
</item>
- <item>
- <p>ERL_U_INTEGER <c><![CDATA[/* unsigned integer */]]></c></p>
+ <item><c>ERL_U_INTEGER</c> (unsigned integer)
</item>
- <item>
- <p>ERL_ATOM</p>
+ <item><c>ERL_ATOM</c>
</item>
- <item>
- <p>ERL_PID <c><![CDATA[/* Erlang process identifier */]]></c></p>
+ <item><c>ERL_PID</c> (Erlang process identifier)
</item>
- <item>
- <p>ERL_PORT</p>
+ <item><c>ERL_PORT</c>
</item>
- <item>
- <p>ERL_REF <c><![CDATA[/* Erlang reference */]]></c></p>
+ <item><c>ERL_REF</c> (Erlang reference)
</item>
- <item>
- <p>ERL_LIST</p>
+ <item><c>ERL_LIST</c>
</item>
- <item>
- <p>ERL_EMPTY_LIST</p>
+ <item><c>ERL_EMPTY_LIST</c>
</item>
- <item>
- <p>ERL_TUPLE</p>
+ <item><c>ERL_TUPLE</c>
</item>
- <item>
- <p>ERL_BINARY</p>
+ <item><c>ERL_BINARY</c>
</item>
- <item>
- <p>ERL_FLOAT</p>
+ <item><c>ERL_FLOAT</c>
</item>
- <item>
- <p>ERL_VARIABLE</p>
+ <item><c>ERL_VARIABLE</c>
</item>
- <item>
- <p>ERL_SMALL_BIG <c><![CDATA[/* bignum */]]></c></p>
+ <item><c>ERL_SMALL_BIG</c> (bignum)
</item>
- <item>
- <p>ERL_U_SMALL_BIG <c><![CDATA[/* bignum */]]></c></p>
+ <item><c>ERL_U_SMALL_BIG</c> (bignum)
</item>
</list>
- <p><c><![CDATA[ERL_SMALL_BIG]]></c> and <c><![CDATA[ERL_U_SMALL_BIG]]></c> are for
- creating Erlang <c><![CDATA[bignums]]></c>, which can contain integers of
- arbitrary size. The size of an integer in Erlang is machine
- dependent, but in general any integer larger than 2^28
- requires a bignum.</p>
+ <p><c>ERL_SMALL_BIG</c> and
+ <c>ERL_U_SMALL_BIG</c> are for
+ creating Erlang <c>bignums</c>, which can contain integers
+ of any size. The size of an integer in Erlang is machine-dependent,
+ but any integer &gt; 2^28 requires a bignum.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name>
- <fsummary>Clears the ETERM freelist</fsummary>
+ <fsummary>Clear the ETERM freelist.</fsummary>
<desc>
- <p>Clears the
- freelist, where blocks are placed when they are
- released by <c><![CDATA[erl_free_term()]]></c> and
- <c><![CDATA[erl_free_compound()]]></c>. </p>
+ <p>Clears the freelist, where blocks are placed when they are
+ released by <c>erl_free_term()</c> and
+ <c>erl_free_compound()</c>.</p>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name>
- <fsummary>Reports term allocation statistics</fsummary>
+ <fsummary>Report term allocation statistics.</fsummary>
<type>
<v>long *allocated;</v>
<v>long *freed;</v>
</type>
<desc>
- <p><c><![CDATA[allocated]]></c> and <c><![CDATA[freed]]></c> are initialized to
+ <p>Reports term allocation statistics.</p>
+ <p><c>allocated</c> and <c>freed</c> are
+ initialized to
contain information about the fix-allocator used to allocate
- ETERM components. <c><![CDATA[allocated]]></c> is the number of blocks
- currently allocated to ETERM objects. <c><![CDATA[freed]]></c> is the
- length of the freelist, where blocks are placed when they are
- released by <c><![CDATA[erl_free_term()]]></c> and
- <c><![CDATA[erl_free_compound()]]></c>. </p>
+ <c>ETERM</c> components.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>allocated</c> is the number of blocks currently
+ allocated to <c>ETERM</c> objects.</p>
+ </item>
+ <item>
+ <p><c>freed</c> is the length of the freelist, where
+ blocks are placed when they are
+ released by <c>erl_free_term()</c> and
+ <c>erl_free_compound()</c>.</p>
+ </item>
+ </list>
</desc>
</func>
+
<func>
- <name><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name>
- <fsummary>Frees an array of ETERM structures</fsummary>
+ <name><ret>void</ret><nametext>erl_free(ptr)</nametext></name>
+ <fsummary>Free some memory.</fsummary>
<type>
- <v>ETERM **array;</v>
- <v>int size;</v>
+ <v>void *ptr;</v>
</type>
<desc>
- <p>This function frees an array of Erlang terms.</p>
- <p><c><![CDATA[array]]></c> is an array of ETERM* objects.
- </p>
- <p><c><![CDATA[size]]></c> is the number of terms in the array.</p>
+ <p>Calls the standard
+ <c>free()</c> function.</p>
</desc>
</func>
+
<func>
- <name><ret>void</ret><nametext>erl_free_term(t)</nametext></name>
- <fsummary>Frees an ETERM structure</fsummary>
+ <name><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name>
+ <fsummary>Free an array of ETERM structures.</fsummary>
<type>
- <v>ETERM *t;</v>
+ <v>ETERM **array;</v>
+ <v>int size;</v>
</type>
<desc>
- <p>Use this function to free an Erlang term.</p>
+ <p>Frees an array of Erlang terms.</p>
+ <list type="bulleted">
+ <item><c>array</c> is an array of ETERM* objects.</item>
+ <item><c>size</c> is the number of terms in the array.
+ </item>
+ </list>
</desc>
</func>
+
<func>
<name><ret>void</ret><nametext>erl_free_compound(t)</nametext></name>
- <fsummary>Frees an array of ETERM structures</fsummary>
+ <fsummary>Free an array of ETERM structures.</fsummary>
<type>
<v>ETERM *t;</v>
</type>
<desc>
<p>Normally it is the programmer's responsibility to free each
Erlang term that has been returned from any of the
- <c><![CDATA[erl_interface]]></c> functions. However since many of the
+ <c>Erl_Interface</c> functions. However, as many of the
functions that build new Erlang terms in fact share objects
- with other existing terms, it may be difficult for the
- programmer to maintain pointers to all such terms in order to
- free them individually.
- </p>
- <p><c><![CDATA[erl_free_compound()]]></c> will recursively free all of the
- sub-terms associated with a given Erlang term, regardless of
- whether we are still holding pointers to the sub-terms.
- </p>
- <p>There is an example in the User Manual under "Building
- Terms and Patterns"
- </p>
+ with other existing terms, it can be difficult for the
+ programmer to maintain pointers to all such terms to
+ free them individually.</p>
+ <p><c>erl_free_compound()</c> recursively frees all of the
+ subterms associated with a specified Erlang term, regardless of
+ whether we are still holding pointers to the subterms.</p>
+ <p>For an example, see section
+ <seealso marker="ei_users_guide#building_terms_and_patterns">Building Terms and Patterns</seealso>
+ in the User's Guide.</p>
</desc>
</func>
+
<func>
- <name><ret>void</ret><nametext>erl_malloc(size)</nametext></name>
- <fsummary>Allocates some memory</fsummary>
+ <name><ret>void</ret><nametext>erl_free_term(t)</nametext></name>
+ <fsummary>Free an ETERM structure.</fsummary>
<type>
- <v>long size;</v>
+ <v>ETERM *t;</v>
</type>
<desc>
- <p>This function calls the standard
- <c><![CDATA[malloc()]]></c> function. </p>
+ <p>Frees an Erlang term.</p>
</desc>
</func>
+
<func>
- <name><ret>void</ret><nametext>erl_free(ptr)</nametext></name>
- <fsummary>Frees some memory</fsummary>
+ <name><ret>void</ret><nametext>erl_malloc(size)</nametext></name>
+ <fsummary>Allocate some memory.</fsummary>
<type>
- <v>void *ptr;</v>
+ <v>long size;</v>
</type>
<desc>
- <p>This function calls the standard
- <c><![CDATA[free()]]></c> function. </p>
+ <p>Calls the standard
+ <c>malloc()</c> function.</p>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/doc/src/erl_marshal.xml b/lib/erl_interface/doc/src/erl_marshal.xml
index 7c56089016..2ad658f78b 100644
--- a/lib/erl_interface/doc/src/erl_marshal.xml
+++ b/lib/erl_interface/doc/src/erl_marshal.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>erl_marshal</title>
@@ -28,246 +28,241 @@
<docno></docno>
<approved>Bjarne D&auml;cker</approved>
<checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
- <date>980703</date>
+ <date>1998-07-03</date>
<rev>A</rev>
- <file>erl_marshal.sgml</file>
+ <file>erl_marshal.xml</file>
</header>
<lib>erl_marshal</lib>
- <libsummary>Encoding and Decoding of Erlang terms</libsummary>
+ <libsummary>Encoding and decoding of Erlang terms.</libsummary>
<description>
<p>This module contains functions for encoding Erlang terms into
a sequence of bytes, and for decoding Erlang terms from a
sequence of bytes.</p>
</description>
+
<funcs>
<func>
<name><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name>
- <fsummary>Compares encoded byte sequences</fsummary>
+ <fsummary>Compare encoded byte sequences.</fsummary>
<type>
<v>unsigned char *bufp1,*bufp2;</v>
</type>
<desc>
- <p>This function compares two encoded terms.
- </p>
- <p><c><![CDATA[bufp1]]></c> is a buffer containing an encoded Erlang
- term term1.
- </p>
- <p><c><![CDATA[bufp2]]></c> is a buffer containing an encoded Erlang
- term term2.
- </p>
- <p>The function returns 0 if the terms are equal, -1 if term1
- is less than term2, or 1 if term2 is less than term1.
- </p>
+ <p>Compares two encoded terms.</p>
+ <list type="bulleted">
+ <item><c>bufp1</c> is a buffer containing an encoded
+ Erlang term term1.</item>
+ <item><c>bufp2</c> is a buffer containing an encoded
+ Erlang term term2.</item>
+ </list>
+ <p>Returns <c>0</c> if the terms are equal, <c>-1</c> if
+ <c>term1</c> &lt; <c>term2</c>, or <c>1</c> if <c>term2</c> &lt;
+ <c>term1</c>.</p>
</desc>
</func>
+
<func>
<name><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name>
<name><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name>
- <fsummary>Converts a term from Erlang external format</fsummary>
+ <fsummary>Convert a term from Erlang external format.</fsummary>
<type>
<v>unsigned char *bufp;</v>
<v>unsigned char **bufpp;</v>
</type>
<desc>
- <p><c><![CDATA[erl_decode()]]></c> and <c><![CDATA[erl_decode_buf()]]></c> decode
+ <p><c>erl_decode()</c> and
+ <c>erl_decode_buf()</c> decode
the contents of a buffer and return the corresponding
- Erlang term. <c><![CDATA[erl_decode_buf()]]></c> provides a simple
+ Erlang term. <c>erl_decode_buf()</c> provides a simple
mechanism for dealing with several encoded terms stored
consecutively in the buffer.</p>
- <p><c><![CDATA[bufp]]></c> is a pointer to a buffer containing one or
- more encoded Erlang terms.
- </p>
- <p><c><![CDATA[bufpp]]></c> is the address of a buffer pointer. The buffer
- contains one or more consecutively encoded Erlang terms.
- Following a successful call to <c><![CDATA[erl_decode_buf()]]></c>,
- <c><![CDATA[bufpp]]></c> will be updated so that it points to the next
- encoded term.
- </p>
- <p><c><![CDATA[erl_decode()]]></c> returns an Erlang term
- corresponding to the contents of <c><![CDATA[bufp]]></c> on success, or
- NULL on failure. <c><![CDATA[erl_decode_buf()]]></c> returns an Erlang
+ <list type="bulleted">
+ <item>
+ <p><c>bufp</c> is a pointer to a buffer containing one
+ or more encoded Erlang terms.</p>
+ </item>
+ <item>
+ <p><c>bufpp</c> is the address of a buffer pointer. The
+ buffer contains one or more consecutively encoded Erlang terms.
+ Following a successful call to
+ <c>erl_decode_buf()</c>, <c>bufpp</c> is
+ updated so that it points to the next encoded term.</p>
+ </item>
+ </list>
+ <p><c>erl_decode()</c> returns an Erlang term
+ corresponding to the contents of <c>bufp</c> on success,
+ otherwise <c>NULL</c>. <c>erl_decode_buf()</c>
+ returns an Erlang
term corresponding to the first of the consecutive terms in
- <c><![CDATA[bufpp]]></c> and moves <c><![CDATA[bufpp]]></c> forward to point to the
+ <c>bufpp</c> and moves <c>bufpp</c> forward
+ to point to the
next term in the buffer. On failure, each of the functions
- returns NULL.
- </p>
+ return <c>NULL</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name>
<name><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name>
- <fsummary>Converts a term into Erlang external format</fsummary>
+ <fsummary>Convert a term into Erlang external format.</fsummary>
<type>
<v>ETERM *term;</v>
<v>unsigned char *bufp;</v>
<v>unsigned char **bufpp;</v>
</type>
<desc>
- <p><c><![CDATA[erl_encode()]]></c> and <c><![CDATA[erl_encode_buf()]]></c> encode
+ <p><c>erl_encode()</c> and
+ <c>erl_encode_buf()</c> encode
Erlang terms into external format for storage or transmission.
- <c><![CDATA[erl_encode_buf()]]></c> provides a simple mechanism for
- encoding several terms consecutively in the same
- buffer.
- </p>
- <p><c>term</c> is an Erlang term to be encoded.
- </p>
- <p><c>bufp</c> is a pointer to a buffer containing one or
- more encoded Erlang terms.
- </p>
- <p><c>bufpp</c> is a pointer to a pointer to a buffer
- containing one or more consecutively encoded Erlang terms.
- Following a successful call to <c><![CDATA[erl_encode_buf()]]></c>,
- <c>bufpp</c> will be updated so that it points to the
- position for the next encoded term.
- </p>
- <p>
- These functions returns the number of bytes written to buffer
- if successful, otherwise returns 0.
- </p>
- <p>Note that no bounds checking is done on the buffer. It is
- the caller's responsibility to make sure that the buffer is
+ <c>erl_encode_buf()</c> provides a simple mechanism for
+ encoding several terms consecutively in the same buffer.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>term</c> is an Erlang term to be encoded.</p>
+ </item>
+ <item>
+ <p><c>bufp</c> is a pointer to a buffer containing one or
+ more encoded Erlang terms.</p>
+ </item>
+ <item>
+ <p><c>bufpp</c> is a pointer to a pointer to a buffer
+ containing one or more consecutively encoded Erlang terms.
+ Following a successful call to
+ <c>erl_encode_buf()</c>, <c>bufpp</c> is updated so
+ that it points to the
+ position for the next encoded term.</p>
+ </item>
+ </list>
+ <p>These functions return the number of bytes written to buffer
+ on success, otherwise <c>0</c>.</p>
+ <p>Notice that no bounds checking is done on the buffer. It is
+ the caller's responsibility to ensure that the buffer is
large enough to hold the encoded terms. You can either use a
- static buffer that is large enough to hold the terms you
- expect to need in your program, or use <c><![CDATA[erl_term_len()]]></c>
- to determine the exact requirements for a given term.
- </p>
+ static buffer that is large enough to hold the terms you expect
+ to need in your program, or use <c>erl_term_len()</c>
+ to determine the exact requirements for a given term.</p>
<p>The following can help you estimate the buffer
- requirements for a term. Note that this information is
- implementation specific, and may change in future versions.
- If you are unsure, use <c><![CDATA[erl_term_len()]]></c>.
- </p>
+ requirements for a term. Notice that this information is
+ implementation-specific, and can change in future versions.
+ If you are unsure, use <c>erl_term_len()</c>.</p>
<p>Erlang terms are encoded with a 1 byte tag that
identifies the type of object, a 2- or 4-byte length field,
- and then the data itself. Specifically:
- </p>
+ and then the data itself. Specifically:</p>
<taglist>
- <tag><c><![CDATA[Tuples]]></c></tag>
- <item>need 5 bytes, plus the space for each element.</item>
- <tag><c><![CDATA[Lists]]></c></tag>
- <item>need 5 bytes, plus the space for each element, and 1
- additional byte for the empty list at the end.</item>
- <tag><c><![CDATA[Strings and atoms]]></c></tag>
- <item>need 3 bytes, plus 1 byte for each character (the
- terminating 0 is not encoded). Really long strings (more
- than 64k characters) are encoded as lists. Atoms cannot
- contain more than 256 characters.</item>
- <tag><c><![CDATA[Integers]]></c></tag>
- <item>need 5 bytes.</item>
- <tag><c><![CDATA[Characters]]></c></tag>
- <item>(integers &lt; 256) need 2 bytes.</item>
- <tag><c><![CDATA[Floating point numbers]]></c></tag>
- <item>need 32 bytes.</item>
- <tag><c><![CDATA[Pids]]></c></tag>
- <item>need 10 bytes, plus the space for the node name, which
- is an atom.</item>
- <tag><c><![CDATA[Ports and Refs]]></c></tag>
- <item>need 6 bytes, plus the space for the node name, which
- is an atom.</item>
+ <tag><c>Tuples</c></tag>
+ <item>Need 5 bytes, plus the space for each element.</item>
+ <tag><c>Lists</c></tag>
+ <item>Need 5 bytes, plus the space for each element, and 1
+ more byte for the empty list at the end.</item>
+ <tag><c>Strings and atoms</c></tag>
+ <item>Need 3 bytes, plus 1 byte for each character (the
+ terminating 0 is not encoded). Really long strings (more
+ than 64k characters) are encoded as lists. Atoms cannot
+ contain more than 256 characters.</item>
+ <tag><c>Integers</c></tag>
+ <item>Need 5 bytes.</item>
+ <tag><c>Characters</c></tag>
+ <item>(Integers &lt; 256) need 2 bytes.</item>
+ <tag><c>Floating point numbers</c></tag>
+ <item>Need 32 bytes.</item>
+ <tag><c>Pids</c></tag>
+ <item>Need 10 bytes, plus the space for the node name, which
+ is an atom.</item>
+ <tag><c>Ports and Refs</c></tag>
+ <item>Need 6 bytes, plus the space for the node name, which
+ is an atom.</item>
</taglist>
- <p>The total space required will be the result calculated
- from the information above, plus 1 additional byte for a
- version identifier.
- </p>
+ <p>The total space required is the result calculated
+ from the information above, plus 1 more byte for a
+ version identifier.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name>
- <fsummary>Counts elements in encoded term</fsummary>
+ <fsummary>Count elements in encoded term.</fsummary>
<type>
<v>unsigned char *bufp;</v>
</type>
<desc>
- <p>This function returns the number of elements in an
- encoded term.</p>
+ <p>Returns the number of elements in an encoded term.</p>
</desc>
</func>
+
<func>
<name><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name>
- <fsummary>Determines type of an encoded byte sequence</fsummary>
+ <fsummary>Determine type of an encoded byte sequence.</fsummary>
<type>
<v>unsigned char *bufp;</v>
</type>
<desc>
- <p>This function identifies and returns the type of Erlang term encoded
- in a buffer. It will skip a trailing <em>magic</em> identifier.
- Returns <c><![CDATA[0]]></c> if the type can't be determined or one of</p>
+ <p>Identifies and returns the type of Erlang term encoded
+ in a buffer. It skips a trailing <em>magic</em> identifier.</p>
+ <p>Returns <c>0</c> if the type cannot be determined or
+ one of:</p>
<list type="bulleted">
- <item>
- <p>ERL_INTEGER</p>
+ <item><c>ERL_INTEGER</c>
</item>
- <item>
- <p>ERL_ATOM</p>
+ <item><c>ERL_ATOM</c>
</item>
- <item>
- <p>ERL_PID <c><![CDATA[/* Erlang process identifier */]]></c></p>
+ <item><c>ERL_PID</c> (Erlang process identifier)
</item>
- <item>
- <p>ERL_PORT</p>
+ <item><c>ERL_PORT</c>
</item>
- <item>
- <p>ERL_REF <c><![CDATA[/* Erlang reference */]]></c></p>
+ <item><c>ERL_REF</c> (Erlang reference)
</item>
- <item>
- <p>ERL_EMPTY_LIST</p>
+ <item><c>ERL_EMPTY_LIST</c>
</item>
- <item>
- <p>ERL_LIST</p>
+ <item><c>ERL_LIST</c>
</item>
- <item>
- <p>ERL_TUPLE</p>
+ <item><c>ERL_TUPLE</c>
</item>
- <item>
- <p>ERL_FLOAT</p>
+ <item><c>ERL_FLOAT</c>
</item>
- <item>
- <p>ERL_BINARY</p>
+ <item><c>ERL_BINARY</c>
</item>
- <item>
- <p>ERL_FUNCTION</p>
+ <item><c>ERL_FUNCTION</c>
</item>
</list>
</desc>
</func>
+
<func>
<name><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name>
- <fsummary>Steps over encoded term</fsummary>
+ <fsummary>Step over encoded term.</fsummary>
<type>
<v>unsigned char *bufp;</v>
<v>int pos;</v>
</type>
<desc>
<p>This function is used for stepping over one or more
- encoded terms in a buffer, in order to directly access a
- later term.
- </p>
- <p><c><![CDATA[bufp]]></c> is a pointer to a buffer containing one or
- more encoded Erlang terms.
- </p>
- <p><c><![CDATA[pos]]></c> indicates how many terms to step over in the
- buffer.
- </p>
- <p>The function returns a pointer to a sub-term that can be
- used in a subsequent call to <c><![CDATA[erl_decode()]]></c> in order to retrieve
- the term at that position. If there is no term, or <c><![CDATA[pos]]></c>
- would exceed the size of the terms in the buffer, NULL is returned.
- </p>
+ encoded terms in a buffer, to directly access later term.</p>
+ <list type="bulleted">
+ <item><c>bufp</c> is a pointer to a buffer containing one
+ or more encoded Erlang terms.</item>
+ <item><c>pos</c> indicates how many terms to step over in
+ the buffer.</item>
+ </list>
+ <p>Returns a pointer to a subterm that can be
+ used in a later call to <c>erl_decode()</c> to retrieve
+ the term at that position. If there is no term, or
+ <c>pos</c> would exceed the size of the terms in the
+ buffer, <c>NULL</c> is returned.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>erl_term_len(t)</nametext></name>
- <fsummary>Determines encoded size of term</fsummary>
+ <fsummary>Determine encoded size of term.</fsummary>
<type>
<v>ETERM *t;</v>
</type>
<desc>
- <p>This function determines the buffer space that would be
- needed by <c><![CDATA[t]]></c> if it were encoded into Erlang external
- format by <c><![CDATA[erl_encode()]]></c>.
- </p>
- <p>The size in bytes is returned.
- </p>
+ <p>Determines the buffer space that would be
+ needed by <c>t</c> if it were encoded into Erlang external
+ format by <c>erl_encode()</c>.</p>
+ <p>Returns the size in bytes.</p>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/doc/src/fascicules.xml b/lib/erl_interface/doc/src/fascicules.xml
deleted file mode 100644
index f7edd8a973..0000000000
--- a/lib/erl_interface/doc/src/fascicules.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="part_ei" href="part_ei_frame.html" entry="no">
- EI User's Guide
- </fascicule>
- <fascicule file="ref_man_ei" href="ref_man_ei_frame.html" entry="yes">
- EI Library Reference
- </fascicule>
- <fascicule file="ref_man_erl_interface" href="ref_man_erl_interface_frame.html" entry="no">
- Erl_interface Library Reference
- </fascicule>
- <fascicule file="ref_man" href="ref_man_frame.html" entry="no">
- Command Reference
- </fascicule>
- <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../../doc/print.html" entry="no">
- Off-Print
- </fascicule>
-</fascicules>
-
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index a69c5aac11..b5d8def655 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -31,6 +31,67 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.9.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minor documentation update</p>
+ <p>
+ Own Id: OTP-14233 Aux Id: PR-1343 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.9.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix <c>ei_connect_init</c> and <c>ei_connect_xinit</c> to
+ adjust the <c>creation</c> argument to be compatible with
+ nodes older than OTP-19.</p>
+ <p>
+ Own Id: OTP-13981</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Editorial documentation changes</p>
+ <p>
+ Own Id: OTP-13980</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Look for .erlang.cookie in windows system directory if
+ HOMEDRIVE and HOMEPATH is not set. The same behaviour as
+ the VM.</p>
+ <p>
+ Own Id: OTP-13849</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/doc/src/part.xml b/lib/erl_interface/doc/src/part.xml
index d044e2b981..3b761df221 100644
--- a/lib/erl_interface/doc/src/part.xml
+++ b/lib/erl_interface/doc/src/part.xml
@@ -22,7 +22,7 @@
</legalnotice>
- <title>EI User's Guide</title>
+ <title>Erl_Interface User's Guide</title>
<prepared>Gordon Beaton</prepared>
<docno></docno>
<date>1998-11-30</date>
diff --git a/lib/erl_interface/doc/src/part_erl_interface.xml b/lib/erl_interface/doc/src/part_erl_interface.xml
index 2abe7ecd60..e256cfa193 100644
--- a/lib/erl_interface/doc/src/part_erl_interface.xml
+++ b/lib/erl_interface/doc/src/part_erl_interface.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>Erl_Interface User's Guide</title>
@@ -31,4 +31,3 @@
</header>
<xi:include href="erl_interface.xml"/>
</part>
-
diff --git a/lib/erl_interface/doc/src/ref_man.xml b/lib/erl_interface/doc/src/ref_man.xml
index 0cf060829b..1e20637cb7 100644
--- a/lib/erl_interface/doc/src/ref_man.xml
+++ b/lib/erl_interface/doc/src/ref_man.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,9 +19,9 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
- <title>Erl_Interface Command Reference</title>
+ <title>Erl_Interface Reference Manual</title>
<prepared>Gordon Beaton</prepared>
<docno></docno>
<date>1998-11.30</date>
@@ -29,17 +29,6 @@
<file>ref_man.xml</file>
</header>
<description>
- <p>The <c>ei</c> and <c>erl_interface</c> are <c>C</c> interface libraries for
- communication with <c>Erlang</c>.</p>
- <note>
- <p>By default, the <c>ei</c> and <c>erl_interface</c> libraries are only guaranteed
- to be compatible with other Erlang/OTP components from the same
- release as the libraries themself. See the documentation of the
- <seealso marker="ei#ei_set_compat_rel">ei_set_compat_rel()</seealso> and
- <seealso marker="erl_eterm#erl_set_compat_rel">erl_set_compat_rel()</seealso>
- functions on how to communicate with Erlang/OTP components from earlier
- releases.</p>
- </note>
</description>
<xi:include href="ei.xml"/>
<xi:include href="ei_connect.xml"/>
@@ -53,4 +42,3 @@
<xi:include href="erl_marshal.xml"/>
<xi:include href="erl_call.xml"/>
</application>
-
diff --git a/lib/erl_interface/doc/src/ref_man_ei.xml b/lib/erl_interface/doc/src/ref_man_ei.xml
index d24828c394..92ff9ed328 100644
--- a/lib/erl_interface/doc/src/ref_man_ei.xml
+++ b/lib/erl_interface/doc/src/ref_man_ei.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>EI Library Reference</title>
@@ -30,12 +30,12 @@
<file>ref_man_ei.xml</file>
</header>
<description>
- <p>The <c><![CDATA[ei]]></c> library is a <c><![CDATA[C]]></c> interface library for
- communication with <c><![CDATA[Erlang]]></c>.</p>
+ <p>The <c>ei</c> library is a <c>C</c> interface library for
+ communication with <c>Erlang</c>.</p>
<note>
- <p>By default, the <c><![CDATA[ei]]></c> library is only guaranteed
+ <p>By default, the <c>ei</c> library is only guaranteed
to be compatible with other Erlang/OTP components from the same
- release as the <c><![CDATA[ei]]></c> library itself. See the documentation of the
+ release as the <c>ei</c> library itself. See the documentation of the
<seealso marker="ei#ei_set_compat_rel">ei_set_compat_rel()</seealso>
function on how to communicate with Erlang/OTP components from earlier
releases.</p>
@@ -45,4 +45,3 @@
<xi:include href="ei_connect.xml"/>
<xi:include href="registry.xml"/>
</application>
-
diff --git a/lib/erl_interface/doc/src/ref_man_erl_interface.xml b/lib/erl_interface/doc/src/ref_man_erl_interface.xml
index fb39c5a7e4..4b1d0e9981 100644
--- a/lib/erl_interface/doc/src/ref_man_erl_interface.xml
+++ b/lib/erl_interface/doc/src/ref_man_erl_interface.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>Erl_Interface Library Reference</title>
@@ -50,4 +50,3 @@
<xi:include href="erl_malloc.xml"/>
<xi:include href="erl_marshal.xml"/>
</application>
-
diff --git a/lib/erl_interface/doc/src/registry.xml b/lib/erl_interface/doc/src/registry.xml
index 285a2402b8..6d70fb3475 100644
--- a/lib/erl_interface/doc/src/registry.xml
+++ b/lib/erl_interface/doc/src/registry.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -19,7 +19,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
+
</legalnotice>
<title>registry</title>
@@ -28,457 +28,585 @@
<docno></docno>
<approved>Gordon Beaton</approved>
<checked>Gordon Beaton</checked>
- <date>980707</date>
+ <date>1998-07-07</date>
<rev>A</rev>
- <file>registry.sgml</file>
+ <file>registry.xml</file>
</header>
<lib>registry</lib>
- <libsummary>Store and backup key-value pairs</libsummary>
+ <libsummary>Store and back up key-value pairs.</libsummary>
<description>
<p>This module provides support for storing key-value
pairs in a table known as a registry, backing up registries to
- Mnesia in an atomic manner, and later restoring the contents of a
- registry from Mnesia.</p>
+ <seealso marker="mnesia:mnesia">Mnesia</seealso>
+ in an atomic manner, and later restoring the contents of a
+ registry from <c>Mnesia</c>.</p>
</description>
+
<funcs>
<func>
- <name><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name>
- <fsummary>Create and open a registry</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name>
+ <fsummary>Close a registry.</fsummary>
<type>
- <v>int size;</v>
+ <v>ei_reg *reg;</v>
</type>
<desc>
- <p>Open (create) a registry. The registry will be
- initially empty. Use <c><![CDATA[ei_reg_close()]]></c> to close the registry
- later.
- </p>
- <p><c><![CDATA[size]]></c> is the approximate number of objects you intend
- to store in the registry. Since the registry uses a hash table
- with collision chaining, there is no absolute upper limit on the
- number of objects that can be stored in it. However for reasons
- of efficiency, it is a good idea to choose a number that is
- appropriate for your needs. It is possible to use
- <c><![CDATA[ei_reg_resize()]]></c> to change the size later. Note that the
- number you provide will be increased to the nearest larger prime
- number.
- </p>
- <p>On success, an empty registry will be returned. On failure, NULL
- will be returned.</p>
+ <p>A registry that has previously been created with
+ <c>ei_reg_open()</c> is closed, and all the objects it
+ contains are freed.</p>
+ <p><c>reg</c> is the registry to close.</p>
+ <p>Returns <c>0</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name>
- <fsummary>Resize a registry</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name>
+ <fsummary>Delete an object from the registry.</fsummary>
<type>
<v>ei_reg *reg;</v>
- <v>int newsize;</v>
+ <v>const char *key;</v>
</type>
<desc>
- <p>Change the size of a registry.
- </p>
- <p><c><![CDATA[newsize]]></c> is the new size to make the registry. The
- number will be increased to the nearest larger prime number.
- </p>
- <p>On success, the registry will be resized, all contents
- rehashed, and the function will return 0. On failure, the
- registry will be left unchanged and the function will return -1.</p>
+ <p>Deletes an object from the registry. The object is not
+ removed from the registry, it is only marked for later
+ removal so that on later backups to <c>Mnesia</c>, the
+ corresponding object can be removed from the <c>Mnesia</c> table as
+ well. If another object is later created with the same key, the
+ object will be reused. </p>
+ <p>The object is removed from the registry after a call to
+ <c>ei_reg_dump()</c> or <c>ei_reg_purge()</c>.
+ </p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry containing
+ <c>key</c>.</item>
+ <item><c>key</c> is the object to remove.</item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name>
- <fsummary>Close a registry </fsummary>
+ <name><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name>
+ <fsummary>Back up a registry to Mnesia.</fsummary>
<type>
+ <v>int fd;</v>
<v>ei_reg *reg;</v>
+ <v>const char *mntab;</v>
+ <v>int flags;</v>
</type>
<desc>
- <p>A registry that has previously been created with
- <c><![CDATA[ei_reg_open()]]></c> is closed, and all the objects it contains
- are freed.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry to close.
- </p>
- <p>The function returns 0.</p>
+ <p>Dumps the contents of a registry to a <c>Mnesia</c> table in an
+ atomic manner, that is, either all data or no data is updated.
+ If any errors are encountered while backing up
+ the data, the entire operation is aborted.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open connection to Erlang.
+ <c>Mnesia</c> 3.0 or later must be running on the Erlang node.
+ </item>
+ <item><c>reg</c> is the registry to back up.</item>
+ <item><c>mntab</c> is the name of the <c>Mnesia</c> table
+ where the backed up data is to be placed. If the table does not
+ exist, it is created automatically using configurable defaults.
+ For information about configuring this behavior, see
+ <seealso marker="mnesia:mnesia"><c>Mnesia</c></seealso>.</item>
+ </list>
+ <p>If <c>flags</c> is <c>0</c>, the backup includes only
+ those objects that have been created, modified, or deleted since the
+ last backup or restore (that is, an incremental backup). After the
+ backup, any objects that were marked dirty are now clean, and any
+ objects that had been marked for deletion are deleted.</p>
+ <p>Alternatively, setting flags to <c>EI_FORCE</c> causes a full
+ backup to be done, and <c>EI_NOPURGE</c> causes the deleted objects
+ to be left in the registry afterwards. These can be bitwise OR'ed
+ together if both behaviors are desired. If <c>EI_NOPURGE</c> was
+ specified, <c>ei_reg_purge()</c> can be used to
+ explicitly remove the deleted items from the registry later.</p>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name>
- <fsummary>Assign an integer object</fsummary>
+ <name><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name>
+ <fsummary>Get a floating point object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
- <v>int i;</v>
</type>
<desc>
- <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> and integer
- value <c><![CDATA[i]]></c>. If an object already existed with the same
- <c><![CDATA[key]]></c>, the new value replaces the old one. If the previous
- value was a binary or string, it is freed with <c><![CDATA[free()]]></c>.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object.
- </p>
- <p><c><![CDATA[i]]></c> is the integer value to assign.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Gets the value associated with <c>key</c> in the
+ registry. The value must be a floating point type.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object will be
+ looked up.</item>
+ <item><c>key</c> is the name of the object to look up.
+ </item>
+ </list>
+ <p>On success, the function returns the value associated with
+ <c>key</c>.
+ If the object is not found or if it is not a floating point
+ object, <c>-1.0</c> is returned. To avoid problems with in-band error
+ reporting (that is, if you cannot distinguish between <c>-1.0</c> and
+ a valid result), use the more general function
+ <c>ei_reg_getval()</c> instead.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name>
- <fsummary>Assign a floating point object</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name>
+ <fsummary>Get an integer object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
- <v>double f;</v>
</type>
<desc>
- <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> and
- floating point value <c><![CDATA[f]]></c>. If an object already existed with
- the same <c><![CDATA[key]]></c>, the new value replaces the old one. If the
- previous value was a binary or string, it is freed with <c><![CDATA[free()]]></c>.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object.
- </p>
- <p><c><![CDATA[f]]></c> is the floating point value to assign.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Gets the value associated with <c>key</c> in the
+ registry. The value must be an integer.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object will be
+ looked up.</item>
+ <item><c>key</c> is the name of the object to look up.
+ </item>
+ </list>
+ <p>On success, the function returns the value associated with
+ <c>key</c>.
+ If the object is not found or if it is not an integer
+ object, <c>-1</c> is returned. To avoid problems with in-band error
+ reporting (that is, if you cannot distinguish between <c>-1</c> and a
+ valid result), use the more general function
+ <c>ei_reg_getval()</c> instead.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name>
- <fsummary>Assign a string object</fsummary>
+ <name><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name>
+ <fsummary>Get a binary object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
- <v>const char *s;</v>
+ <v>int size;</v>
</type>
<desc>
- <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose
- "value" is the specified string <c><![CDATA[s]]></c>. If an object already
- existed with the same <c><![CDATA[key]]></c>, the new value replaces the old
- one. If the previous value was a binary or string, it is freed
- with <c><![CDATA[free()]]></c>.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object.
- </p>
- <p><c><![CDATA[s]]></c> is the string to assign. The string itself
- must have been created through a single call to <c><![CDATA[malloc()]]></c> or
- similar function, so that the registry can later delete it if
- necessary by calling <c><![CDATA[free()]]></c>.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Gets the value associated with <c>key</c> in the
+ registry. The value must be a binary (pointer) type.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object will be
+ looked up.</item>
+ <item><c>key</c> is the name of the object to look up.
+ </item>
+ <item><c>size</c> is initialized to contain the length in
+ bytes of the object, if it is found.</item>
+ </list>
+ <p>On success, the function returns the value associated with
+ <c>key</c> and indicates its length in
+ <c>size</c>.
+ If the object is not found or if it is not a binary object,
+ <c>NULL</c> is returned. To avoid problems with in-band error
+ reporting (that is, if you cannot distinguish between <c>NULL</c> and
+ a valid result), use the more general function
+ <c>ei_reg_getval()</c> instead.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name>
- <fsummary>Assign a binary object</fsummary>
+ <name><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name>
+ <fsummary>Get a string object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
- <v>const void *p;</v>
- <v>int size;</v>
</type>
<desc>
- <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose
- "value" is the binary object pointed to by <c><![CDATA[p]]></c>. If an
- object already existed with the same <c><![CDATA[key]]></c>, the new value
- replaces the old one. If the previous value was a binary or
- string, it is freed with <c><![CDATA[free()]]></c>.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object.
- </p>
- <p><c><![CDATA[p]]></c> is a pointer to the binary object. The object itself
- must have been created through a single call to <c><![CDATA[malloc()]]></c> or
- similar function, so that the registry can later delete it if
- necessary by calling <c><![CDATA[free()]]></c>.
- </p>
- <p><c><![CDATA[size]]></c> is the length in bytes of the binary object.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Gets the value associated with <c>key</c> in the
+ registry. The value must be a string.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object will be
+ looked up.</item>
+ <item><c>key</c> is the name of the object to look up.
+ </item>
+ </list>
+ <p>On success, the function returns the value associated with
+ <c>key</c>. If the object is not found or if it is not a
+ string, <c>NULL</c> is returned. To avoid problems with in-band error
+ reporting (that is, if you cannot distinguish between <c>NULL</c> and
+ a valid result), use the more general function
+ <c>ei_reg_getval()</c> instead.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name>
- <fsummary>Assign a value to any object type</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name>
+ <fsummary>Get any object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
<v>int flags;</v>
- <v>v (see below)</v>
+ <v>void *v (see below)</v>
</type>
<desc>
- <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose
- value is specified by <c><![CDATA[v]]></c>. If an object already
- existed with the same <c><![CDATA[key]]></c>, the new value replaces the old
- one. If the previous value was a binary or string, it is freed
- with <c><![CDATA[free()]]></c>.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object.
- </p>
- <p><c><![CDATA[flags]]></c> indicates the type of the object specified by
- <c><![CDATA[v]]></c>. Flags must be one of EI_INT, EI_FLT, EI_STR and
- EI_BIN, indicating whether <c><![CDATA[v]]></c> is <c><![CDATA[int]]></c>, <c><![CDATA[double]]></c>,
- <c><![CDATA[char*]]></c> or <c><![CDATA[void*]]></c>. If <c><![CDATA[flags]]></c> is EI_BIN, then a
- fifth argument <c><![CDATA[size]]></c> is required, indicating the size
- in bytes of the object pointed to by <c><![CDATA[v]]></c>.
- </p>
- <p>If you wish to store an arbitrary pointer in the registry,
- specify a <c><![CDATA[size]]></c> of 0. In this case, the object itself will
- not be transferred by an <c><![CDATA[ei_reg_dump()]]></c> operation, just
- the pointer value.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>A general function for retrieving any kind of
+ object from the registry.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>reg</c> is the registry where the object will be
+ looked up.</p>
+ </item>
+ <item>
+ <p><c>key</c> is the name of the object to look up.</p>
+ </item>
+ <item>
+ <p><c>flags</c> indicates the type of object that you
+ are looking for. If <c>flags</c> is <c>0</c>, any
+ kind of object is returned.
+ If <c>flags</c> is <c>EI_INT</c>, <c>EI_FLT</c>,
+ <c>EI_STR</c>, or <c>EI_BIN</c>, then only values of
+ that kind are returned.</p>
+ <p>The buffer pointed to by <c>v</c>
+ must be large enough to hold the return data, that is, it must be
+ a pointer to one of <c>int</c>,
+ <c>double</c>, <c>char*</c>, or
+ <c>void*</c>, respectively.</p>
+ <p>If <c>flags</c> is <c>EI_BIN</c>, a fifth argument
+ <c>int *size</c> is required, so that the size of the
+ object can be returned.</p>
+ </item>
+ </list>
+ <p>On success, <c>v</c> (and <c>size</c> if the
+ object is binary) is initialized with the value associated
+ with <c>key</c>, and the function returns <c>EI_INT</c>,
+ <c>EI_FLT</c>, <c>EI_STR</c>, or <c>EI_BIN</c>, indicating the type
+ of object. On failure, <c>-1</c> is returned and the
+ arguments are not updated.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name>
- <fsummary>Get an integer object</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name>
+ <fsummary>Mark an object as dirty.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
</type>
<desc>
- <p>Get the value associated with <c><![CDATA[key]]></c> in the
- registry. The value must be an integer.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
- up.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object to look up.
- </p>
- <p>On success, the function returns the value associated with <c><![CDATA[key]]></c>.
- If the object was not found or it was not an integer
- object, -1 is returned. To avoid problems with in-band error
- reporting (i.e. if you cannot distinguish between -1 and a
- valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
- instead.</p>
+ <p>Marks a registry object as dirty. This ensures that
+ it is included in the next backup to <c>Mnesia</c>. Normally this
+ operation is not necessary, as all of the normal registry
+ 'set' functions do this automatically. However, if you have
+ retrieved the value of a string or binary object from the
+ registry and modified the contents, then the change is
+ invisible to the registry and the object is assumed to be
+ unmodified. This function allows you to make such modifications
+ and then let the registry know about them.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry containing the object.
+ </item>
+ <item><c>key</c> is the name of the object to mark.
+ </item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name>
- <fsummary>Get a floating point object</fsummary>
+ <name><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name>
+ <fsummary>Create and open a registry.</fsummary>
+ <type>
+ <v>int size;</v>
+ </type>
+ <desc>
+ <p>Opens (creates) a registry, which initially is empty. To
+ close the registry later, use <c>ei_reg_close()</c>.</p>
+ <p><c>size</c> is the approximate number of objects you
+ intend to store in the registry. As the registry uses a hash table
+ with collision chaining, no absolute upper limit exists on the
+ number of objects that can be stored in it. However, for reasons
+ of efficiency, it is a good idea to choose a number that is
+ appropriate for your needs. To change the size later, use
+ <c>ei_reg_resize()</c>. Notice that the number
+ you provide is increased to the nearest larger prime number.</p>
+ <p>Returns an empty registry on success, otherwise <c>NULL</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name>
+ <fsummary>Remove deleted objects.</fsummary>
<type>
<v>ei_reg *reg;</v>
- <v>const char *key;</v>
</type>
<desc>
- <p>Get the value associated with <c><![CDATA[key]]></c> in the
- registry. The value must be a floating point type.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
- up.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object to look up.
- </p>
- <p>On success, the function returns the value associated with <c><![CDATA[key]]></c>.
- If the object was not found or it was not a floating point
- object, -1.0 is returned. To avoid problems with in-band error
- reporting (i.e. if you cannot distinguish between -1.0 and a
- valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
- instead.</p>
+ <p>Removes all objects marked for deletion. When objects
+ are deleted with <c>ei_reg_delete()</c> they are not
+ removed from the registry, only marked for later removal.
+ On a later backup to <c>Mnesia</c>, the
+ objects can also be removed from the <c>Mnesia</c> table. If you are
+ not backing up to <c>Mnesia</c>, you may wish to remove the objects
+ manually with this function.</p>
+ <p><c>reg</c> is a registry containing objects marked for
+ deletion.</p>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name>
- <fsummary>Get a string object</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name>
+ <fsummary>Resize a registry.</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>int newsize;</v>
+ </type>
+ <desc>
+ <p>Changes the size of a registry.</p>
+ <p><c>newsize</c> is the new size to make the registry. The
+ number is increased to the nearest larger prime number.</p>
+ <p>On success, the registry is resized, all contents
+ rehashed, and <c>0</c> is returned. On failure, the
+ registry is left unchanged and <c>-1</c> is returned.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name>
+ <fsummary>Restore a registry from Mnesia.</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>ei_reg *reg;</v>
+ <v>const char *mntab;</v>
+ </type>
+ <desc>
+ <p>The contents of a <c>Mnesia</c> table are read into the registry.</p>
+ <list type="bulleted">
+ <item><c>fd</c> is an open connection to Erlang.
+ <c>Mnesia</c> 3.0 or later must be running on the Erlang node.
+ </item>
+ <item><c>reg</c> is the registry where the data is to be
+ placed.</item>
+ <item><c>mntab</c> is the name of the <c>Mnesia</c> table
+ to read data from.</item>
+ </list>
+ <p>Notice that only tables of a certain format can be
+ restored, that is, those that have been created and backed up to
+ with <c>ei_reg_dump()</c>. If the registry was not empty
+ before the operation, the contents of the table are added to the
+ contents of the registry. If the table contains objects with the
+ same keys as those already in the registry, the registry objects
+ are overwritten with the new values. If the registry
+ contains objects that were not in the table, they are
+ unchanged by this operation.</p>
+ <p>After the restore operation, the entire contents of the
+ registry is marked as unmodified. Notice that this includes any
+ objects that were modified before the restore and not
+ overwritten by the restore.</p>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name>
+ <fsummary>Assign a floating point object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
+ <v>double f;</v>
</type>
<desc>
- <p>Get the value associated with <c><![CDATA[key]]></c> in the
- registry. The value must be a string.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
- up.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object to look up.
- </p>
- <p>On success, the function returns the value associated with
- <c><![CDATA[key]]></c>. If the object was not found or it was not a string,
- NULL is returned. To avoid problems with in-band error
- reporting (i.e. if you cannot distinguish between NULL and a
- valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
- instead.</p>
+ <p>Creates a key-value pair with the specified <c>key</c>
+ and floating point value <c>f</c>. If an object already
+ exists with the same <c>key</c>, the new value replaces
+ the old one. If the previous value was a binary or string, it is
+ freed with <c>free()</c>.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object is to be
+ placed.</item>
+ <item><c>key</c> is the object name.</item>
+ <item><c>f</c> is the floating point value to assign.
+ </item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name>
- <fsummary>Get a binary object</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name>
+ <fsummary>Assign an integer object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
- <v>int size;</v>
+ <v>int i;</v>
</type>
<desc>
- <p>Get the value associated with <c><![CDATA[key]]></c> in the
- registry. The value must be a binary (pointer) type.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
- up.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object to look up.
- </p>
- <p><c><![CDATA[size]]></c> will be initialized to contain the length in
- bytes of the object, if it is found.
- </p>
- <p>On success, the function returns the value associated with
- <c><![CDATA[key]]></c> and indicates its length in <c><![CDATA[size]]></c>.
- If the object was not found or it was not a binary object,
- NULL is returned. To avoid problems with in-band error
- reporting (i.e. if you cannot distinguish between NULL and a
- valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
- instead.</p>
+ <p>Creates a key-value pair with the specified <c>key</c>
+ and integer value <c>i</c>. If an object already exists
+ with the same <c>key</c>, the new value replaces the old
+ one. If the previous value was a binary or string, it is freed with
+ <c>free()</c>.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object is to be
+ placed.</item>
+ <item><c>key</c> is the object name.</item>
+ <item><c>i</c> is the integer value to assign.</item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name>
- <fsummary>Get any object</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name>
+ <fsummary>Assign a binary object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
- <v>int flags;</v>
- <v>void *v (see below)</v>
+ <v>const void *p;</v>
+ <v>int size;</v>
</type>
<desc>
- <p>This is a general function for retrieving any kind of
- object from the registry.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
- up.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object to look up.
- </p>
- <p><c><![CDATA[flags]]></c> indicates the type of object that you are
- looking for. If <c><![CDATA[flags]]></c> is 0, then any kind of object will
- be returned. If <c><![CDATA[flags]]></c> is one of EI_INT, EI_FLT, EI_STR or
- EI_BIN, then only values of that kind will be returned. The
- buffer pointed to by <c><![CDATA[v]]></c> must be large enough to hold the return
- data, i.e. it must be a pointer to one of <c><![CDATA[int]]></c>,
- <c><![CDATA[double]]></c>, <c><![CDATA[char*]]></c> or <c><![CDATA[void*]]></c>, respectively. Also,
- if <c><![CDATA[flags]]></c> is EI_BIN, then a fifth argument <c><![CDATA[int *size]]></c> is required, so that the size of the object can be
- returned.
- </p>
- <p>If the function succeeds, <c><![CDATA[v]]></c> (and <c><![CDATA[size]]></c> if the
- object is binary) will be initialized with the value associated
- with <c><![CDATA[key]]></c>, and the function will return one of EI_INT,
- EI_FLT, EI_STR or EI_BIN, indicating the type of object. On failure the
- function will return -1 and the arguments will not be updated.</p>
+ <p>Creates a key-value pair with the specified <c>key</c>
+ whose "value" is the binary object pointed to by <c>p</c>.
+ If an object already exists with the same <c>key</c>,
+ the new value replaces the old one. If the previous value was a
+ binary or string, it is freed with <c>free()</c>.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object is to be
+ placed.</item>
+ <item><c>key</c> is the object name.</item>
+ <item><c>p</c> is a pointer to the binary object. The
+ object itself must have been created through a single call to
+ <c>malloc()</c> or a similar function, so that the
+ registry can later delete it if necessary by calling
+ <c>free()</c>.</item>
+ <item><c>size</c> is the length in bytes of the binary
+ object.</item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name>
- <fsummary>Mark an object as dirty </fsummary>
+ <name><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name>
+ <fsummary>Assign a string object.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
+ <v>const char *s;</v>
</type>
<desc>
- <p>Mark a registry object as dirty. This will ensure that
- it is included in the next backup to Mnesia. Normally this
- operation will not be necessary since all of the normal registry
- 'set' functions do this automatically. However if you have
- retrieved the value of a string or binary object from the
- registry and modified the contents, then the change will be
- invisible to the registry and the object will be assumed to be
- unmodified. This function allows you to make such modifications
- and then let the registry know about them.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry containing the object.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object to mark.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ <p>Creates a key-value pair with the specified <c>key</c>
+ whose "value" is the specified string <c>s</c>. If an
+ object already exists with the same <c>key</c>, the new
+ value replaces the old one. If the previous value was a binary or
+ string, it is freed with <c>free()</c>.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry where the object is to be
+ placed.</item>
+ <item><c>key</c> is the object name.</item>
+ <item><c>s</c> is the string to assign. The string itself
+ must have been created through a single call to
+ <c>malloc()</c> or similar a function,
+ so that the registry can later delete it if
+ necessary by calling <c>free()</c>.</item>
+ </list>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name>
- <fsummary>Delete an object from the registry</fsummary>
+ <name><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name>
+ <fsummary>Assign a value to any object type.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
+ <v>int flags;</v>
+ <v>v (see below)</v>
</type>
<desc>
- <p>Delete an object from the registry. The object is not
- actually removed from the registry, it is only marked for later
- removal so that on subsequent backups to Mnesia, the
- corresponding object can be removed from the Mnesia table as
- well. If another object is later created with the same key, the
- object will be reused.
- </p>
- <p>The object will be removed from the registry after a call to
- <c><![CDATA[ei_reg_dump()]]></c> or <c><![CDATA[ei_reg_purge()]]></c>.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry containing <c><![CDATA[key]]></c>.
- </p>
- <p><c><![CDATA[key]]></c> is the object to remove.
- </p>
- <p>If the object was found, the function returns 0 indicating
- success. Otherwise the function returns -1.</p>
+ <p>Creates a key-value pair with the specified <c>key</c>
+ whose value is specified by <c>v</c>. If an object already
+ exists with the same <c>key</c>, the new value replaces
+ the old one. If the previous value was a binary or string, it is freed
+ with <c>free()</c>.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>reg</c> is the registry where the object is to be
+ placed.</p>
+ </item>
+ <item>
+ <p><c>key</c> is the object name.</p>
+ </item>
+ <item>
+ <p><c>flags</c> indicates the type of the object
+ specified by <c>v</c>. Flags must be one of
+ <c>EI_INT</c>, <c>EI_FLT</c>, <c>EI_STR</c>, and <c>EI_BIN</c>,
+ indicating whether
+ <c>v</c> is <c>int</c>,
+ <c>double</c>, <c>char*</c>, or
+ <c>void*</c>.</p>
+ <p>If <c>flags</c> is <c>EI_BIN</c>, a fifth argument
+ <c>size</c> is required, indicating the size
+ in bytes of the object pointed to by <c>v</c>.</p>
+ </item>
+ </list>
+ <p>If you wish to store an arbitrary pointer in the registry,
+ specify a <c>size</c> of <c>0</c>. In this case, the
+ object itself is not transferred by an
+ <c>ei_reg_dump()</c> operation, only the pointer
+ value.</p>
+ <p>Returns <c>0</c> on success, otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name>
- <fsummary>Get object information</fsummary>
+ <fsummary>Get object information.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>const char *key;</v>
<v>struct ei_reg_stat *obuf;</v>
</type>
<desc>
- <p>Return information about an object.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry containing the object.
- </p>
- <p><c><![CDATA[key]]></c> is the name of the object.
- </p>
- <p><c><![CDATA[obuf]]></c> is a pointer to an <c><![CDATA[ei_reg_stat]]></c> structure,
- defined below:
- </p>
+ <p>Returns information about an object.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry containing the object.
+ </item>
+ <item><c>key</c> is the object name.</item>
+ <item><c>obuf</c> is a pointer to an
+ <c>ei_reg_stat</c> structure, defined as follows:</item>
+ </list>
<code type="none"><![CDATA[
struct ei_reg_stat {
int attr;
int size;
};
]]></code>
- <p>In <c><![CDATA[attr]]></c> the object's attributes are stored as the logical
- OR of its type (one of EI_INT, EI_FLT, EI_BIN and EI_STR),
- whether it is marked for deletion (EI_DELET) and whether it has
- been modified since the last backup to Mnesia (EI_DIRTY).
- </p>
- <p>The <c><![CDATA[size]]></c> field indicates the size in bytes required to store
- EI_STR (including the terminating 0) and EI_BIN objects, or 0
- for EI_INT and EI_FLT.
- </p>
- <p>The function returns 0 and initializes <c><![CDATA[obuf]]></c> on
- success, or returns -1 on failure.</p>
+ <p>In <c>attr</c> the attributes of the object are stored
+ as the logical <em>OR</em> of its type (one of <c>EI_INT</c>,
+ <c>EI_FLT</c>, <c>EI_BIN</c>, and <c>EI_STR</c>),
+ whether it is marked for deletion (<c>EI_DELET</c>), and whether it
+ has been modified since the last backup to <c>Mnesia</c>
+ (<c>EI_DIRTY</c>).</p>
+ <p>Field <c>size</c> indicates the size in bytes required
+ to store <c>EI_STR</c> (including the terminating <c>0</c>) and
+ <c>EI_BIN</c> objects, or <c>0</c> for <c>EI_INT</c> and
+ <c>EI_FLT</c>.</p>
+ <p>Returns <c>0</c> and initializes <c>obuf</c> on success,
+ otherwise <c>-1</c>.</p>
</desc>
</func>
+
<func>
<name><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name>
- <fsummary>Get registry information</fsummary>
+ <fsummary>Get registry information.</fsummary>
<type>
<v>ei_reg *reg;</v>
<v>struct ei_reg_tabstat *obuf;</v>
</type>
<desc>
- <p>Return information about a registry. Using information
+ <p>Returns information about a registry. Using information
returned by this function, you can see whether the size of the
- registry is suitable for the amount of data it contains.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry to return information about.
- </p>
- <p><c><![CDATA[obuf]]></c> is a pointer to an <c><![CDATA[ei_reg_tabstat]]></c> structure,
- defined below:
- </p>
+ registry is suitable for the amount of data it contains.</p>
+ <list type="bulleted">
+ <item><c>reg</c> is the registry to return information
+ about.</item>
+ <item><c>obuf</c> is a pointer to an
+ <c>ei_reg_tabstat</c> structure, defined as follows:
+ </item>
+ </list>
<code type="none"><![CDATA[
struct ei_reg_tabstat {
int size;
@@ -487,126 +615,23 @@ struct ei_reg_tabstat {
int collisions;
};
]]></code>
- <p>The <c><![CDATA[size]]></c> field indicates the number of hash positions
+ <p>Field <c>size</c> indicates the number of hash positions
in the registry. This is the number you provided when you
created or last resized the registry, rounded up to the nearest
- prime.
- </p>
- <p><c><![CDATA[nelem]]></c> indicates the number of elements stored in the
- registry. It includes objects that are deleted but not purged.
- </p>
- <p><c><![CDATA[npos]]></c> indicates the number of unique positions that are
- occupied in the registry.
- </p>
- <p><c><![CDATA[collisions]]></c> indicates how many elements are sharing
- positions in the registry.
- </p>
- <p>On success, the function returns 0 and <c><![CDATA[obuf]]></c> is
- initialized to contain table statistics. On failure, the function
- returns -1.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name>
- <fsummary>Back up a registry to Mnesia</fsummary>
- <type>
- <v>int fd;</v>
- <v>ei_reg *reg;</v>
- <v>const char *mntab;</v>
- <v>int flags;</v>
- </type>
- <desc>
- <p>Dump the contents of a registry to a Mnesia table in an
- atomic manner, i.e. either all data will be updated, or none of
- it will. If any errors are encountered while backing up
- the data, the entire operation is aborted.
- </p>
- <p><c><![CDATA[fd]]></c> is an open connection to Erlang.
- Mnesia 3.0 or later must be running on the Erlang node.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry to back up.
- </p>
- <p><c><![CDATA[mntab]]></c> is the name of the Mnesia table where the backed
- up data should be placed. If the table does not exist, it will
- be created automatically using configurable defaults. See your
- Mnesia documentation for information about configuring this
- behaviour.
- </p>
- <p>If <c><![CDATA[flags]]></c> is 0, the backup will include only those
- objects which have been created, modified or deleted since the
- last backup or restore (i.e. an incremental backup). After the
- backup, any objects that were marked dirty are now clean, and any
- objects that had been marked for deletion are deleted.
- </p>
- <p>Alternatively, setting flags to EI_FORCE will cause a full
- backup to be done, and EI_NOPURGE will cause the deleted objects
- to be left in the registry afterwards. These can be bitwise ORed
- together if both behaviours are desired. If EI_NOPURGE was
- specified, you can use <c><![CDATA[ei_reg_purge()]]></c> to explicitly remove
- the deleted items from the registry later.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name>
- <fsummary>Restore a registry from Mnesia</fsummary>
- <type>
- <v>int fd;</v>
- <v>ei_reg *reg;</v>
- <v>const char *mntab;</v>
- </type>
- <desc>
- <p>The contents of a Mnesia table are read into the
- registry.
- </p>
- <p><c><![CDATA[fd]]></c> is an open connection to Erlang.
- Mnesia 3.0 or later must be running on the Erlang node.
- </p>
- <p><c><![CDATA[reg]]></c> is the registry where the data should be placed.
- </p>
- <p><c><![CDATA[mntab]]></c> is the name of the Mnesia table to read data
- from.
- </p>
- <p>Note that only tables of a certain format can be
- restored, i.e. those that have been created and backed up to
- with <c><![CDATA[ei_reg_dump()]]></c>. If the registry was not empty before
- the operation, then the contents of the table are added to the
- contents of the registry. If the table contains objects with the
- same keys as those already in the registry, the registry objects
- will be overwritten with the new values. If the registry
- contains objects that were not in the table, they will be
- unchanged by this operation.
- </p>
- <p>After the restore operation, the entire contents of the
- registry is marked as unmodified. Note that this includes any
- objects that were modified before the restore and not
- overwritten by the restore.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name>
- <fsummary>Remove deleted objects</fsummary>
- <type>
- <v>ei_reg *reg;</v>
- </type>
- <desc>
- <p>Remove all objects marked for deletion. When objects
- are deleted with <c><![CDATA[ei_reg_delete()]]></c> they are not actually
- removed from the registry, only marked for later removal. This
- is so that on a subsequent backup to Mnesia, the
- objects can also be removed from the Mnesia table. If you are
- not backing up to Mnesia then you may wish to remove the objects
- manually with this function.
- </p>
- <p><c><![CDATA[reg]]></c> is a registry containing objects marked for
- deletion.
- </p>
- <p>The function returns 0 on success, or -1 on failure.</p>
+ prime number.</p>
+ <list type="bulleted">
+ <item><c>nelem</c> indicates the number of elements stored
+ in the registry. It includes objects that are deleted but not
+ purged.</item>
+ <item><c>npos</c> indicates the number of unique positions
+ that are occupied in the registry.</item>
+ <item><c>collisions</c> indicates how many elements are
+ sharing positions in the registry.</item>
+ </list>
+ <p>On success, <c>0</c> is returned and
+ <c>obuf</c> is initialized to contain table statistics,
+ otherwise <c>-1</c> is returned.</p>
</desc>
</func>
</funcs>
</cref>
-
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 6dc51adee1..c193fd804a 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -423,7 +423,7 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
}
#endif /* _REENTRANT */
- ec->creation = creation;
+ ec->creation = creation & 0x3; /* 2 bits */
if (cookie) {
if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) {
@@ -462,7 +462,7 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
strcpy(ec->self.node,thisnodename);
ec->self.num = 0;
ec->self.serial = 0;
- ec->self.creation = creation;
+ ec->self.creation = creation & 0x3; /* 2 bits */
if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL ||
(dbglevel = getenv("ERL_DEBUG_DIST")) != NULL)
@@ -1708,28 +1708,36 @@ error:
static int get_home(char *buf, int size)
{
- char* homedrive;
- char* homepath;
-
#ifdef __WIN32__
- homedrive = getenv("HOMEDRIVE");
- homepath = getenv("HOMEPATH");
-#else
- homedrive = "";
- homepath = getenv("HOME");
-#endif
+ char* homedrive = getenv("HOMEDRIVE");
+ char* homepath = getenv("HOMEPATH");
- if (!homedrive || !homepath) {
- buf[0] = '.';
- buf[1] = '\0';
- return 1;
- } else if (strlen(homedrive)+strlen(homepath) < size-1) {
+ if (homedrive && homepath) {
+ if (strlen(homedrive)+strlen(homepath) >= size)
+ return 0;
strcpy(buf, homedrive);
strcat(buf, homepath);
return 1;
}
-
- return 0;
+ else {
+ int len = GetWindowsDirectory(buf, size);
+ if (len) {
+ return (len < size);
+ }
+ }
+#else
+ char* homepath = getenv("HOME");
+ if (homepath) {
+ if (strlen(homepath) >= size)
+ return 0;
+ strcpy(buf, homepath);
+ return 1;
+ }
+#endif
+
+ buf[0] = '.';
+ buf[1] = '\0';
+ return 1;
}
diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h
index fbb61b0ccf..bded811a35 100644
--- a/lib/erl_interface/src/misc/ei_portio.h
+++ b/lib/erl_interface/src/misc/ei_portio.h
@@ -21,7 +21,7 @@
*/
#ifndef _EI_PORTIO_H
#define _EI_PORTIO_H
-#if !defined(__WIN32__) || !defined(VXWORKS)
+#if !defined(__WIN32__) && !defined(VXWORKS)
#ifdef HAVE_WRITEV
/* Declaration of struct iovec *iov should be visible in this scope. */
#include <sys/uio.h>
diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c
index d8f0632341..670a5900c9 100644
--- a/lib/erl_interface/src/prog/erl_start.c
+++ b/lib/erl_interface/src/prog/erl_start.c
@@ -17,7 +17,6 @@
*
* %CopyrightEnd%
*
-
*/
/* An exception from using eidef.h, use config.h directly */
@@ -45,7 +44,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <netinet/tcp.h>
+#include <netinet/tcp.h>
#include <symLib.h>
#include <sysSymTbl.h>
#include <sysLib.h>
@@ -117,9 +116,9 @@ static int unique_id(void);
static unsigned long spawn_erlang_epmd(ei_cnode *ec,
char *alive,
Erl_IpAddr adr,
- int flags,
- char *erl_or_epmd,
- char *args[],
+ int flags,
+ char *erl_or_epmd,
+ char *args[],
int port,
int is_erlang);
#else
@@ -161,10 +160,10 @@ int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
r = ERL_SYS_ERROR;
goto done;
}
-
+
memset(&addr,0,sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
if (bind(sockd,(struct sockaddr *)&addr,sizeof(addr))<0) {
@@ -179,12 +178,12 @@ int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
listen(sockd,5);
#if defined(VXWORKS) || defined(__WIN32__)
- if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1))
+ if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1))
== 0)
return ERL_SYS_ERROR;
timeout.tv_usec = 0;
timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
- if((r = wait_for_erlang(sockd,unique_id(),&timeout))
+ if((r = wait_for_erlang(sockd,unique_id(),&timeout))
== ERL_TIMEOUT) {
#if defined(VXWORKS)
taskDelete((int) pid);
@@ -262,7 +261,7 @@ done:
static int unique_id(void){
#if defined(VXWORKS)
return taskIdSelf();
-#else
+#else
return (int) GetCurrentThreadId();
#endif
}
@@ -285,7 +284,7 @@ static int enquote_args(char **oargs, char ***qargs){
for(len=0;oargs[len] != NULL; ++len)
;
args = malloc(sizeof(char *) * (len + 1));
-
+
for(i = 0; i < len; ++i){
qwhole = strchr(oargs[i],' ') != NULL;
extra = qwhole * 2;
@@ -337,16 +336,16 @@ static FUNCPTR lookup_function(char *symname){
static unsigned long spawn_erlang_epmd(ei_cnode *ec,
char *alive,
Erl_IpAddr adr,
- int flags,
- char *erl_or_epmd,
- char *args[],
+ int flags,
+ char *erl_or_epmd,
+ char *args[],
int port,
int is_erlang)
{
#if defined(VXWORKS)
FUNCPTR erlfunc;
#else /* Windows */
- STARTUPINFO sinfo;
+ STARTUPINFO sinfo;
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION pinfo;
#endif
@@ -364,7 +363,7 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
if(is_erlang){
get_addr(ei_thishostname(ec), &myaddr);
#if defined(VXWORKS)
- inet_ntoa_b(myaddr, iaddrbuf);
+ inet_ntoa_b(myaddr, iaddrbuf);
#else /* Windows */
if((ptr = inet_ntoa(myaddr)) == NULL)
return 0;
@@ -372,7 +371,7 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
strcpy(iaddrbuf,ptr);
#endif
}
- if ((flags & ERL_START_REMOTE) ||
+ if ((flags & ERL_START_REMOTE) ||
(is_erlang && (hisaddr->s_addr != myaddr.s_addr))) {
return 0;
} else {
@@ -382,19 +381,17 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
#if !defined(VXWORKS)
/* On VxWorks, we dont actually run a command,
we call start_erl() */
- if(!erl_or_epmd)
+ if(!erl_or_epmd)
#endif
erl_or_epmd = (is_erlang) ? DEF_ERL_COMMAND :
DEF_EPMD_COMMAND;
if(is_erlang){
name_format = (flags & ERL_START_LONG) ? ERL_NAME_FMT :
ERL_SNAME_FMT;
- cmdlen +=
+ cmdlen +=
strlen(erl_or_epmd) + (*erl_or_epmd != '\0') +
strlen(name_format) + 1 + strlen(alive) +
- strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) +
- 2 * FORMATTED_INT_LEN +
- 1;
+ strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) + 2 * FORMATTED_INT_LEN + 1;
ptr = cmdbuf = malloc(cmdlen);
if(*erl_or_epmd != '\0')
ptr += sprintf(ptr,"%s ",erl_or_epmd);
@@ -484,11 +481,11 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
* arguments we use here.
*/
static int exec_erlang(ei_cnode *ec,
- char *alive,
+ char *alive,
Erl_IpAddr adr,
- int flags,
- char *erl,
- char *args[],
+ int flags,
+ char *erl,
+ char *args[],
int port)
{
#if !defined(__WIN32__) && !defined(VXWORKS)
@@ -498,8 +495,11 @@ static int exec_erlang(ei_cnode *ec,
char argbuf[BUFSIZ];
struct in_addr myaddr;
struct in_addr *hisaddr = (struct in_addr *)adr;
-
- get_addr(ei_thishostname(ec), &myaddr);
+
+ if (!get_addr(ei_thishostname(ec), &myaddr)) {
+ fprintf(stderr,"erl_call: failed to find hostname\r\n");
+ return ERL_SYS_ERROR;
+ }
/* on this host? */
/* compare ip addresses, unless forced by flag setting to use rsh */
@@ -525,8 +525,8 @@ static int exec_erlang(ei_cnode *ec,
/* *must* be noinput or node (seems to) hang... */
/* long or short names? */
- sprintf(&argbuf[len], "-noinput %s %s ",
- ((flags & ERL_START_LONG) ? "-name" : "-sname"),
+ sprintf(&argbuf[len], "-noinput %s %s ",
+ ((flags & ERL_START_LONG) ? "-name" : "-sname"),
alive);
len = strlen(argbuf);
@@ -572,7 +572,7 @@ static int exec_erlang(ei_cnode *ec,
fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t));
fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
}
- }
+ }
/* start the system */
execvp(argv[0], argv);
@@ -609,7 +609,7 @@ static void gettimeofday(struct timeval *now, void *dummy){
now->tv_usec = ((ctick - (now->tv_sec * rate))*1000000)/rate;
}
#endif
-
+
/* wait for the remote system to reply */
/*
@@ -648,7 +648,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
"will timeout at %ld.%06ld\n",
now.tv_sec,now.tv_usec,stop_time.tv_sec,stop_time.tv_usec);
#endif
-
+
while (1) {
FD_ZERO(&rdset);
FD_SET(sockd,&rdset);
@@ -662,7 +662,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
to.tv_sec--;
}
if (to.tv_sec < 0) return ERL_TIMEOUT;
-
+
#ifdef DEBUG
fprintf(stderr,"erl_call: debug remaining to timeout: %ld.%06ld\n",
to.tv_sec,to.tv_usec);
@@ -690,7 +690,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
if (FD_ISSET(sockd,&rdset)) {
if ((fd = accept(sockd,(struct sockaddr *)&peer,&len)) < 0)
return ERL_SYS_ERROR;
-
+
/* now get sign-on message and terminate it */
#if defined(__WIN32__)
if ((n=recv(fd,buf,16,0)) >= 0) buf[n]=0x0;
@@ -703,7 +703,6 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
fprintf(stderr,"erl_call: debug got %d, expected %d\n",
atoi(buf),magic);
#endif
-
if (atoi(buf) == magic) return 0; /* success */
} /* if FD_SET */
} /* switch */
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 33705d1e8b..563694a0c1 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.9
+EI_VSN = 3.9.3
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index 88602e8222..8509f44ffc 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -33,6 +33,39 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The address to the FSF in the license header has been
+ updated.</p>
+ <p>
+ Own Id: OTP-14084</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eunit 2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When asserts were moved out to a separate header file,
+ the automatic enabling of asserts when testing is enabled
+ stopped working.</p>
+ <p>
+ Own Id: OTP-13892</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.3</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index 7fd6c206a4..0f7a15f669 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Copyright (C) 2004-2006 Mickaël Rémond, Richard Carlsson
@@ -51,7 +51,9 @@
%% note that the main switch used within this file is NOTEST; however,
%% both TEST and EUNIT may be used to check whether testing is enabled
-ifndef(NOTEST).
--undef(NOASSERT). % testing requires that assertions are enabled
+-ifndef(ASSERT).
+-define(ASSERT, true). % testing requires that assertions are enabled
+-endif.
-ifndef(TEST).
-define(TEST, true).
-endif.
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index fbfd123c43..1009d76d5b 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2004-2009 Mickaël Rémond, Richard Carlsson
diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl
index 7bb78f5ea8..a3eb64f9c8 100644
--- a/lib/eunit/src/eunit_autoexport.erl
+++ b/lib/eunit/src/eunit_autoexport.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl
index cc002cb449..cea7bcd5c5 100644
--- a/lib/eunit/src/eunit_data.erl
+++ b/lib/eunit/src/eunit_data.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl
index 9dbb4835f8..b19f50b990 100644
--- a/lib/eunit/src/eunit_lib.erl
+++ b/lib/eunit/src/eunit_lib.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2004-2007 Mickaël Rémond, Richard Carlsson
diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl
index 8bdf94c877..c6bb8bdbb3 100644
--- a/lib/eunit/src/eunit_proc.erl
+++ b/lib/eunit/src/eunit_proc.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_serial.erl b/lib/eunit/src/eunit_serial.erl
index da76064a53..bbda4400da 100644
--- a/lib/eunit/src/eunit_serial.erl
+++ b/lib/eunit/src/eunit_serial.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_server.erl b/lib/eunit/src/eunit_server.erl
index 387976eba1..e767822543 100644
--- a/lib/eunit/src/eunit_server.erl
+++ b/lib/eunit/src/eunit_server.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_striptests.erl b/lib/eunit/src/eunit_striptests.erl
index c6ade389ba..ae1a834662 100644
--- a/lib/eunit/src/eunit_striptests.erl
+++ b/lib/eunit/src/eunit_striptests.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index 1b468551d8..a70b8bfd4c 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Mickaël Rémond <[email protected]>
diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl
index 62d30b1930..f2b9fa46f2 100644
--- a/lib/eunit/src/eunit_test.erl
+++ b/lib/eunit/src/eunit_test.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl
index 5dee1cb49e..7aadefb29f 100644
--- a/lib/eunit/src/eunit_tests.erl
+++ b/lib/eunit/src/eunit_tests.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl
index f604ca5ba3..1fbc4edd45 100644
--- a/lib/eunit/src/eunit_tty.erl
+++ b/lib/eunit/src/eunit_tty.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index b551ee6eb6..7eee75ee10 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.3
+EUNIT_VSN = 2.3.2
diff --git a/lib/gs/doc/src/Makefile b/lib/gs/doc/src/Makefile
index b270bc84fe..a24ec77e31 100644
--- a/lib/gs/doc/src/Makefile
+++ b/lib/gs/doc/src/Makefile
@@ -148,7 +148,7 @@ release_docs_spec: docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- (/bin/cp -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ ($(CP) -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
diff --git a/lib/gs/doc/src/notes.xml b/lib/gs/doc/src/notes.xml
index 20188c75e2..4f3f0645a5 100644
--- a/lib/gs/doc/src/notes.xml
+++ b/lib/gs/doc/src/notes.xml
@@ -31,7 +31,23 @@
</header>
<p>This document describes the changes made to the GS application.</p>
- <section><title>GS 1.6.1</title>
+ <section><title>GS 1.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Update build scripts to not make assumtions about where
+ env, cp and perl are located.</p>
+ <p>
+ Own Id: OTP-13800</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>GS 1.6.1</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/gs/vsn.mk b/lib/gs/vsn.mk
index c762507bab..d2c5d15a96 100644
--- a/lib/gs/vsn.mk
+++ b/lib/gs/vsn.mk
@@ -1,2 +1,2 @@
-GS_VSN = 1.6.1
+GS_VSN = 1.6.2
diff --git a/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl b/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
index 5451f1fe7d..b1f7bd7572 100644
--- a/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
+++ b/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
@@ -87,22 +87,29 @@ do_fp_unop(I, TempMap) ->
%%% Fix an fmove op.
do_fmove(I, TempMap) ->
#fmove{src=Src,dst=Dst} = I,
- case is_mem_opnd(Dst, TempMap) and is_mem_opnd(Src, TempMap) of
+ case
+ (is_mem_opnd(Src, TempMap) andalso is_mem_opnd(Dst, TempMap))
+ orelse (is_mem_opnd(Src, TempMap) andalso (not is_float_temp(Dst)))
+ orelse ((not is_float_temp(Src)) andalso is_mem_opnd(Dst, TempMap))
+ of
true ->
- Tmp = clone(Src),
+ Tmp = spill_temp(double),
{[#fmove{src=Src, dst=Tmp},I#fmove{src=Tmp,dst=Dst}],
true};
false ->
{[I], false}
end.
+is_float_temp(#x86_temp{type=Type}) -> Type =:= double;
+is_float_temp(#x86_mem{}) -> false.
+
%%% Check if an operand denotes a memory cell (mem or pseudo).
is_mem_opnd(Opnd, TempMap) ->
R =
case Opnd of
#x86_mem{} -> true;
- #x86_temp{} ->
+ #x86_temp{type=double} ->
Reg = hipe_x86:temp_reg(Opnd),
case hipe_x86:temp_is_allocatable(Opnd) of
true ->
@@ -176,6 +183,9 @@ clone(Dst) ->
#x86_mem{} -> hipe_x86:mem_type(Dst);
#x86_temp{} -> hipe_x86:temp_type(Dst)
end,
+ spill_temp(Type).
+
+spill_temp(Type) ->
hipe_x86:mk_new_temp(Type).
%%% Make a certain reg into a clone of Dst
diff --git a/lib/hipe/arm/hipe_arm_registers.erl b/lib/hipe/arm/hipe_arm_registers.erl
index 24cd929d41..dcf039676b 100644
--- a/lib/hipe/arm/hipe_arm_registers.erl
+++ b/lib/hipe/arm/hipe_arm_registers.erl
@@ -67,6 +67,8 @@
-define(R15, 15).
-define(LAST_PRECOLOURED, 15). % must handle both GPR and FPR ranges
+-define(LR, ?R14).
+
-define(ARG0, ?R1).
-define(ARG1, ?R2).
-define(ARG2, ?R3).
@@ -114,7 +116,7 @@ stack_pointer() -> ?STACK_POINTER.
proc_pointer() -> ?PROC_POINTER.
-lr() -> ?R14.
+lr() -> ?LR.
pc() -> ?R15.
@@ -198,7 +200,9 @@ call_clobbered() -> % does the RA strip the type or not?
].
tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}].
+ [{?TEMP1,tagged},{?TEMP1,untagged}
+ ,{?LR,tagged},{?LR,untagged}
+ ].
live_at_return() ->
[%%{?LR,untagged},
diff --git a/lib/hipe/arm/hipe_rtl_to_arm.erl b/lib/hipe/arm/hipe_rtl_to_arm.erl
index ad5a559995..93342aba33 100644
--- a/lib/hipe/arm/hipe_rtl_to_arm.erl
+++ b/lib/hipe/arm/hipe_rtl_to_arm.erl
@@ -148,10 +148,11 @@ mk_shift_ir(S, Dst, Src1, ShiftOp, Src2) ->
mk_li(Tmp, Src1,
mk_shift_rr(S, Dst, Tmp, ShiftOp, Src2)).
-mk_shift_ri(S, Dst, Src1, ShiftOp, Src2) when is_integer(Src2) ->
- if Src2 >= 0, Src2 < 32 -> ok;
- true -> io:format("~w: excessive immediate shift ~w\n", [?MODULE,Src2])
- end,
+mk_shift_ri(S, Dst, Src1, ShiftOp, 0)
+ when ShiftOp =:= lsl; ShiftOp =:= lsr; ShiftOp =:= asr ->
+ [hipe_arm:mk_move(S, Dst, Src1)];
+mk_shift_ri(S, Dst, Src1, ShiftOp, Src2)
+ when is_integer(Src2), Src2 > 0, Src2 < 32 ->
Am1 = {Src1,ShiftOp,Src2},
[hipe_arm:mk_move(S, Dst, Am1)].
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 9453ca6c6f..230fce2e68 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -124,7 +124,7 @@
t_map_entries/2,
t_map_put/3,
t_map_update/3,
- map_pairwise_merge/3
+ t_map_pairwise_merge/4
]).
-ifdef(DO_ERL_BIF_TYPES_TEST).
@@ -1689,10 +1689,10 @@ type(maps, merge, 2, Xs, Opaques) ->
BDefK = t_map_def_key(MapB, Opaques),
ADefV = t_map_def_val(MapA, Opaques),
BDefV = t_map_def_val(MapB, Opaques),
- t_map(map_pairwise_merge(
+ t_map(t_map_pairwise_merge(
fun(K, _, _, mandatory, V) -> {K, mandatory, V};
(K, MNess, VA, optional, VB) -> {K, MNess, t_sup(VA,VB)}
- end, MapA, MapB),
+ end, MapA, MapB, Opaques),
t_sup(ADefK, BDefK), t_sup(ADefV, BDefV))
end, Opaques);
type(maps, put, 3, Xs, Opaques) ->
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 7826dada9d..a5a3e8c136 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -159,6 +159,7 @@
t_map_get/2, t_map_get/3,
t_map_is_key/2, t_map_is_key/3,
t_map_update/2, t_map_update/3,
+ t_map_pairwise_merge/4,
t_map_put/2, t_map_put/3,
t_matchstate/0,
t_matchstate/2,
@@ -219,8 +220,7 @@
is_erl_type/1,
atom_to_string/1,
var_table__new/0,
- cache__new/0,
- map_pairwise_merge/3
+ cache__new/0
]).
%%-define(DO_ERL_TYPES_TEST, true).
@@ -236,7 +236,8 @@
-export([t_is_identifier/1]).
-endif.
--export_type([erl_type/0, opaques/0, type_table/0, var_table/0, cache/0]).
+-export_type([erl_type/0, opaques/0, type_table/0, mod_records/0,
+ var_table/0, cache/0]).
%%-define(DEBUG, true).
@@ -379,8 +380,9 @@
-type type_value() :: {{module(), {file:name(), erl_anno:line()},
erl_parse:abstract_type(), ArgNames :: [atom()]},
erl_type()}.
--type type_table() :: dict:dict(record_key() | type_key(),
- record_value() | type_value()).
+-type type_table() :: #{record_key() | type_key() =>
+ record_value() | type_value()}.
+-type mod_records() :: dict:dict(module(), type_table()).
-opaque var_table() :: #{atom() => erl_type()}.
@@ -494,9 +496,9 @@ t_contains_opaque(?function(Domain, Range), Opaques) ->
t_contains_opaque(Domain, Opaques)
orelse t_contains_opaque(Range, Opaques);
t_contains_opaque(?identifier(_Types), _Opaques) -> false;
-t_contains_opaque(?integer(_Types), _Opaques) -> false;
t_contains_opaque(?int_range(_From, _To), _Opaques) -> false;
t_contains_opaque(?int_set(_Set), _Opaques) -> false;
+t_contains_opaque(?integer(_Types), _Opaques) -> false;
t_contains_opaque(?list(Type, Tail, _), Opaques) ->
t_contains_opaque(Type, Opaques) orelse t_contains_opaque(Tail, Opaques);
t_contains_opaque(?map(_, _, _) = Map, Opaques) ->
@@ -524,7 +526,8 @@ list_contains_opaque(List, Opaques) ->
lists:any(fun(E) -> t_contains_opaque(E, Opaques) end, List).
%% t_find_opaque_mismatch/2 of two types should only be used if their
-%% t_inf is t_none() due to some opaque type violation.
+%% t_inf is t_none() due to some opaque type violation. However,
+%% 'error' is returned if a structure mismatch is found.
%%
%% The first argument of the function is the pattern and its second
%% argument the type we are matching against the pattern.
@@ -533,22 +536,30 @@ list_contains_opaque(List, Opaques) ->
'error' | {'ok', erl_type(), erl_type()}.
t_find_opaque_mismatch(T1, T2, Opaques) ->
- t_find_opaque_mismatch(T1, T2, T2, Opaques).
+ catch t_find_opaque_mismatch(T1, T2, T2, Opaques).
t_find_opaque_mismatch(?any, _Type, _TopType, _Opaques) -> error;
-t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> error;
+t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> throw(error);
t_find_opaque_mismatch(?list(T1, Tl1, _), ?list(T2, Tl2, _), TopType, Opaques) ->
t_find_opaque_mismatch_ordlists([T1, Tl1], [T2, Tl2], TopType, Opaques);
t_find_opaque_mismatch(T1, ?opaque(_) = T2, TopType, Opaques) ->
case is_opaque_type(T2, Opaques) of
- false -> {ok, TopType, T2};
+ false ->
+ case t_is_opaque(T1) andalso compatible_opaque_types(T1, T2) =/= [] of
+ true -> error;
+ false -> {ok, TopType, T2}
+ end;
true ->
t_find_opaque_mismatch(T1, t_opaque_structure(T2), TopType, Opaques)
end;
t_find_opaque_mismatch(?opaque(_) = T1, T2, TopType, Opaques) ->
%% The generated message is somewhat misleading:
case is_opaque_type(T1, Opaques) of
- false -> {ok, TopType, T1};
+ false ->
+ case t_is_opaque(T2) andalso compatible_opaque_types(T1, T2) =/= [] of
+ true -> error;
+ false -> {ok, TopType, T1}
+ end;
true ->
t_find_opaque_mismatch(t_opaque_structure(T1), T2, TopType, Opaques)
end;
@@ -564,7 +575,11 @@ t_find_opaque_mismatch(?tuple(_, _, _) = T1, ?tuple_set(_) = T2,
t_find_opaque_mismatch_lists(Tuples1, Tuples2, TopType, Opaques);
t_find_opaque_mismatch(T1, ?union(U2), TopType, Opaques) ->
t_find_opaque_mismatch_lists([T1], U2, TopType, Opaques);
-t_find_opaque_mismatch(_T1, _T2, _TopType, _Opaques) -> error.
+t_find_opaque_mismatch(T1, T2, _TopType, Opaques) ->
+ case t_is_none(t_inf(T1, T2, Opaques)) of
+ false -> error;
+ true -> throw(error)
+ end.
t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
List = lists:zipwith(fun(T1, T2) ->
@@ -573,10 +588,11 @@ t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
t_find_opaque_mismatch_list(List).
t_find_opaque_mismatch_lists(L1, L2, _TopType, Opaques) ->
- List = [t_find_opaque_mismatch(T1, T2, T2, Opaques) || T1 <- L1, T2 <- L2],
+ List = [catch t_find_opaque_mismatch(T1, T2, T2, Opaques) ||
+ T1 <- L1, T2 <- L2],
t_find_opaque_mismatch_list(List).
-t_find_opaque_mismatch_list([]) -> error;
+t_find_opaque_mismatch_list([]) -> throw(error);
t_find_opaque_mismatch_list([H|T]) ->
case H of
{ok, _T1, _T2} -> H;
@@ -611,9 +627,13 @@ t_decorate_with_opaque(T1, T2, Opaques) ->
false -> T1;
true ->
R = decorate(T1, T, Opaques),
- ?debug(case catch t_is_equal(t_unopaque(R), t_unopaque(T1)) of
- true -> ok;
- false ->
+ ?debug(case catch
+ not t_is_equal(t_unopaque(R), t_unopaque(T1))
+ orelse
+ t_is_equal(T1, T) andalso not t_is_equal(T1, R)
+ of
+ false -> ok;
+ _ ->
io:format("T1 = ~p,\n", [T1]),
io:format("T2 = ~p,\n", [T2]),
io:format("O = ~p,\n", [Opaques]),
@@ -642,7 +662,6 @@ decorate(?tuple_set(List), ?tuple_set(L), Opaques) ->
decorate(?union(List), T, Opaques) when T =/= ?any ->
?union(L) = force_union(T),
union_decorate(List, L, Opaques);
-decorate(?opaque(_)=T, _, _Opaques) -> T;
decorate(T, ?union(L), Opaques) when T =/= ?any ->
?union(List) = force_union(T),
union_decorate(List, L, Opaques);
@@ -656,7 +675,7 @@ decorate_with_opaque(Type, ?opaque(Set2), Opaques) ->
case decoration(set_to_list(Set2), Type, Opaques, [], false) of
{[], false} -> Type;
{List, All} when List =/= [] ->
- NewType = ?opaque(ordsets:from_list(List)),
+ NewType = sup_opaque(List),
case All of
true -> NewType;
false -> t_sup(NewType, Type)
@@ -670,9 +689,10 @@ decoration([#opaque{struct = S} = Opaque|OpaqueTypes], Type, Opaques,
case not IsOpaque orelse t_is_none(I) of
true -> decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes0, All);
false ->
- NewOpaque = Opaque#opaque{struct = decorate(I, S, Opaques)},
+ NewI = decorate(I, S, Opaques),
+ NewOpaque = combine(NewI, [Opaque]),
NewAll = All orelse t_is_equal(I, Type),
- NewOpaqueTypes = [NewOpaque|NewOpaqueTypes0],
+ NewOpaqueTypes = NewOpaque ++ NewOpaqueTypes0,
decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes, NewAll)
end;
decoration([], _Type, _Opaques, NewOpaqueTypes, All) ->
@@ -745,16 +765,16 @@ decorate_tuples_in_sets([], _L, _Opaques, Acc) ->
-spec t_opaque_from_records(type_table()) -> [erl_type()].
-t_opaque_from_records(RecDict) ->
- OpaqueRecDict =
- dict:filter(fun(Key, _Value) ->
+t_opaque_from_records(RecMap) ->
+ OpaqueRecMap =
+ maps:filter(fun(Key, _Value) ->
case Key of
{opaque, _Name, _Arity} -> true;
_ -> false
end
- end, RecDict),
- OpaqueTypeDict =
- dict:map(fun({opaque, Name, _Arity},
+ end, RecMap),
+ OpaqueTypeMap =
+ maps:map(fun({opaque, Name, _Arity},
{{Module, _FileLine, _Form, ArgNames}, _Type}) ->
%% Args = args_to_types(ArgNames),
%% List = lists:zip(ArgNames, Args),
@@ -763,8 +783,8 @@ t_opaque_from_records(RecDict) ->
Rep = t_any(), % not used for anything right now
Args = [t_any() || _ <- ArgNames],
t_opaque(Module, Name, Args, Rep)
- end, OpaqueRecDict),
- [OpaqueType || {_Key, OpaqueType} <- dict:to_list(OpaqueTypeDict)].
+ end, OpaqueRecMap),
+ [OpaqueType || {_Key, OpaqueType} <- maps:to_list(OpaqueTypeMap)].
%% Decompose opaque instances of type arg2 to structured types, in arg1
%% XXX: Same as t_unopaque
@@ -798,10 +818,6 @@ list_struct_from_opaque(Types, Opaques) ->
[t_struct_from_opaque(Type, Opaques) || Type <- Types].
%%-----------------------------------------------------------------------------
-
--type mod_records() :: dict:dict(module(), type_table()).
-
-%%-----------------------------------------------------------------------------
%% Unit type. Signals non termination.
%%
@@ -1664,10 +1680,12 @@ t_map(Pairs0, DefK0, DefV0) ->
%% define(DEBUG, true).
try
validate_map_elements(Pairs)
- catch error:badarg -> error(badarg, [Pairs0,DefK0,DefV0]);
- error:{badarg, E} -> error({badarg, E}, [Pairs0,DefK0,DefV0])
+ catch error:badarg -> error(badarg, [Pairs0,DefK0,DefV0])
end,
- ?map(Pairs, DefK, DefV).
+ case map_pairs_are_none(Pairs) of
+ true -> ?none;
+ false -> ?map(Pairs, DefK, DefV)
+ end.
normalise_map_optionals([], _, _) -> [];
normalise_map_optionals([E={K,?opt,?none}|T], DefK, DefV) ->
@@ -1684,7 +1702,6 @@ normalise_map_optionals([E={K,?opt,V}|T], DefK, DefV) ->
normalise_map_optionals([E|T], DefK, DefV) ->
[E|normalise_map_optionals(T, DefK, DefV)].
-validate_map_elements([{_,?mand,?none}|_]) -> error({badarg, none_in_mand});
validate_map_elements([{K1,_,_}|Rest=[{K2,_,_}|_]]) ->
case is_singleton_type(K1) andalso K1 < K2 of
false -> error(badarg);
@@ -1697,6 +1714,10 @@ validate_map_elements([{K,_,_}]) ->
end;
validate_map_elements([]) -> true.
+map_pairs_are_none([]) -> false;
+map_pairs_are_none([{_,?mand,?none}|_]) -> true;
+map_pairs_are_none([_|Ps]) -> map_pairs_are_none(Ps).
+
-spec t_is_map(erl_type()) -> boolean().
t_is_map(Type) ->
@@ -1763,13 +1784,26 @@ mapdict_insert(E1={K1,_,_}, [E2={K2,_,_}|T]) when K1 > K2 ->
[E2|mapdict_insert(E1, T)];
mapdict_insert(E={_,_,_}, T) -> [E|T].
+-type map_pairwise_merge_fun() :: fun((erl_type(),
+ t_map_mandatoriness(), erl_type(),
+ t_map_mandatoriness(), erl_type())
+ -> t_map_pair() | false).
+
+-spec t_map_pairwise_merge(map_pairwise_merge_fun(), erl_type(), erl_type(),
+ opaques()) -> t_map_dict().
+t_map_pairwise_merge(F, MapA, MapB, Opaques) ->
+ do_opaque(MapA, Opaques,
+ fun(UMapA) ->
+ do_opaque(MapB, Opaques,
+ fun(UMapB) ->
+ map_pairwise_merge(F, UMapA, UMapB)
+ end)
+ end).
+
%% Merges the pairs of two maps together. Missing pairs become (?opt, DefV) or
%% (?opt, ?none), depending on whether K \in DefK.
--spec map_pairwise_merge(fun((erl_type(),
- t_map_mandatoriness(), erl_type(),
- t_map_mandatoriness(), erl_type())
- -> t_map_pair() | false),
- erl_type(), erl_type()) -> t_map_dict().
+-spec map_pairwise_merge(map_pairwise_merge_fun(), erl_type(), erl_type())
+ -> t_map_dict().
map_pairwise_merge(F, ?map(APairs, ADefK, ADefV),
?map(BPairs, BDefK, BDefV)) ->
map_pairwise_merge(F, APairs, ADefK, ADefV, BPairs, BDefK, BDefV).
@@ -2223,16 +2257,21 @@ t_has_var_list([]) -> false.
-spec t_collect_vars(erl_type()) -> [erl_type()].
t_collect_vars(T) ->
- t_collect_vars(T, []).
+ Vs = t_collect_vars(T, maps:new()),
+ [V || {V, _} <- maps:to_list(Vs)].
+
+-type ctab() :: #{erl_type() => 'any'}.
--spec t_collect_vars(erl_type(), [erl_type()]) -> [erl_type()].
+-spec t_collect_vars(erl_type(), ctab()) -> ctab().
t_collect_vars(?var(_) = Var, Acc) ->
- ordsets:add_element(Var, Acc);
+ maps:put(Var, any, Acc);
t_collect_vars(?function(Domain, Range), Acc) ->
- ordsets:union(t_collect_vars(Domain, Acc), t_collect_vars(Range, []));
+ Acc1 = t_collect_vars(Domain, Acc),
+ t_collect_vars(Range, Acc1);
t_collect_vars(?list(Contents, Termination, _), Acc) ->
- ordsets:union(t_collect_vars(Contents, Acc), t_collect_vars(Termination, []));
+ Acc1 = t_collect_vars(Contents, Acc),
+ t_collect_vars(Termination, Acc1);
t_collect_vars(?product(Types), Acc) ->
t_collect_vars_list(Types, Acc);
t_collect_vars(?tuple(?any, ?any, ?any), Acc) ->
@@ -2833,12 +2872,7 @@ t_inf(?map(_, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B, _Opaques) ->
%% becomes mandatory in the infinumum
(K, _, V1, _, V2) -> {K, ?mand, t_inf(V1, V2)}
end, A, B),
- %% If the infinimum of any mandatory values is ?none, the entire map infinimum
- %% is ?none.
- case lists:any(fun({_,?mand,?none})->true; ({_,_,_}) -> false end, Pairs) of
- true -> t_none();
- false -> t_map(Pairs, t_inf(ADefK, BDefK), t_inf(ADefV, BDefV))
- end;
+ t_map(Pairs, t_inf(ADefK, BDefK), t_inf(ADefV, BDefV));
t_inf(?matchstate(Pres1, Slots1), ?matchstate(Pres2, Slots2), _Opaques) ->
?matchstate(t_inf(Pres1, Pres2), t_inf(Slots1, Slots2));
t_inf(?nil, ?nil, _Opaques) -> ?nil;
@@ -2978,27 +3012,21 @@ inf_collect(_T1, [], _Opaques, OpL) ->
OpL.
combine(S, T1, T2) ->
- #opaque{mod = Mod1, name = Name1, args = Args1} = T1,
- #opaque{mod = Mod2, name = Name2, args = Args2} = T2,
- Comb1 = comb(Mod1, Name1, Args1, S, T1),
- case is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}) of
- true -> Comb1;
- false -> Comb1 ++ comb(Mod2, Name2, Args2, S, T2)
+ case is_compat_opaque_names(T1, T2) of
+ true -> combine(S, [T1]);
+ false -> combine(S, [T1, T2])
end.
-comb(Mod, Name, Args, S, T) ->
- case can_combine_opaque_names(Mod, Name, Args, S) of
- true ->
- ?opaque(Set) = S,
- Set;
- false ->
- [T#opaque{struct = S}]
- end.
+combine(?opaque(Set), Ts) ->
+ [comb2(O, T) || O <- Set, T <- Ts];
+combine(S, Ts) ->
+ [T#opaque{struct = S} || T <- Ts].
-can_combine_opaque_names(Mod1, Name1, Args1,
- ?opaque([#opaque{mod = Mod2, name = Name2, args = Args2}])) ->
- is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2});
-can_combine_opaque_names(_, _, _, _) -> false.
+comb2(O, T) ->
+ case is_compat_opaque_names(O, T) of
+ true -> O;
+ false -> T#opaque{struct = ?opaque(set_singleton(O))}
+ end.
%% Combining two lists this way can be very time consuming...
%% Note: two parameterized opaque types are not the same if their
@@ -3007,32 +3035,27 @@ inf_opaque(Set1, Set2, Opaques) ->
List1 = inf_look_up(Set1, Opaques),
List2 = inf_look_up(Set2, Opaques),
List0 = [combine(Inf, T1, T2) ||
- {Is1, ModNameArgs1, T1} <- List1,
- {Is2, ModNameArgs2, T2} <- List2,
- not t_is_none(Inf = inf_opaque_types(Is1, ModNameArgs1, T1,
- Is2, ModNameArgs2, T2,
- Opaques))],
- List = lists:sort(lists:append(List0)),
+ {Is1, T1} <- List1,
+ {Is2, T2} <- List2,
+ not t_is_none(Inf = inf_opaque_types(Is1, T1, Is2, T2, Opaques))],
+ List = lists:append(List0),
sup_opaque(List).
%% Optimization: do just one lookup.
inf_look_up(Set, Opaques) ->
- [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques),
- {M, N, Args}, T} ||
- #opaque{mod = M, name = N, args = Args} = T <- set_to_list(Set)].
+ [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques), T} ||
+ T <- set_to_list(Set)].
inf_is_opaque_type2(T, {match, Opaques}) ->
is_opaque_type2(T, Opaques);
inf_is_opaque_type2(T, Opaques) ->
is_opaque_type2(T, Opaques).
-inf_opaque_types(IsOpaque1, ModNameArgs1, T1,
- IsOpaque2, ModNameArgs2, T2, Opaques) ->
+inf_opaque_types(IsOpaque1, T1, IsOpaque2, T2, Opaques) ->
#opaque{struct = S1}=T1,
#opaque{struct = S2}=T2,
case
- Opaques =:= 'universe' orelse
- is_compat_opaque_names(ModNameArgs1, ModNameArgs2)
+ Opaques =:= 'universe' orelse is_compat_opaque_names(T1, T2)
of
true -> t_inf(S1, S2, Opaques);
false ->
@@ -3046,98 +3069,109 @@ inf_opaque_types(IsOpaque1, ModNameArgs1, T1,
end
end.
-is_compat_opaque_names(ModNameArgs, ModNameArgs) -> true;
-is_compat_opaque_names({Mod,Name,Args1}, {Mod,Name,Args2}) ->
- is_compat_args(Args1, Args2);
-is_compat_opaque_names(_, _) -> false.
+compatible_opaque_types(?opaque(Es1), ?opaque(Es2)) ->
+ [{O1, O2} || O1 <- Es1, O2 <- Es2, is_compat_opaque_names(O1, O2)].
+
+is_compat_opaque_names(Opaque1, Opaque2) ->
+ #opaque{mod = Mod1, name = Name1, args = Args1} = Opaque1,
+ #opaque{mod = Mod2, name = Name2, args = Args2} = Opaque2,
+ case {{Mod1, Name1, Args1}, {Mod2, Name2, Args2}} of
+ {ModNameArgs, ModNameArgs} -> true;
+ {{Mod, Name, Args1}, {Mod, Name, Args2}} ->
+ is_compat_args(Args1, Args2);
+ _ -> false
+ end.
is_compat_args([A1|Args1], [A2|Args2]) ->
is_compat_arg(A1, A2) andalso is_compat_args(Args1, Args2);
is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
-is_compat_arg(A1, A2) ->
- is_specialization(A1, A2) orelse is_specialization(A2, A1).
-
--spec is_specialization(erl_type(), erl_type()) -> boolean().
-
-%% Returns true if the first argument is a specialization of the
-%% second argument in the sense that every type is a specialization of
-%% any(). For example, {_,_} is a specialization of any(), but not of
-%% tuple(). Does not handle variables, but any() and unions (sort of).
-
-is_specialization(T, T) -> true;
-is_specialization(_, ?any) -> true;
-is_specialization(?any, _) -> false;
-is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
- (is_specialization(Domain1, Domain2) andalso
- is_specialization(Range1, Range2));
-is_specialization(?list(Contents1, Termination1, Size1),
- ?list(Contents2, Termination2, Size2)) ->
+-spec is_compat_arg(erl_type(), erl_type()) -> boolean().
+
+%% The intention is that 'true' is to be returned iff one of the
+%% arguments is a specialization of the other argument in the sense
+%% that every type is a specialization of any(). For example, {_,_} is
+%% a specialization of any(), but not of tuple(). Does not handle
+%% variables, but any() and unions (sort of). However, the
+%% implementation is more relaxed as any() is compatible to anything.
+
+is_compat_arg(T, T) -> true;
+is_compat_arg(_, ?any) -> true;
+is_compat_arg(?any, _) -> true;
+is_compat_arg(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_compat_arg(Domain1, Domain2) andalso
+ is_compat_arg(Range1, Range2));
+is_compat_arg(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
(Size1 =:= Size2 andalso
- is_specialization(Contents1, Contents2) andalso
- is_specialization(Termination1, Termination2));
-is_specialization(?product(Types1), ?product(Types2)) ->
- specialization_list(Types1, Types2);
-is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
-is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(Elements1, Elements2);
-is_specialization(?tuple_set([{Arity, List}]),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(sup_tuple_elements(List), Elements2);
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
- specialization_list(Elements1, sup_tuple_elements(List));
-is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ is_compat_arg(Contents1, Contents2) andalso
+ is_compat_arg(Termination1, Termination2));
+is_compat_arg(?product(Types1), ?product(Types2)) ->
+ is_compat_list(Types1, Types2);
+is_compat_arg(?map(Pairs1, DefK1, DefV1), ?map(Pairs2, DefK2, DefV2)) ->
+ (is_compat_list(Pairs1, Pairs2) andalso
+ is_compat_arg(DefK1, DefK2) andalso
+ is_compat_arg(DefV1, DefV2));
+is_compat_arg(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_compat_arg(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(Elements1, Elements2);
+is_compat_arg(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(sup_tuple_elements(List), Elements2);
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ is_compat_list(Elements1, sup_tuple_elements(List));
+is_compat_arg(?tuple_set(List1), ?tuple_set(List2)) ->
try
- specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
- [sup_tuple_elements(T) || {_Arity, T} <- List2])
+ is_compat_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
+ [sup_tuple_elements(T) || {_Arity, T} <- List2])
catch _:_ -> false
end;
-is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
- case specialization_union2(T1, T2) of
- {yes, Type1, Type2} -> is_specialization(Type1, Type2);
- no -> specialization_list(List1, List2)
+is_compat_arg(?opaque(_) = T1, T2) ->
+ is_compat_arg(t_opaque_structure(T1), T2);
+is_compat_arg(T1, ?opaque(_) = T2) ->
+ is_compat_arg(T1, t_opaque_structure(T2));
+is_compat_arg(?union(List1)=T1, ?union(List2)=T2) ->
+ case is_compat_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_compat_arg(Type1, Type2);
+ no -> is_compat_list(List1, List2)
end;
-is_specialization(?union(List), T2) ->
+is_compat_arg(?union(List), T2) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(Type, T2);
+ {yes, Type} -> is_compat_arg(Type, T2);
no -> false
end;
-is_specialization(T1, ?union(List)) ->
+is_compat_arg(T1, ?union(List)) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(T1, Type);
+ {yes, Type} -> is_compat_arg(T1, Type);
no -> false
end;
-is_specialization(?opaque(_) = T1, T2) ->
- is_specialization(t_opaque_structure(T1), T2);
-is_specialization(T1, ?opaque(_) = T2) ->
- is_specialization(T1, t_opaque_structure(T2));
-is_specialization(?var(_), _) -> exit(error);
-is_specialization(_, ?var(_)) -> exit(error);
-is_specialization(?none, _) -> false;
-is_specialization(_, ?none) -> false;
-is_specialization(?unit, _) -> false;
-is_specialization(_, ?unit) -> false;
-is_specialization(#c{}, #c{}) -> false.
-
-specialization_list_list(LL1, LL2) ->
- length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2).
-
-specialization_list_list1([], []) -> true;
-specialization_list_list1([L1|LL1], [L2|LL2]) ->
- specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2).
-
-specialization_list(L1, L2) ->
- length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
-
-specialization_list1([], []) -> true;
-specialization_list1([T1|L1], [T2|L2]) ->
- is_specialization(T1, T2) andalso specialization_list1(L1, L2).
-
-specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+is_compat_arg(?var(_), _) -> exit(error);
+is_compat_arg(_, ?var(_)) -> exit(error);
+is_compat_arg(?none, _) -> false;
+is_compat_arg(_, ?none) -> false;
+is_compat_arg(?unit, _) -> false;
+is_compat_arg(_, ?unit) -> false;
+is_compat_arg(#c{}, #c{}) -> false.
+
+is_compat_list_list(LL1, LL2) ->
+ length(LL1) =:= length(LL2) andalso is_compat_list_list1(LL1, LL2).
+
+is_compat_list_list1([], []) -> true;
+is_compat_list_list1([L1|LL1], [L2|LL2]) ->
+ is_compat_list(L1, L2) andalso is_compat_list_list1(LL1, LL2).
+
+is_compat_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso is_compat_list1(L1, L2).
+
+is_compat_list1([], []) -> true;
+is_compat_list1([T1|L1], [T2|L2]) ->
+ is_compat_arg(T1, T2) andalso is_compat_list1(L1, L2).
+
+is_compat_union2(?union(List1)=T1, ?union(List2)=T2) ->
case {unify_union(List1), unify_union(List2)} of
{{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
{{yes, Type1}, no} -> {yes, Type1, T2};
@@ -4170,7 +4204,7 @@ t_map(Fun, T) ->
-spec t_to_string(erl_type()) -> string().
t_to_string(T) ->
- t_to_string(T, dict:new()).
+ t_to_string(T, maps:new()).
-spec t_to_string(erl_type(), type_table()) -> string().
@@ -4366,7 +4400,7 @@ record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
string:join(FieldDiffs, " and ").
field_diffs([F|Fs], [{FName, _Abstr, DefType}|FDefs], RecDict, Acc) ->
- %% Don't care about opaqueness for now.
+ %% Don't care about opacity for now.
NewAcc =
case not t_is_none(t_inf(F, DefType)) of
true -> Acc;
@@ -4469,28 +4503,31 @@ t_from_form1(Form, ET, Site, MR, V, C) ->
vtab = V,
tnames = TypeNames},
L = ?EXPAND_LIMIT,
- {T1, L1, C1} = from_form(Form, State, ?EXPAND_DEPTH, L, C),
+ {T0, L0, C0} = from_form(Form, State, ?EXPAND_DEPTH, L, C),
if
- L1 =< 0 ->
- from_form_loop(Form, State, 1, L, C1);
+ L0 =< 0 ->
+ {T1, _, C1} = from_form(Form, State, 1, L, C0),
+ from_form_loop(Form, State, 2, L, C1, T1);
true ->
- {T1, C1}
+ {T0, C0}
end.
initial_typenames({type, _MTA}=Site) -> [Site];
initial_typenames({spec, _MFA}) -> [];
initial_typenames({record, _MRA}) -> [].
-from_form_loop(Form, State, D, Limit, C) ->
+from_form_loop(Form, State, D, Limit, C, T0) ->
{T1, L1, C1} = from_form(Form, State, D, Limit, C),
Delta = Limit - L1,
if
- %% Save some time by assuming next depth will exceed the limit.
+ L1 =< 0 ->
+ {T0, C1};
Delta * 8 > Limit ->
+ %% Save some time by assuming next depth will exceed the limit.
{T1, C1};
true ->
D1 = D + 1,
- from_form_loop(Form, State, D1, Limit, C1)
+ from_form_loop(Form, State, D1, Limit, C1, T1)
end.
-spec from_form(parse_form(),
@@ -4528,6 +4565,8 @@ from_form({atom, _L, Atom}, _S, _D, L, C) ->
{t_atom(Atom), L, C};
from_form({integer, _L, Int}, _S, _D, L, C) ->
{t_integer(Int), L, C};
+from_form({char, _L, Char}, _S, _D, L, C) ->
+ {t_integer(Char), L, C};
from_form({op, _L, _Op, _Arg} = Op, _S, _D, L, C) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
@@ -4749,7 +4788,7 @@ type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) ->
{Rep, L2, C2} = recur_limit(Fun, D, L1, TypeName, TypeNames),
Rep1 = choose_opaque_type(Rep, Type),
Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of
- true -> Rep1;
+ true -> Rep;
false ->
ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
t_opaque(Module, Name, ArgTypes2, Rep1)
@@ -4821,7 +4860,7 @@ remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames,
NewRep1 = choose_opaque_type(NewRep, Type),
NewRep2 =
case cannot_have_opaque(NewRep1, RemType, TypeNames) of
- true -> NewRep1;
+ true -> NewRep;
false ->
ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
t_opaque(Mod, Name, ArgTypes2, NewRep1)
@@ -5042,6 +5081,7 @@ check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
list_check_record_fields(Args, S, C);
check_record_fields({atom, _L, _}, _S, C) -> C;
check_record_fields({integer, _L, _}, _S, C) -> C;
+check_record_fields({char, _L, _}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _S, C) -> C;
check_record_fields({type, _L, tuple, any}, _S, C) -> C;
@@ -5143,6 +5183,7 @@ t_form_to_string({var, _L, Name}) -> atom_to_list(Name);
t_form_to_string({atom, _L, Atom}) ->
io_lib:write_string(atom_to_list(Atom), $'); % To quote or not to quote... '
t_form_to_string({integer, _L, Int}) -> integer_to_list(Int);
+t_form_to_string({char, _L, Char}) -> integer_to_list(Char);
t_form_to_string({op, _L, _Op, _Arg} = Op) ->
case erl_eval:partial_eval(Op) of
{integer, _, _} = Int -> t_form_to_string(Int);
@@ -5225,7 +5266,7 @@ t_form_to_string({type, _L, union, Args}) ->
t_form_to_string({type, _L, Name, []} = T) ->
try
M = mod,
- D0 = dict:new(),
+ D0 = maps:new(),
MR = dict:from_list([{M, D0}]),
Site = {type, {M,Name,0}},
V = var_table__new(),
@@ -5289,8 +5330,8 @@ is_erl_type(_) -> false.
-spec lookup_record(atom(), type_table()) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
-lookup_record(Tag, RecDict) when is_atom(Tag) ->
- case dict:find({record, Tag}, RecDict) of
+lookup_record(Tag, Table) when is_atom(Tag) ->
+ case maps:find({record, Tag}, Table) of
{ok, {_FileLine, [{_Arity, Fields}]}} ->
{ok, Fields};
{ok, {_FileLine, List}} when is_list(List) ->
@@ -5304,18 +5345,18 @@ lookup_record(Tag, RecDict) when is_atom(Tag) ->
-spec lookup_record(atom(), arity(), type_table()) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
-lookup_record(Tag, Arity, RecDict) when is_atom(Tag) ->
- case dict:find({record, Tag}, RecDict) of
+lookup_record(Tag, Arity, Table) when is_atom(Tag) ->
+ case maps:find({record, Tag}, Table) of
{ok, {_FileLine, [{Arity, Fields}]}} -> {ok, Fields};
{ok, {_FileLine, OrdDict}} -> orddict:find(Arity, OrdDict);
error -> error
end.
-spec lookup_type(_, _, _) -> {'type' | 'opaque', type_value()} | 'error'.
-lookup_type(Name, Arity, RecDict) ->
- case dict:find({type, Name, Arity}, RecDict) of
+lookup_type(Name, Arity, Table) ->
+ case maps:find({type, Name, Arity}, Table) of
error ->
- case dict:find({opaque, Name, Arity}, RecDict) of
+ case maps:find({opaque, Name, Arity}, Table) of
error -> error;
{ok, Found} -> {opaque, Found}
end;
@@ -5325,8 +5366,8 @@ lookup_type(Name, Arity, RecDict) ->
-spec type_is_defined('type' | 'opaque', atom(), arity(), type_table()) ->
boolean().
-type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
- dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+type_is_defined(TypeOrOpaque, Name, Arity, Table) ->
+ maps:is_key({TypeOrOpaque, Name, Arity}, Table).
cannot_have_opaque(Type, TypeName, TypeNames) ->
t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index e2a1524be6..627794aee8 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,111 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.15.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug concerning parameterized opaque types. </p>
+ <p>
+ Own Id: OTP-14130</p>
+ </item>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.15.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix flow control bug in hipe compiler that may cause
+ compile time crash.</p>
+ <p>
+ Own Id: OTP-13965 Aux Id: PR-1253 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in native compilation of bitstring pattern
+ matching causing erroneous runtime matching result. The
+ bug only affects code containing constant-valued segments
+ whose size is expressed in bits; it is triggered when the
+ pattern matching against these segments fails (i.e., when
+ the next clause needs to be tried).</p>
+ <p>
+ Own Id: OTP-14005</p>
+ </item>
+ <item>
+ <p>
+ Workaround in HiPE LLVM backend for a bug in LLVM 3.9.
+ The bug could cause LLVM-compiled modules to be rejected
+ during loading with a badarg exception in
+ hipe_bifs:enter_sdecs/1, but also cause corruption or
+ segmentation faults i runtime.</p>
+ <p>
+ Own Id: OTP-14027 Aux Id: ERL-292, PR-1237 </p>
+ </item>
+ <item>
+ <p>
+ Fix a bug in HiPE LLVM backend involving incorrect type
+ tests of atoms sometimes causing incorrect behaviour or
+ even segfaults.</p>
+ <p>
+ Own Id: OTP-14028 Aux Id: PR-1237 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.15.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed various hipe compiler backend bugs affecting mostly
+ ARM and SPARC.</p>
+ <p>
+ Own Id: OTP-13846 Aux Id: PR-1146 </p>
+ </item>
+ <item>
+ <p>
+ Fixed some Dialyzer warnings and code cleanup for the
+ Sparc compiler backend.</p>
+ <p>
+ Own Id: OTP-13861 Aux Id: PR-1148 </p>
+ </item>
+ <item>
+ <p> Fix erl_bif_types opaque bug. </p>
+ <p>
+ Own Id: OTP-13878 Aux Id: PR-1161, ERL-249 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Fix erl_types opaque match order</p>
+ <p>
+ Own Id: OTP-13876</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.15.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -45,12 +150,12 @@
</item>
<item>
<p>
- Various fixes and improvements to the HiPE LLVM backend.
+ Various fixes and improvements to the HiPE LLVM backend.</p>
<list> <item>Add support for LLVM 3.7 and 3.8 in the
HiPE/LLVM x86_64 backend</item> <item>Reinstate support
for the LLVM backend on x86 (works OK for LLVM 3.5 to 3.7
-- LLVM 3.8 has a bug that prevents it from generating
- correct native code on x86)</item> </list></p>
+ correct native code on x86)</item> </list>
<p>
Own Id: OTP-13626</p>
</item>
@@ -106,7 +211,7 @@
<item>
<p>
Fix various binary construction inconsistencies for hipe
- compiled code. <list> <item>Passing bad field sizes to
+ compiled code.</p> <list> <item>Passing bad field sizes to
binary constructions would throw <c>badarith</c> rather
than <c>badarg</c>. Worse, in guards, when the unit size
of the field was 1, the exception would leak rather than
@@ -126,7 +231,7 @@
missing check for unit size match when inserting a
binary. For example, a faulty expression like
<c>&lt;&lt;&lt;&lt;1:7&gt;&gt;/binary&gt;&gt;</c> would
- succeed.</item> </list></p>
+ succeed.</item> </list>
<p>
Own Id: OTP-13272</p>
</item>
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 224aacd8d7..3386523206 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -763,32 +763,10 @@ trans_fun([{test,bs_test_unit,{f,Lbl},[Ms,Unit]}|
[MsVar], [], Env, Instructions);
trans_fun([{test,bs_match_string,{f,Lbl},[Ms,BitSize,Bin]}|
Instructions], Env) ->
- True = mk_label(new),
- FalseLabName = map_label(Lbl),
- TrueLabName = hipe_icode:label_name(True),
+ %% the current match buffer
MsVar = mk_var(Ms),
- TmpVar = mk_var(new),
- ByteSize = BitSize div 8,
- ExtraBits = BitSize rem 8,
- WordSize = hipe_rtl_arch:word_size(),
- if ExtraBits =:= 0 ->
- trans_op_call({hipe_bs_primop,{bs_match_string,Bin,ByteSize}}, Lbl,
- [MsVar], [MsVar], Env, Instructions);
- BitSize =< ((WordSize * 8) - 5) ->
- <<Int:BitSize, _/bits>> = Bin,
- {I1,Env1} = trans_one_op_call({hipe_bs_primop,{bs_get_integer,BitSize,0}}, Lbl,
- [MsVar], [TmpVar, MsVar], Env),
- I2 = hipe_icode:mk_type([TmpVar], {integer,Int}, TrueLabName, FalseLabName),
- I1 ++ [I2,True] ++ trans_fun(Instructions, Env1);
- true ->
- <<RealBin:ByteSize/binary, Int:ExtraBits, _/bits>> = Bin,
- {I1,Env1} = trans_one_op_call({hipe_bs_primop,{bs_match_string,RealBin,ByteSize}}, Lbl,
- [MsVar], [MsVar], Env),
- {I2,Env2} = trans_one_op_call({hipe_bs_primop,{bs_get_integer,ExtraBits,0}}, Lbl,
- [MsVar], [TmpVar, MsVar], Env1),
- I3 = hipe_icode:mk_type([TmpVar], {integer,Int}, TrueLabName, FalseLabName),
- I1 ++ I2 ++ [I3,True] ++ trans_fun(Instructions, Env2)
- end;
+ Primop = {hipe_bs_primop, {bs_match_string, Bin, BitSize}},
+ trans_op_call(Primop, Lbl, [MsVar], [MsVar], Env, Instructions);
trans_fun([{bs_context_to_binary,Var}|Instructions], Env) ->
%% the current match buffer
IVars = [trans_arg(Var)],
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 78508dff22..13a0bf6141 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/icode/hipe_icode_call_elim.erl b/lib/hipe/icode/hipe_icode_call_elim.erl
index 6a22133962..71c709a7d1 100644
--- a/lib/hipe/icode/hipe_icode_call_elim.erl
+++ b/lib/hipe/icode/hipe_icode_call_elim.erl
@@ -46,7 +46,8 @@ cfg(IcodeSSA) ->
-spec elim_insn(icode_instr()) -> icode_instr().
elim_insn(Insn=#icode_call{'fun'={_,_,_}=MFA, args=Args, type=remote,
dstlist=[Dst=#icode_variable{
- annotation={type_anno, RetType, _}}]}) ->
+ annotation={type_anno, RetType, _}}],
+ continuation=[], fail_label=[]}) ->
Opaques = 'universe',
case erl_types:t_is_singleton(RetType, Opaques) of
true ->
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
index cee37b6a57..2a141c514e 100644
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ b/lib/hipe/icode/hipe_icode_primops.erl
@@ -287,8 +287,8 @@ pp(Dev, Op) ->
io:format(Dev, "bs_start_match<~w>", [Max]);
{{bs_start_match, Type}, Max} ->
io:format(Dev, "bs_start_match<~w,~w>", [Type,Max]);
- {bs_match_string, String, SizeInBytes} ->
- io:format(Dev, "bs_match_string<~w, ~w>", [String, SizeInBytes]);
+ {bs_match_string, String, SizeInBits} ->
+ io:format(Dev, "bs_match_string<~w, ~w>", [String, SizeInBits]);
{bs_get_integer, Size, Flags} ->
io:format(Dev, "bs_get_integer<~w, ~w>", [Size, Flags]);
{bs_get_float, Size, Flags} ->
@@ -596,10 +596,10 @@ type(Primop, Args) ->
erl_types:t_subtract(Type, erl_types:t_matchstate()),
erl_types:t_matchstate_slot(
erl_types:t_inf(Type, erl_types:t_matchstate()), 0));
- {hipe_bs_primop, {bs_match_string,_,Bytes}} ->
+ {hipe_bs_primop, {bs_match_string,_,Bits}} ->
[MatchState] = Args,
BinType = erl_types:t_matchstate_present(MatchState),
- NewBinType = match_bin(erl_types:t_bitstr(0, Bytes*8), BinType),
+ NewBinType = match_bin(erl_types:t_bitstr(0, Bits), BinType),
erl_types:t_matchstate_update_present(NewBinType, MatchState);
{hipe_bs_primop, {bs_test_unit,Unit}} ->
[MatchState] = Args,
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index 476d6fb49c..7f70826046 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -84,7 +84,7 @@ compile_with_llvm(FunName, Arity, LLVMCode, Options, UseBuffer) ->
__ = file:close(File_llvm),
%% Invoke LLVM compiler tools to produce an object file
llvm_opt(Dir, Filename, Options),
- llvm_llc(Dir, Filename, Options),
+ llvm_llc(Dir, Filename, Ver, Options),
compile(Dir, Filename, "gcc"), %%FIXME: use llc -filetype=obj and skip this!
{ok, Dir, Dir ++ Filename ++ ".o"}.
@@ -103,12 +103,14 @@ llvm_opt(Dir, Filename, Options) ->
%% @doc Invoke llc tool to compile the bitcode to object file
%% (_name.bc -> _name.o).
-llvm_llc(Dir, Filename, Options) ->
+llvm_llc(Dir, Filename, Ver, Options) ->
Source = Dir ++ Filename ++ ".bc",
OptLevel = trans_optlev_flag(llc, Options),
+ VerFlags = llc_ver_flags(Ver),
Align = find_stack_alignment(),
LlcFlags = [OptLevel, "-code-model=medium", "-stack-alignment=" ++ Align
- , "-tailcallopt", "-filetype=asm"], %%FIXME
+ , "-tailcallopt", "-filetype=asm" %FIXME
+ | VerFlags],
Command = "llc " ++ fix_opts(LlcFlags) ++ " " ++ Source,
%% io:format("LLC: ~s~n", [Command]),
case os:cmd(Command) of
@@ -153,6 +155,12 @@ trans_optlev_flag(Tool, Options) ->
undefined -> "-O2"
end.
+llc_ver_flags(Ver = {_, _}) when Ver >= {3,9} ->
+ %% Works around a bug in the x86-call-frame-opt pass (as of LLVM 3.9) that
+ %% break the garbage collection stack descriptors.
+ ["-no-x86-call-frame-opt"];
+llc_ver_flags({_, _}) -> [].
+
%%------------------------------------------------------------------------------
%% Functions to manage Relocations
%%------------------------------------------------------------------------------
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
index 66b2e10fb8..2179f7f765 100644
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -10,7 +10,8 @@
-include("../rtl/hipe_literals.hrl").
-include("hipe_llvm_arch.hrl").
--define(WORD_WIDTH, (?bytes_to_bits(hipe_rtl_arch:word_size()))).
+-define(BITS_IN_WORD, (?bytes_to_bits(hipe_rtl_arch:word_size()))).
+-define(BITS_IN_BYTE, (?bytes_to_bits(1))).
-define(BRANCH_META_TAKEN, "0").
-define(BRANCH_META_NOT_TAKEN, "1").
-define(FIRST_FREE_META_NO, 2).
@@ -95,9 +96,9 @@ 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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
case hipe_rtl:is_var(D) of
true ->
Num = hipe_rtl:var_index(D),
@@ -233,7 +234,7 @@ trans_alu(I, Relocs) ->
{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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []),
I4 = store_stack_dst(TmpDst, RtlDst),
{[I4, I3, I2, I1], Relocs}.
@@ -258,7 +259,7 @@ trans_alub_overflow(I, Sign, Relocs) ->
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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
ReturnType = hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]),
T1 = mk_temp(),
I3 = hipe_llvm:mk_call(T1, false, [], [], ReturnType, "@" ++ Name,
@@ -320,7 +321,7 @@ trans_alub_no_overflow(I, Relocs) ->
{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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I5 = hipe_llvm:mk_icmp(T3, Cond, WordTy, Dst, "0"),
%% br
Metadata = branch_metadata(hipe_rtl:alub_pred(I)),
@@ -338,7 +339,7 @@ trans_branch(I, Relocs) ->
Cond = trans_rel_op(hipe_rtl:branch_cond(I)),
%% icmp
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I3 = hipe_llvm:mk_icmp(T1, Cond, WordTy, Src1, Src2),
%% br
True_label = mk_jump_label(hipe_rtl:branch_true_label(I)),
@@ -366,7 +367,7 @@ trans_call(I, Relocs) ->
{Name, I3, Relocs2} =
trans_call_name(RtlCallName, Relocs1, CallArgs, FinalArgs),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
I4 =
case hipe_rtl:call_fail(I) of
@@ -450,7 +451,7 @@ trans_call_name(RtlCallName, Relocs, CallArgs, FinalArgs) ->
%% order to make the call
TT1 = mk_temp(),
{RegName, II1} = trans_src(Reg),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
II2 =
hipe_llvm:mk_conversion(TT1, inttoptr, WordTy, RegName, WordTyPtr),
@@ -503,7 +504,7 @@ trans_enter(I, Relocs) ->
{Name, I2, NewRelocs} =
trans_call_name(hipe_rtl:enter_fun(I), Relocs, CallArgs, FinalArgs),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
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}]),
@@ -518,7 +519,7 @@ trans_fconv(I, Relocs) ->
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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I2 = hipe_llvm:mk_conversion(TmpDst, sitofp, WordTy, Src, FloatTy),
I3 = store_float_stack(TmpDst, RtlDst),
{[I3, I2, I1], Relocs}.
@@ -538,7 +539,7 @@ trans_fload(I, Relocs) ->
{Src, I1} = trans_float_src(RtlSrc),
{Offset, I2} = trans_float_src(_Offset),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()),
I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
T2 = mk_temp(),
@@ -619,7 +620,7 @@ trans_fstore(I, Relocs) ->
trans_fstore_reg(I, Relocs) ->
{Base, I0} = trans_reg(hipe_rtl:fstore_base(I), dst),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
FloatTy = hipe_llvm:mk_double(),
FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
@@ -659,7 +660,7 @@ trans_load(I, Relocs) ->
{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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
%%----------------------------------------------------------------
@@ -737,7 +738,7 @@ trans_move(I, Relocs) ->
%% return
%%
trans_return(I, Relocs) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
{VarRet, I1} =
case hipe_rtl:return_varlist(I) of
[] ->
@@ -777,7 +778,7 @@ trans_store(I, Relocs) ->
{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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
I4 = hipe_llvm:mk_operation(T1, add, WordTy, Base, Offset, []),
I5 =
@@ -811,14 +812,14 @@ trans_switch(I, Relocs, Data) ->
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)),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I2 = hipe_llvm:mk_getelementptr(T1, TableTypeP, "@"++TableName,
[{WordTy, "0"}, {WordTy, Src}], false),
T2 = mk_temp(),
@@ -933,7 +934,7 @@ create_fail_blocks(Label, FailLabels, Acc) ->
false ->
Acc;
{value, {Label, FailLabel, SpAdj}, RestFailLabels} ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I1 = hipe_llvm:mk_label(FailLabel),
LP = hipe_llvm:mk_landingpad(),
I2 =
@@ -962,7 +963,7 @@ create_fail_blocks(Label, FailLabels, Acc) ->
%% @doc Convert RTL argument list to LLVM argument list.
trans_args(ArgList) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
MakeArg =
fun(A) ->
{Name, I1} = trans_src(A),
@@ -972,13 +973,13 @@ trans_args(ArgList) ->
%% @doc Convert a list of Precoloured registers to LLVM argument list.
fix_reg_args(ArgList) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
[{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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
Fun1 =
fun (X, Y) ->
@@ -991,7 +992,7 @@ load_fixed_regs(RegList) ->
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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
Fun1 =
@@ -1060,7 +1061,7 @@ mk_temp_reg(Name) ->
store_stack_dst(TempDst, Dst) ->
{Dst2, II1} = trans_dst(Dst),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
II2 = hipe_llvm:mk_store(WordTy, TempDst, WordTyPtr, Dst2, [], [], false),
[II2, II1].
@@ -1078,7 +1079,7 @@ trans_float_src(Src) ->
Name = "@DL" ++ integer_to_list(hipe_rtl:const_label_label(Src)),
T1 = mk_temp(),
%% XXX: Hardcoded offset
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
I1 = hipe_llvm:mk_getelementptr(T1, ByteTyPtr, Name,
[{ByteTy, integer_to_list(?FLOAT_OFFSET)}], true),
@@ -1094,7 +1095,7 @@ trans_float_src(Src) ->
end.
trans_src(A) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
case hipe_rtl:is_imm(A) of
true ->
@@ -1197,7 +1198,7 @@ map_precoloured_reg(Index) ->
fix_reg_dst(Register) ->
case Register of
{Name, Offset} -> %% Case of %fcalls, %hplim
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
pointer_from_reg(Name, WordTy, Offset);
Name -> %% Case of %p and %hp
{Name, []}
@@ -1205,7 +1206,7 @@ fix_reg_dst(Register) ->
%% @doc Load precoloured src register.
fix_reg_src(Register) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
case Register of
{Name, Offset} -> %% Case of %fcalls, %hplim
@@ -1327,10 +1328,10 @@ insn_dst(I) ->
llvm_type_from_size(Size) ->
case Size of
- byte -> hipe_llvm:mk_int(8);
+ byte -> hipe_llvm:mk_int(?BITS_IN_BYTE);
int16 -> hipe_llvm:mk_int(16);
int32 -> hipe_llvm:mk_int(32);
- word -> hipe_llvm:mk_int(64)
+ word -> hipe_llvm:mk_int(?BITS_IN_WORD)
end.
%% @doc Create definition for the compiled function. The parameters that are
@@ -1360,13 +1361,13 @@ create_function_definition(Fun, Params, Code, LocalVars) ->
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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
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 = hipe_llvm:mk_int(?BITS_IN_WORD),
[{WordTy, "%v" ++ integer_to_list(hipe_rtl:var_index(P))} || P <- Params].
store_params(Params) ->
@@ -1375,7 +1376,7 @@ store_params(Params) ->
Index = hipe_rtl:var_index(X),
{Name, _} = trans_dst(X),
ParamName = "%v" ++ integer_to_list(Index),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
hipe_llvm:mk_store(WordTy, ParamName, WordTyPtr, Name, [], [], false)
end,
@@ -1392,11 +1393,11 @@ fixed_registers() ->
end.
header_regs(Registers) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
[{WordTy, "%" ++ X ++ "_in"} || X <- Registers].
load_regs(Registers) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
Fun1 =
fun(X) ->
@@ -1496,28 +1497,30 @@ seperate_relocs([R|Rs], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) ->
%% @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, "").
+ %% The type has to be byte, or a backend might assume the constant is aligned
+ %% and incorrectly optimise away type tests
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
+ hipe_llvm:mk_const_decl("@" ++ AtomName, "external constant", ByteTy, "").
%% @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).
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
+ hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
%% @doc External declaration of a closure.
declare_closure({ClosureName, _})->
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
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)),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
%% @doc Declaration of a local variable for a switch jump table.
@@ -1548,7 +1551,7 @@ declare_closure_labels(ClosureLabels, Relocs, Fun) ->
List3 = string:join(List2, ",\n"),
List4 = "[\n" ++ List3 ++ "\n]\n",
NrLabels = length(LabelList),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
ConstDecl =
hipe_llvm:mk_const_decl("@table_closures", "constant", TableType, List4),
@@ -1563,7 +1566,7 @@ is_external_call(_, _) -> true.
call_to_decl({Name, {call, MFA}}) ->
{M, _F, A} = MFA,
CConv = "cc 11",
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
{Type, Args} =
case M of
@@ -1578,14 +1581,14 @@ call_to_decl({Name, {call, MFA}}) ->
%% @doc These functions are always declared, even if not used.
fixed_fun_decl() ->
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
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),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
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", [], []),
@@ -1599,7 +1602,7 @@ fixed_fun_decl() ->
%% 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),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
hipe_llvm:mk_const_decl(Name, "external constant", ByteTy, "").
%% @doc Load a constant is achieved by converting a pointer to an integer of
@@ -1607,8 +1610,8 @@ declare_constant(Label) ->
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)),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
%% @doc Store external constants and calls to dictionary.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 6c525dd143..cc0148a80e 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -635,44 +635,51 @@ run_compiler(Name, DisasmFun, IcodeFun, Opts0) ->
Opts = expand_basic_options(Opts0 ++ ?COMPILE_DEFAULTS),
?when_option(verbose, Opts, ?debug_msg("Compiling: ~p\n",[Name])),
?option_start_time("Compile", Opts),
- Res = run_compiler_1(DisasmFun, IcodeFun, Opts),
+ Res = run_compiler_1(Name, DisasmFun, IcodeFun, Opts),
?option_stop_time("Compile", Opts),
Res.
-run_compiler_1(DisasmFun, IcodeFun, Options) ->
+run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
Parent = self(),
{trap_exit,TrapExit} = process_info(Parent, trap_exit),
%% Spawn a compilation process CompProc. In case this process gets
%% killed, the trap_exit flag is restored to that of the Parent process.
process_flag(trap_exit, true),
- CompProc = spawn_link(fun () ->
- %% Compiler process
- set_architecture(Options),
- pre_init(Options),
- %% The full option expansion is not done
- %% until the DisasmFun returns.
- {Code, CompOpts} = DisasmFun(Options),
- Opts0 = expand_options(Options ++ CompOpts,
- get(hipe_target_arch)),
- Opts =
- case proplists:get_bool(to_llvm, Opts0) andalso
- not llvm_support_available() of
- true ->
- ?error_msg("No LLVM version 3.4 or greater "
- "found in $PATH; aborting "
- "native code compilation.\n", []),
- ?EXIT(cant_find_required_llvm_version);
- false ->
- Opts0
- end,
- check_options(Opts),
- ?when_option(verbose, Options,
- ?debug_msg("Options: ~p.\n",[Opts])),
- init(Opts),
- {Icode, WholeModule} = IcodeFun(Code, Opts),
- CompRes = compile_finish(Icode, WholeModule, Opts),
- compiler_return(CompRes, Parent)
- end),
+ CompProc =
+ spawn_link(
+ fun () ->
+ try
+ %% Compiler process
+ set_architecture(Options),
+ pre_init(Options),
+ %% The full option expansion is not done
+ %% until the DisasmFun returns.
+ {Code, CompOpts} = DisasmFun(Options),
+ Opts0 = expand_options(Options ++ CompOpts,
+ get(hipe_target_arch)),
+ Opts =
+ case proplists:get_bool(to_llvm, Opts0) andalso
+ not llvm_support_available() of
+ true ->
+ ?error_msg("No LLVM version 3.4 or greater "
+ "found in $PATH; aborting "
+ "native code compilation.\n", []),
+ ?EXIT(cant_find_required_llvm_version);
+ false ->
+ Opts0
+ end,
+ check_options(Opts),
+ ?when_option(verbose, Options,
+ ?debug_msg("Options: ~p.\n",[Opts])),
+ init(Opts),
+ {Icode, WholeModule} = IcodeFun(Code, Opts),
+ CompRes = compile_finish(Icode, WholeModule, Opts),
+ compiler_return(CompRes, Parent)
+ catch error:Error ->
+ print_crash_message(Name, Error),
+ exit(Error)
+ end
+ end),
Timeout = case proplists:get_value(timeout, Options) of
N when is_integer(N), N >= 0 -> N;
undefined -> ?DEFAULT_TIMEOUT;
@@ -691,7 +698,7 @@ run_compiler_1(DisasmFun, IcodeFun, Options) ->
exit(CompProc, kill),
receive {'EXIT', CompProc, _} -> ok end,
flush(),
- ?error_msg("ERROR: Compilation timed out.\n",[]),
+ ?error_msg("ERROR: Compilation of ~w timed out.\n",[Name]),
exit(timed_out)
end,
Result = receive {CompProc, Res} -> Res end,
@@ -844,11 +851,25 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
catch
error:Error ->
?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
- ErrorInfo = {Error, erlang:get_stacktrace()},
- ?error_msg("ERROR: ~p~n", [ErrorInfo]),
- ?EXIT(ErrorInfo)
+ print_crash_message(MFA, Error),
+ exit(Error)
end.
+print_crash_message(What, Error) ->
+ StackFun = fun(_,_,_) -> false end,
+ FormatFun = fun (Term, _) -> io_lib:format("~p", [Term]) end,
+ StackTrace = lib:format_stacktrace(1, erlang:get_stacktrace(),
+ StackFun, FormatFun),
+ WhatS = case What of
+ {M,F,A} -> io_lib:format("~w:~w/~w", [M,F,A]);
+ Mod -> io_lib:format("~w", [Mod])
+ end,
+ ?error_msg("INTERNAL ERROR~n"
+ "while compiling ~s~n"
+ "crash reason: ~p~n"
+ "~s~n",
+ [WhatS, Error, StackTrace]).
+
pp_server_start(Opts) ->
set_architecture(Opts),
garbage_collect(),
diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src
index 53b59f88f0..b001743038 100644
--- a/lib/hipe/main/hipe.hrl.src
+++ b/lib/hipe/main/hipe.hrl.src
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- mode: erlang; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,20 +70,24 @@
code_server:info_msg(?MSGTAG ++ Msg, Args)).
-define(untagged_msg(Msg, Args),
code_server:info_msg(Msg, Args)).
+-define(untagged_error_msg(Msg, Args),
+ code_server:error_msg(Msg, Args)).
-else.
-define(msg(Msg, Args),
io:format(?MSGTAG ++ Msg, Args)).
-define(untagged_msg(Msg, Args),
io:format(Msg, Args)).
+-define(untagged_error_msg(Msg, Args),
+ io:format(Msg, Args)).
-endif.
%%
%% Define error and warning messages.
%%
-define(error_msg(Msg, Args),
- code_server:error_msg(?MSGTAG ++
+ ?untagged_error_msg(?MSGTAG ++
"Error: [~s:~w]: " ++ Msg,
- [?MODULE,?LINE|Args])).
+ [?MODULE,?LINE|Args])).
-define(WARNING_MSG(Msg, Args),
?msg("Warning: [~s:~w]: " ++ Msg, [?MODULE,?LINE|Args])).
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index 4b89feb48a..8737560ad5 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/ppc/hipe_ppc.erl b/lib/hipe/ppc/hipe_ppc.erl
index 0fa96162f6..380e791bc1 100644
--- a/lib/hipe/ppc/hipe_ppc.erl
+++ b/lib/hipe/ppc/hipe_ppc.erl
@@ -167,8 +167,10 @@ temp_is_precoloured(#ppc_temp{reg=Reg,type=Type}) ->
_ -> hipe_ppc_registers:is_precoloured_gpr(Reg)
end.
-mk_simm16(Value) -> #ppc_simm16{value=Value}.
-mk_uimm16(Value) -> #ppc_uimm16{value=Value}.
+mk_simm16(Value) when Value >= -(1 bsl 15), Value < (1 bsl 15) ->
+ #ppc_simm16{value=Value}.
+mk_uimm16(Value) when Value >= 0, Value < (1 bsl 16) ->
+ #ppc_uimm16{value=Value}.
mk_mfa(M, F, A) -> #ppc_mfa{m=M, f=F, a=A}.
@@ -240,7 +242,11 @@ mk_li(Dst, Value, Tail) -> % Dst can be R0
Value =< 16#7FFFFFFF ->
mk_li32(Dst, R0, Value, Tail);
true ->
- Highest = (Value bsr 48), % Value@highest
+ Highest = case (Value bsr 48) of % Value@highest
+ TopBitSet when TopBitSet >= (1 bsl 15) ->
+ TopBitSet - (1 bsl 16); % encoder needs it to be negative
+ FitsSimm16 -> FitsSimm16
+ end,
Higher = (Value bsr 32) band 16#FFFF, % Value@higher
High = (Value bsr 16) band 16#FFFF, % Value@h
Low = Value band 16#FFFF, % Value@l
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
index ff9da01b11..d89ff6235c 100644
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ b/lib/hipe/ppc/hipe_ppc_assemble.erl
@@ -175,7 +175,8 @@ do_slwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
{Dst, Src1, {sh,N}, {mb,0}, {me,31-N}}.
do_srwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
- {Dst, Src1, {sh,32-N}, {mb,N}, {me,31}}.
+ %% SH should be 0 (not 32) when N is 0
+ {Dst, Src1, {sh,(32-N) band 31}, {mb,N}, {me,31}}.
do_srawi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 32 -> {sh,N}.
@@ -184,7 +185,8 @@ do_sldi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
{Dst, Src1, {sh6,N}, {me6,63-N}}.
do_srdi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
- {Dst, Src1, {sh6,64-N}, {mb6,N}}.
+ %% SH should be 0 (not 64) when N is 0
+ {Dst, Src1, {sh6,(64-N) band 63}, {mb6,N}}.
do_sradi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 64 -> {sh6,N}.
@@ -246,6 +248,7 @@ do_load(I) ->
case LdOp of
'ld' -> do_disp_ds(Disp);
'ldu' -> do_disp_ds(Disp);
+ 'lwa' -> do_disp_ds(Disp);
_ -> do_disp(Disp)
end,
NewBase = do_reg(Base),
diff --git a/lib/hipe/rtl/hipe_rtl_binary.erl b/lib/hipe/rtl/hipe_rtl_binary.erl
index fb9c0c196d..9b400f4c93 100644
--- a/lib/hipe/rtl/hipe_rtl_binary.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary.erl
@@ -19,7 +19,7 @@
%%% %CopyrightEnd%
%%%
%%%-------------------------------------------------------------------
-%%% File : hipe_rtl_binary_2.erl
+%%% File : hipe_rtl_binary.erl
%%% Author : Per Gustafsson <[email protected]>
%%% Description :
%%%
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 528672b893..d999cd2743 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -270,24 +270,23 @@ gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset),
hipe_rtl:mk_goto(TrueLblName)];
%% ----- bs_match_string -----
-gen_rtl({bs_match_string, String, ByteSize}, Dst, [Ms],
+gen_rtl({bs_match_string, String, BitSize}, Dst, [Ms],
TrueLblName, FalseLblName) ->
{[Offset, BinSize, Base], Instrs} =
extract_matchstate_vars([offset, binsize, base], Ms),
[SuccessLbl, ALbl, ULbl] = create_lbls(3),
[NewOffset, BitOffset] = create_gcsafe_regs(2),
- Unit = hipe_rtl_arch:word_size() - 1,
- Loops = ByteSize div Unit,
- Init =
+ Unit = (hipe_rtl_arch:word_size() - 1) * ?BYTE_SIZE,
+ Init =
[Instrs,
opt_update_ms(Dst, Ms),
- check_size(Offset, hipe_rtl:mk_imm(ByteSize*?BYTE_SIZE), BinSize,
+ check_size(Offset, hipe_rtl:mk_imm(BitSize), BinSize,
NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl],
SplitCode =
[hipe_rtl:mk_alub(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq,
hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))],
- Loops = ByteSize div Unit,
+ Loops = BitSize div Unit,
SkipSize = Loops * Unit,
{ACode1, UCode1} =
case Loops of
@@ -297,9 +296,9 @@ gen_rtl({bs_match_string, String, ByteSize}, Dst, [Ms],
create_loops(Loops, Unit, String, Base,
Offset, BitOffset, FalseLblName)
end,
- <<_:SkipSize/binary, RestString/binary>> = String,
+ <<_:SkipSize/bits, RestString/bits>> = String,
{ACode2, UCode2} =
- case ByteSize rem Unit of
+ case BitSize rem Unit of
0 ->
{[], []};
Rem ->
@@ -393,12 +392,12 @@ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) ->
[Reg] = create_gcsafe_regs(1),
AlignedFun = fun(Value) ->
- [get_int_to_reg(Reg, Unit*?BYTE_SIZE, Base, Offset, 'srl',
+ [get_int_to_reg(Reg, Unit, Base, Offset, 'srl',
{unsigned, big}),
update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
end,
UnAlignedFun = fun(Value) ->
- [get_unaligned_int_to_reg(Reg, Unit*?BYTE_SIZE,
+ [get_unaligned_int_to_reg(Reg, Unit,
Base, Offset, BitOffset,
'srl', {unsigned, big})|
update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
@@ -406,31 +405,31 @@ create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) ->
{create_loops(Loops, Unit, String, AlignedFun),
create_loops(Loops, Unit, String, UnAlignedFun)}.
-create_rests(Rem, String, Base, Offset, BitOffset, FalseLblName) ->
+create_rests(RemBits, String, Base, Offset, BitOffset, FalseLblName) ->
[Reg] = create_gcsafe_regs(1),
AlignedFun = fun(Value) ->
- [get_int_to_reg(Reg, Rem*?BYTE_SIZE, Base, Offset, 'srl',
+ [get_int_to_reg(Reg, RemBits, Base, Offset, 'srl',
{unsigned, big})|
just_test(Reg, Value, FalseLblName)]
end,
UnAlignedFun = fun(Value) ->
- [get_unaligned_int_to_reg(Reg, Rem*?BYTE_SIZE,
+ [get_unaligned_int_to_reg(Reg, RemBits,
Base, Offset, BitOffset,
'srl', {unsigned, big})|
just_test(Reg, Value, FalseLblName)]
end,
- {create_loops(1, Rem, String, AlignedFun),
- create_loops(1, Rem, String, UnAlignedFun)}.
+ {create_loops(1, RemBits, String, AlignedFun),
+ create_loops(1, RemBits, String, UnAlignedFun)}.
create_loops(0, _Unit, _String, _IntFun) ->
[];
create_loops(N, Unit, String, IntFun) ->
- {Value, RestString} = get_value(Unit,String),
+ {Value, RestString} = get_value(Unit, String),
[IntFun(Value),
create_loops(N-1, Unit, RestString, IntFun)].
update_and_test(Reg, Unit, Offset, Value, FalseLblName) ->
- [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit*?BYTE_SIZE), FalseLblName),
+ [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit), FalseLblName),
just_test(Reg, Value, FalseLblName)].
just_test(Reg, Value, FalseLblName) ->
@@ -439,8 +438,8 @@ just_test(Reg, Value, FalseLblName) ->
hipe_rtl:label_name(ContLbl), FalseLblName),
ContLbl].
-get_value(N,String) ->
- <<I:N/integer-unit:8, Rest/binary>> = String,
+get_value(N, String) ->
+ <<I:N, Rest/bits>> = String,
{I, Rest}.
make_int_gc_code(I) when is_integer(I) ->
diff --git a/lib/hipe/sparc/hipe_rtl_to_sparc.erl b/lib/hipe/sparc/hipe_rtl_to_sparc.erl
index eef5ba8d96..f9c043eafe 100644
--- a/lib/hipe/sparc/hipe_rtl_to_sparc.erl
+++ b/lib/hipe/sparc/hipe_rtl_to_sparc.erl
@@ -750,13 +750,25 @@ xaluop_commutes(XAluOp) ->
xaluop_is_shift(XAluOp) ->
case XAluOp of
+ 'add' -> false;
+ 'addcc' -> false;
+ 'and' -> false;
+ 'andcc' -> false;
+ 'cmpcc' -> false;
+ 'ldsb' -> false;
+ 'ldub' -> false;
+ 'lduw' -> false;
+ 'or' -> false;
'sll' -> true;
- 'srl' -> true;
+ %% 'sllx' -> true;
+ 'smul' -> false;
'sra' -> true;
- 'sllx' -> true;
- 'srlx' -> true;
- 'srax' -> true;
- _ -> false
+ %% 'srax' -> true;
+ 'srl' -> true;
+ %% 'srlx' -> true;
+ 'sub' -> false;
+ 'subcc' -> false;
+ 'xor' -> false
end.
%%% Convert an extended SPARC AluOp back to a plain AluOp.
@@ -764,9 +776,23 @@ xaluop_is_shift(XAluOp) ->
xaluop_normalise(XAluOp) ->
case XAluOp of
- 'cmp' -> 'sub';
+ 'add' -> 'add';
+ 'addcc' -> 'addcc';
+ 'and' -> 'and';
+ 'andcc' -> 'andcc';
+ %% 'cmp' -> 'sub';
'cmpcc' -> 'subcc';
- _ -> XAluOp
+ 'ldsb' -> 'ldsb';
+ 'ldub' -> 'ldub';
+ 'lduw' -> 'lduw';
+ 'or' -> 'or';
+ 'sll' -> 'sll';
+ 'smul' -> 'smul';
+ 'sra' -> 'sra';
+ 'srl' -> 'srl';
+ 'sub' -> 'sub';
+ 'subcc' -> 'subcc';
+ 'xor' -> 'xor'
end.
%%% Convert an RTL condition code.
diff --git a/lib/hipe/sparc/hipe_sparc_registers.erl b/lib/hipe/sparc/hipe_sparc_registers.erl
index 884215702b..6681a10070 100644
--- a/lib/hipe/sparc/hipe_sparc_registers.erl
+++ b/lib/hipe/sparc/hipe_sparc_registers.erl
@@ -86,6 +86,8 @@
-define(I7, 31).
-define(LAST_PRECOLOURED,31). % must handle both GRP and FPR ranges
+-define(RA, ?O7).
+
-define(ARG0, ?O1).
-define(ARG1, ?O2).
-define(ARG2, ?O3).
@@ -174,7 +176,7 @@ stack_pointer() -> ?STACK_POINTER.
proc_pointer() -> ?PROC_POINTER.
-return_address() -> ?O7.
+return_address() -> ?RA.
g0() -> ?G0.
@@ -283,7 +285,9 @@ call_clobbered() -> % does the RA strip the type or not?
].
tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}].
+ [{?TEMP1,tagged},{?TEMP1,untagged}
+ ,{?RA,tagged},{?RA,untagged}
+ ].
live_at_return() ->
[{?HEAP_POINTER,untagged},
diff --git a/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
new file mode 100644
index 0000000000..807c4b0d0d
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
@@ -0,0 +1,217 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% File : basic_num_bif.erl
+%%% Description : Taken from the compiler test suite
+%%%-------------------------------------------------------------------
+-module(basic_num_bif).
+
+-export([test/0]).
+
+%% Tests optimization of the BIFs:
+%% abs/1
+%% float/1
+%% float_to_list/1
+%% integer_to_list/1
+%% list_to_float/1
+%% list_to_integer/1
+%% round/1
+%% trunc/1
+
+test() ->
+ Funs = [fun t_abs/0, fun t_float/0,
+ fun t_float_to_list/0, fun t_integer_to_list/0,
+ fun t_list_to_float_safe/0, fun t_list_to_float_risky/0,
+ fun t_list_to_integer/0, fun t_round/0, fun t_trunc/0],
+ lists:foreach(fun (F) -> ok = F() end, Funs).
+
+t_abs() ->
+ %% Floats.
+ 5.5 = abs(5.5),
+ 0.0 = abs(0.0),
+ 100.0 = abs(-100.0),
+ %% Integers.
+ 5 = abs(5),
+ 0 = abs(0),
+ 100 = abs(-100),
+ %% The largest smallnum. OTP-3190.
+ X = (1 bsl 27) - 1,
+ X = abs(X),
+ X = abs(X-1)+1,
+ X = abs(X+1)-1,
+ X = abs(-X),
+ X = abs(-X-1)-1,
+ X = abs(-X+1)+1,
+ %% Bignums.
+ BigNum = 13984792374983749,
+ BigNum = abs(BigNum),
+ BigNum = abs(-BigNum),
+ ok.
+
+t_float() ->
+ 0.0 = float(0),
+ 2.5 = float(2.5),
+ 0.0 = float(0.0),
+ -100.55 = float(-100.55),
+ 42.0 = float(42),
+ -100.0 = float(-100),
+ %% Bignums.
+ 4294967305.0 = float(4294967305),
+ -4294967305.0 = float(-4294967305),
+ %% Extremely big bignums.
+ Big = list_to_integer(lists:duplicate(2000, $1)),
+ {'EXIT', {badarg, _}} = (catch float(Big)),
+ ok.
+
+%% Tests float_to_list/1.
+
+t_float_to_list() ->
+ test_ftl("0.0e+0", 0.0),
+ test_ftl("2.5e+1", 25.0),
+ test_ftl("2.5e+0", 2.5),
+ test_ftl("2.5e-1", 0.25),
+ test_ftl("-3.5e+17", -350.0e15),
+ ok.
+
+test_ftl(Expect, Float) ->
+ %% No on the next line -- we want the line number from t_float_to_list.
+ Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
+
+%% Removes any non-significant zeros in a floating point number.
+%% Example: 2.500000e+01 -> 2.5e+1
+
+remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
+ remove_zeros([$+, $e|Rest], [X|Result]);
+remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
+ remove_zeros([$-, $e|Rest], [X|Result]);
+remove_zeros([$0, $.|Rest], [$e|Result]) ->
+ remove_zeros(Rest, [$., $0, $e|Result]);
+remove_zeros([$0|Rest], [$e|Result]) ->
+ remove_zeros(Rest, [$e|Result]);
+remove_zeros([Char|Rest], Result) ->
+ remove_zeros(Rest, [Char|Result]);
+remove_zeros([], Result) ->
+ Result.
+
+%% Tests integer_to_list/1.
+
+t_integer_to_list() ->
+ "0" = integer_to_list(0),
+ "42" = integer_to_list(42),
+ "-42" = integer_to_list(-42),
+ "-42" = integer_to_list(-42),
+ "32768" = integer_to_list(32768),
+ "268435455" = integer_to_list(268435455),
+ "-268435455" = integer_to_list(-268435455),
+ "123456932798748738738" = integer_to_list(123456932798748738738),
+ Big_List = lists:duplicate(2000, $1),
+ Big = list_to_integer(Big_List),
+ Big_List = integer_to_list(Big),
+ ok.
+
+%% Tests list_to_float/1.
+
+t_list_to_float_safe() ->
+ 0.0 = list_to_float("0.0"),
+ 0.0 = list_to_float("-0.0"),
+ 0.5 = list_to_float("0.5"),
+ -0.5 = list_to_float("-0.5"),
+ 100.0 = list_to_float("1.0e2"),
+ 127.5 = list_to_float("127.5"),
+ -199.5 = list_to_float("-199.5"),
+ ok.
+
+%% This might crash the emulator...
+%% (Known to crash the Unix version of Erlang 4.4.1)
+
+t_list_to_float_risky() ->
+ Many_Ones = lists:duplicate(25000, $1),
+ _ = list_to_float("2."++Many_Ones),
+ {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
+ ok.
+
+%% Tests list_to_integer/1.
+
+t_list_to_integer() ->
+ 0 = list_to_integer("0"),
+ 0 = list_to_integer("00"),
+ 0 = list_to_integer("-0"),
+ 1 = list_to_integer("1"),
+ -1 = list_to_integer("-1"),
+ 42 = list_to_integer("42"),
+ -12 = list_to_integer("-12"),
+ 32768 = list_to_integer("32768"),
+ 268435455 = list_to_integer("268435455"),
+ -268435455 = list_to_integer("-268435455"),
+ %% Bignums.
+ 123456932798748738738 = list_to_integer("123456932798748738738"),
+ _ = list_to_integer(lists:duplicate(2000, $1)),
+ ok.
+
+%% Tests round/1.
+
+t_round() ->
+ 0 = round(0.0),
+ 0 = round(0.4),
+ 1 = round(0.5),
+ 0 = round(-0.4),
+ -1 = round(-0.5),
+ 255 = round(255.3),
+ 256 = round(255.6),
+ -1033 = round(-1033.3),
+ -1034 = round(-1033.6),
+ %% OTP-3722:
+ X = (1 bsl 27) - 1,
+ MX = -X,
+ MXm1 = -X-1,
+ MXp1 = -X+1,
+ F = X + 0.0,
+ X = round(F),
+ X = round(F+1)-1,
+ X = round(F-1)+1,
+ MX = round(-F),
+ MXm1 = round(-F-1),
+ MXp1 = round(-F+1),
+ X = round(F+0.1),
+ X = round(F+1+0.1)-1,
+ X = round(F-1+0.1)+1,
+ MX = round(-F+0.1),
+ MXm1 = round(-F-1+0.1),
+ MXp1 = round(-F+1+0.1),
+ X = round(F-0.1),
+ X = round(F+1-0.1)-1,
+ X = round(F-1-0.1)+1,
+ MX = round(-F-0.1),
+ MXm1 = round(-F-1-0.1),
+ MXp1 = round(-F+1-0.1),
+ 0.5 = abs(round(F+0.5)-(F+0.5)),
+ 0.5 = abs(round(F-0.5)-(F-0.5)),
+ 0.5 = abs(round(-F-0.5)-(-F-0.5)),
+ 0.5 = abs(round(-F+0.5)-(-F+0.5)),
+ %% Bignums.
+ 4294967296 = round(4294967296.1),
+ 4294967297 = round(4294967296.9),
+ -4294967296 = -round(4294967296.1),
+ -4294967297 = -round(4294967296.9),
+ ok.
+
+t_trunc() ->
+ 0 = trunc(0.0),
+ 5 = trunc(5.3333),
+ -10 = trunc(-10.978987),
+ %% The largest smallnum, converted to float (OTP-3722):
+ X = (1 bsl 27) - 1,
+ F = X + 0.0,
+ %% io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
+ %% [X, X, binary_to_list(term_to_binary(X)),
+ %% F, F, binary_to_list(term_to_binary(F)),
+ %% trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
+ X = trunc(F),
+ X = trunc(F+1)-1,
+ X = trunc(F-1)+1,
+ X = -trunc(-F),
+ X = -trunc(-F-1)-1,
+ X = -trunc(-F+1)+1,
+ %% Bignums.
+ 4294967305 = trunc(4294967305.7),
+ -4294967305 = trunc(-4294967305.7),
+ ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl b/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
index b280705a47..d9f3278b45 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
@@ -9,6 +9,7 @@ test() ->
<<49,50,51>> = lex_digits1(Bin, 1, []),
<<49,50,51>> = lex_digits2(Bin, 1, []),
ok = var_bind_bug(<<1, 2, 3, 4, 5, 6, 7, 8>>),
+ ok = bs_match_string_bug(),
ok.
%%--------------------------------------------------------------------
@@ -65,3 +66,50 @@ var_bind_bug(<<A:1/binary, B:8/integer, _C:B/binary, _Rest/binary>>) ->
B -> wrong;
_ -> ok
end.
+
+%%--------------------------------------------------------------------
+%% From: Andreas Schultz
+%% Date: 2/11/2016
+%%
+%% Either HiPE is messing up binary matches in some cases or I'm not
+%% seeing the problem. ... <SNIP PROGRAM - CLEANED UP VERSION BELOW>
+%% With Erlang 19.1.3 the HiPE compiled version behaves differently
+%% than the non-HiPE version: ... <SNIP TEST RUNS>
+%% So, do I do something wrong here or is this a legitimate HiPE bug?
+%%
+%% Yes, this was a legitimate HiPE bug: The BEAM to ICode tranaslation
+%% of the bs_match_string instruction, written long ago for binaries
+%% (i.e., with byte-sized strings), tried to do a `clever' translation
+%% of even bit-sized strings using a HiPE primop that took a `Size'
+%% argument expressed in *bytes*. ICode is not really the place to do
+%% such a thing, and moreover there is really no reason for the HiPE
+%% primop not to take a Size argument expressed in *bits* instead.
+%% The bug was fixed by changing the `Size' argument to be in bits,
+%% postponing the translation of the bs_match_string primop until RTL
+%% and doing a proper translation using bit-sized quantities there.
+%%--------------------------------------------------------------------
+
+bs_match_string_bug() ->
+ ok = test0(<<50>>),
+ Bin = data(),
+ ok = test1(Bin),
+ ok = test2(Bin),
+ ok.
+
+%% Minimal test case showing the problem matching with strings
+test0(<<6:5, 0:1, 0:2>>) -> weird;
+test0(<<6:5, _:1, _:2>>) -> ok;
+test0(_) -> default.
+
+data() -> <<50,16,0>>.
+
+%% This was the problematic test case in HiPE: 'default' was returned
+test1(<<1:3, 1:1, _:1, 0:1, 0:1, 0:1, _/binary>>) -> weird;
+test1(<<1:3, 1:1, _:1, _:1, _:1, _:1, _/binary>>) -> ok;
+test1(_) -> default.
+
+%% This variation of test1/1 above worked OK, even in HiPE
+test2(<<1:3, 1:1, _:1, A:1, B:1, C:1, _/binary>>)
+ when A =:= 1; B =:= 1; C =:= 1 -> ok;
+test2(<<1:3, 1:1, _:1, 0:1, 0:1, 0:1, _/binary>>) -> weird;
+test2(_) -> default.
diff --git a/lib/hipe/test/hipe_SUITE.erl b/lib/hipe/test/hipe_SUITE.erl
index a5b3924aa8..b9adb660f2 100644
--- a/lib/hipe/test/hipe_SUITE.erl
+++ b/lib/hipe/test/hipe_SUITE.erl
@@ -16,7 +16,11 @@
%%
-module(hipe_SUITE).
--compile([export_all]).
+-export([all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ app/0, app/1, appup/0, appup/1]).
+
-include_lib("common_test/include/ct.hrl").
all() ->
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index 03ec7adfd0..a3048d907e 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -99,7 +99,7 @@ write_suite(Suite) ->
write_header(#suite{suitename = SuiteName, outputfile = OutputFile,
testcases = TestCases}) ->
Exports = format_export(TestCases),
- TimeLimit = 3, %% with 1 or 2 it fails on some slow machines...
+ TimeLimit = 5, %% with 1 or 2 it fails on some slow machines...
io:format(OutputFile,
"%% ATTENTION!\n"
"%% This is an automatically generated file. Do not edit.\n\n"
diff --git a/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
new file mode 100644
index 0000000000..17c3acd6af
--- /dev/null
+++ b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
@@ -0,0 +1,14 @@
+-module(maps_redundant_branch_is_key).
+-export([test/0]).
+
+test() ->
+ ok = thingy(#{a => 1}),
+ ok = thingy(#{a => 2}),
+ ok.
+
+thingy(Map) ->
+ try
+ #{a := _} = Map,
+ ok
+ catch _ -> error
+ end.
diff --git a/lib/hipe/test/opt_verify_SUITE.erl b/lib/hipe/test/opt_verify_SUITE.erl
index 61952e81d7..86083fa02b 100644
--- a/lib/hipe/test/opt_verify_SUITE.erl
+++ b/lib/hipe/test/opt_verify_SUITE.erl
@@ -1,6 +1,9 @@
-module(opt_verify_SUITE).
--compile([export_all]).
+-export([all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ call_elim/0, call_elim/1]).
all() ->
[call_elim].
@@ -23,23 +26,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-call_elim_test_file(Config, FileName, Option) ->
- PrivDir = test_server:lookup_config(priv_dir, Config),
- TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
- {ok, TestCase} = compile:file(FileName),
- {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
- {ok, Icode} = file:read_file(TempOut),
- ok = file:delete(TempOut),
- Icode.
-
-substring_count(Icode, Substring) ->
- substring_count(Icode, Substring, 0).
-substring_count(Icode, Substring, N) ->
- case string:str(Icode, Substring) of
- 0 -> N;
- I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
- end.
-
call_elim() ->
[{doc, "Test that the call elimination optimization pass is ok"}].
call_elim(Config) ->
@@ -60,3 +46,20 @@ call_elim(Config) ->
Icode6 = call_elim_test_file(Config, F3, no_icode_call_elim),
3 = substring_count(binary:bin_to_list(Icode6), "is_key"),
ok.
+
+call_elim_test_file(Config, FileName, Option) ->
+ PrivDir = test_server:lookup_config(priv_dir, Config),
+ TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
+ {ok, TestCase} = compile:file(FileName),
+ {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
+ {ok, Icode} = file:read_file(TempOut),
+ ok = file:delete(TempOut),
+ Icode.
+
+substring_count(Icode, Substring) ->
+ substring_count(Icode, Substring, 0).
+substring_count(Icode, Substring, N) ->
+ case string:str(Icode, Substring) of
+ 0 -> N;
+ I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
+ end.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index e61c1a042c..172d976931 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.15.1
+HIPE_VSN = 3.15.4
diff --git a/lib/hipe/x86/hipe_x86_postpass.erl b/lib/hipe/x86/hipe_x86_postpass.erl
index 939baeccec..4515822a34 100644
--- a/lib/hipe/x86/hipe_x86_postpass.erl
+++ b/lib/hipe/x86/hipe_x86_postpass.erl
@@ -95,7 +95,8 @@ peep([I=#move{src=#x86_temp{reg=Src}, dst=#x86_temp{reg=Dst}},
%% ElimBinALMDouble
%% ----------------
-peep([Move=#move{src=Src, dst=Dst}, Alu=#alu{src=Src, dst=Dst}|Insns], Res, Lst) ->
+peep([Move=#move{src=Src, dst=Dst}, Alu=#alu{src=Src, dst=Dst}|Insns], Res, Lst)
+ when not is_record(Dst, x86_mem) ->
peep([Alu#alu{src=Dst}|Insns], [Move|Res], [elimBinALMDouble|Lst]);
diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile
index c9691df7af..19f12ac6b9 100644
--- a/lib/ic/doc/src/Makefile
+++ b/lib/ic/doc/src/Makefile
@@ -225,7 +225,7 @@ release_docs_spec: docs
$(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- (/bin/cp -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ ($(CP) -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml
index 08b02bc4a4..ea8bf758cf 100644
--- a/lib/ic/doc/src/notes.xml
+++ b/lib/ic/doc/src/notes.xml
@@ -31,7 +31,29 @@
<file>notes.xml</file>
</header>
- <section><title>IC 4.4.1</title>
+ <section><title>IC 4.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Correct bugs when path to mib or idl spec files
+ contains UTF-8 characters. </p>
+ <p>
+ Own Id: OTP-13718 Aux Id: ERL-179 </p>
+ </item>
+ <item>
+ <p>
+ Update build scripts to not make assumtions about where
+ env, cp and perl are located.</p>
+ <p>
+ Own Id: OTP-13800</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>IC 4.4.1</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/ic/src/ic_codegen.erl b/lib/ic/src/ic_codegen.erl
index adad021da1..a3f141f606 100644
--- a/lib/ic/src/ic_codegen.erl
+++ b/lib/ic/src/ic_codegen.erl
@@ -245,8 +245,8 @@ emit_stub_head(G, F1, Name, java) ->
stub_header(G, Name) ->
["Implementation stub file",
"",
- io_lib:format("Target: ~s", [Name]),
- io_lib:format("Source: ~s", [ic_genobj:idlfile(G)]),
+ io_lib:format("Target: ~ts", [Name]),
+ io_lib:format("Source: ~ts", [ic_genobj:idlfile(G)]),
io_lib:format("IC vsn: ~s", [?COMPILERVSN]),
"",
"This file is automatically generated. DO NOT EDIT IT."].
@@ -298,8 +298,8 @@ emit_hrl_head(G, Fd, Name, c_server) ->
hrl_header(G, Name) ->
["",
- io_lib:format("Target: ~s", [Name]),
- io_lib:format("Source: ~s", [ic_genobj:idlfile(G)]),
+ io_lib:format("Target: ~ts", [Name]),
+ io_lib:format("Source: ~ts", [ic_genobj:idlfile(G)]),
io_lib:format("IC vsn: ~s", [?COMPILERVSN]),
"",
"This file is automatically generated. DO NOT EDIT IT."].
diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk
index 7d00ae0170..f0e5e7c266 100644
--- a/lib/ic/vsn.mk
+++ b/lib/ic/vsn.mk
@@ -1 +1 @@
-IC_VSN = 4.4.1
+IC_VSN = 4.4.2
diff --git a/lib/inets/doc/src/http_server.xml b/lib/inets/doc/src/http_server.xml
index aeda961714..65b3dcde95 100644
--- a/lib/inets/doc/src/http_server.xml
+++ b/lib/inets/doc/src/http_server.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2015</year>
+ <year>2004</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -40,8 +40,8 @@
<item>Secure Sockets Layer (SSL)</item>
<item>Erlang Scripting Interface (ESI)</item>
<item>Common Gateway Interface (CGI)</item>
- <item>User Authentication (using <c>Mnesia</c>,
- <c>Dets</c> or plain text database)</item>
+ <item>User Authentication (using Mnesia,
+ Dets or plain text database)</item>
<item>Common Logfile Format (with or without disk_log(3) support)</item>
<item>URL Aliasing</item>
<item>Action Mappings</item>
@@ -563,7 +563,7 @@ http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[
<title>mod_auth - User Authentication</title>
<p>The <seealso marker="mod_auth">mod_auth(3)</seealso>
module provides for basic user authentication using
- textual files, <c>Dets</c> databases as well as <c>Mnesia</c> databases.</p>
+ textual files, Dets databases as well as Mnesia databases.</p>
<p>Uses the following Erlang Web Server API interaction data:
</p>
<list type="bulleted">
@@ -580,15 +580,15 @@ http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[
<section>
<title>Mnesia As Authentication Database</title>
- <p>If <c>Mnesia</c> is used as storage method, <c>Mnesia</c> must be
- started before the HTTP server. The first time <c>Mnesia</c> is
+ <p>If Mnesia is used as storage method, Mnesia must be
+ started before the HTTP server. The first time Mnesia is
started, the schema and the tables must be created before
- <c>Mnesia</c> is started. A simple example of a module with two
- functions that creates and start <c>Mnesia</c> is provided
+ Mnesia is started. A simple example of a module with two
+ functions that creates and start Mnesia is provided
here. Function <c>first_start/0</c> is to be used the first
time. It creates the schema and the tables.
<c>start/0</c> is to be used in consecutive startups.
- <c>start/0</c> starts <c>Mnesia</c> and waits for the tables to
+ <c>start/0</c> starts Mnesia and waits for the tables to
be initiated. This function must only be used when the
schema and the tables are already created.</p>
@@ -616,25 +616,25 @@ start() ->
mnesia:start(),
mnesia:wait_for_tables([httpd_user, httpd_group], 60000). </code>
- <p>To create the <c>Mnesia</c> tables, we use two records defined in
+ <p>To create the Mnesia tables, we use two records defined in
<c>mod_auth.hrl</c>, so that file must be included. <c>first_start/0</c>
creates a schema that specifies on which nodes the database is to reside.
- Then it starts <c>Mnesia</c> and creates the tables. The first argument
+ Then it starts Mnesia and creates the tables. The first argument
is the name of the tables, the second argument is a list of options of
how to create the table, see
- <seealso marker="mnesia:mnesia"><c>mnesia</c></seealso>, documentation for
+ <seealso marker="mnesia:mnesia"><c>mnesia(3)</c></seealso>, documentation for
more information. As the implementation of the <c>mod_auth_mnesia</c>
saves one row for each user, the type must be <c>bag</c>.
When the schema and the tables are created, function
<seealso marker="mnesia:mnesia#start-0">mnesia:start/0</seealso>
- is used to start <c>Mnesia</c> and
- waits for the tables to be loaded. <c>Mnesia</c> uses the
+ is used to start Mnesia and
+ waits for the tables to be loaded. Mnesia uses the
directory specified as <c>mnesia_dir</c> at startup if specified,
- otherwise <c>Mnesia</c> uses the current directory. For security
- reasons, ensure that the <c>Mnesia</c> tables are stored outside
+ otherwise Mnesia uses the current directory. For security
+ reasons, ensure that the Mnesia tables are stored outside
the document tree of the HTTP server. If they are placed in the
directory which it protects, clients can download the tables.
- Only the <c>Dets</c> and <c>Mnesia</c> storage
+ Only the Dets and Mnesia storage
methods allow writing of dynamic user data to disk. <c>plain</c> is
a read only method.</p>
</section>
@@ -669,7 +669,7 @@ start() ->
<section>
<title>mod_disk_log - Logging Using Disk_Log.</title>
<p>Standard logging using the "Common Logfile Format" and
- <seealso marker="kernel:disk_log">kernel:disk_log(3)</seealso>.</p>
+ <seealso marker="kernel:disk_log">disk_log(3)</seealso>.</p>
<p>Uses the following Erlang Web Server API interaction data:
</p>
<list type="bulleted">
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index 8e0301c520..696b7dfa31 100644
--- a/lib/inets/doc/src/http_uri.xml
+++ b/lib/inets/doc/src/http_uri.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2012</year><year>2015</year>
+ <year>2012</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -118,7 +118,7 @@
<v>Option = {ipv6_host_with_brackets, boolean()} |
{scheme_defaults, scheme_defaults()} |
{fragment, boolean()} |
- {schema_validation_fun, fun()}]</v>
+ {scheme_validation_fun, fun()}]</v>
<v>Result = {Scheme, UserInfo, Host, Port, Path, Query} |
{Scheme, UserInfo, Host, Port, Path, Query, Fragment}</v>
<v>UserInfo = user_info()</v>
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index ca9b268a03..4217b3c4fb 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2015</year>
+ <year>2004</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -68,11 +68,11 @@
this module:</p>
<p><c>boolean() = true | false</c></p>
<p><c>string()</c> = list of ASCII characters</p>
- <p><c>request_id() = ref()</c></p>
+ <p><c>request_id() = reference()</c></p>
<p><c>profile() = atom()</c></p>
<p><c>path() = string()</c> representing a file path or directory path</p>
<p><c>ip_address()</c> = See the
- <seealso marker="kernel:inet">inet(3)</seealso> manual page in <c>Kernel</c>.</p>
+ <seealso marker="kernel:inet">inet(3)</seealso> manual page in Kernel.</p>
<p><c>socket_opt()</c> = See the options used by
<seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> <c>gen_tcp(3)</c> and
<seealso marker="ssl:ssl">ssl(3)</seealso> connect(s)</p>
@@ -83,7 +83,7 @@
<title>HTTP DATA TYPES</title>
<p>Type definitions related to HTTP:</p>
- <p><c>method() = head | get | put | post | trace | options | delete</c></p>
+ <p><c>method() = head | get | put | post | trace | options | delete | patch</c></p>
<taglist>
<tag><c>request()</c></tag>
<item><p>= <c>{url(), headers()}</c></p>
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 62b92b8356..d74635fc01 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2015</year>
+ <year>1997</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -455,7 +455,7 @@ text/plain asc txt</pre>
directory. Several files can be given, in which case the server
returns the first it finds, for example:</p>
- <code>{directory_index, ["index.hml", "welcome.html"]}</code>
+ <code>{directory_index, ["index.html", "welcome.html"]}</code>
<p>Access to http://your.server.org/docs/ would return
http://your.server.org/docs/index.html or
@@ -711,7 +711,7 @@ text/plain asc txt</pre>
<item>
<p>Sets the type of authentication database that is used for the
directory. The key difference between the different methods is
- that dynamic data can be saved when <c>Mnesia</c> and <c>Dets</c>
+ that dynamic data can be saved when Mnesia and Dets
are used.
This property is called <c>AuthDbType</c> in the Apache-like
configuration files.</p>
@@ -731,10 +731,10 @@ text/plain asc txt</pre>
<code> ragnar:s7Xxv7
edward:wwjau8 </code>
- <p>If the <c>Dets</c> storage method is used, the user database is
- maintained by <c>Dets</c> and must not be edited by hand. Use the
+ <p>If the Dets storage method is used, the user database is
+ maintained by Dets and must not be edited by hand. Use the
API functions in module <c>mod_auth</c> to create/edit the user
- database. This directive is ignored if the <c>Mnesia</c>
+ database. This directive is ignored if the Mnesia
storage method is used. For security reasons, ensure that
<c>auth_user_file</c> is stored outside the document tree of the web
server. If it is placed in the directory that it protects,
@@ -753,10 +753,10 @@ text/plain asc txt</pre>
<code>group1: bob joe ante</code>
- <p>If the <c>Dets</c> storage method is used, the group database is
- maintained by <c>Dets</c> and must not be edited by hand. Use the
+ <p>If the Dets storage method is used, the group database is
+ maintained by Dets and must not be edited by hand. Use the
API for module <c>mod_auth</c> to create/edit the group database.
- This directive is ignored if the <c>Mnesia</c> storage method is used.
+ This directive is ignored if the Mnesia storage method is used.
For security reasons, ensure that the <c>auth_group_file</c> is
stored outside the document tree of the web server. If it is
placed in the directory that it protects, clients
diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml
index 4b7088b2c5..c4f844622b 100644
--- a/lib/inets/doc/src/mod_auth.xml
+++ b/lib/inets/doc/src/mod_auth.xml
@@ -33,7 +33,7 @@
<modulesummary>User authentication using text files, Dets, or Mnesia database.</modulesummary>
<description>
<p>This module provides for basic user authentication using
- textual files, <c>Dets</c> databases, or <c>Mnesia</c> databases.</p>
+ textual files, Dets databases, or Mnesia databases.</p>
</description>
<funcs>
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index 8279fdc824..46cc796c8a 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -61,13 +61,13 @@
<tag><c>{server_port, integer()}</c></tag>
<item><p>Servers port number.</p></item>
- <tag><c>{request_method, "GET | "PUT" | "DELETE | "POST" | "PATCH"}</c></tag>
+ <tag><c>{request_method, "GET | "PUT" | "DELETE" | "POST" | "PATCH"}</c></tag>
<item><p>HTTP request method.</p></item>
<tag><c>{remote_adress, inet:ip_address()} </c></tag>
<item><p>The clients ip address.</p></item>
- <tag><c>{peer_cert, undefined | no_peercert | DER:binary()</c></tag>
+ <tag><c>{peer_cert, undefined | no_peercert | DER:binary()}</c></tag>
<item>
<p>For TLS connections where client certificates are used this will
be an ASN.1 DER-encoded X509-certificate as an Erlang binary.
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 5321203511..a3e4893ae2 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,7 +33,221 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.3</title>
+ <section><title>Inets 6.3.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The close of a chunked file reception crashed in a
+ certain timing sequence.</p>
+ <p>
+ Own Id: OTP-14391 Aux Id: seq13306 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.8</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added missing release note for inets-6.3.7</p>
+ <p>
+ Own Id: OTP-14383</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug in ftp that made further operations after a
+ recv_chunk operation impossible.</p>
+ <p>
+ Own Id: OTP-14242</p>
+ </item>
+
+ <item>
+ <p>Make default port, 80 and 443, implicit in automatic redirection.
+ </p>
+ <p> Own Id: OTP-14301
+ </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Chunk size decoding could fail. The symptom was that
+ chunk decoding sometimes failed depending on timing of
+ the received stream. If chunk size was split into two
+ different packets decoding would fail.</p>
+ <p>
+ Own Id: OTP-13571 Aux Id: ERL-116 </p>
+ </item>
+ <item>
+ <p>
+ Prevent httpc user process to hang if httpc_handler
+ process terminates unexpectedly</p>
+ <p>
+ Own Id: OTP-14091</p>
+ </item>
+ <item>
+ <p>
+ Correct Host header, to include port number, when
+ redirecting requests.</p>
+ <p>
+ Own Id: OTP-14097</p>
+ </item>
+ <item>
+ <p>
+ Shutdown gracefully on connection or TLS handshake errors</p>
+ <p>
+ Own Id: OTP-14173 Aux Id: seq13262 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct misstakes in ftp client introduced in inets-6.3.4</p>
+ <p>
+ Own Id: OTP-14203 Aux Id: OTP-13982 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixes a bug that makes the ftp client end up in bad state
+ if there is a multi line response from the server and the
+ response number is in the message being sent.</p>
+ <p>
+ Own Id: OTP-13960 Aux Id: PR1196 </p>
+ </item>
+ <item>
+ <p>
+ The ftp client could stop consuming messages when the
+ multiline response handling was corrected.</p>
+ <p>
+ Own Id: OTP-13967</p>
+ </item>
+ <item>
+ <p>
+ Fix keep-alive https through proxy connections so that
+ all requests, following the first one, will run as
+ expected instead of failing.</p>
+ <p>
+ Own Id: OTP-14041</p>
+ </item>
+ <item>
+ <p>
+ Fix bug from commit
+ fdfda2fab0921d409789174556582db28141448e that could make
+ listing of group members in mod_auth callbacks fail.</p>
+ <p>
+ Own Id: OTP-14082</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update behavior of httpc:request to match RFC-7231</p>
+ <p>
+ Own Id: OTP-13902</p>
+ </item>
+ <item>
+ <p>
+ Fixed dialyzer warnings as well as some white-space
+ issues. Thanks to Kostis.</p>
+ <p>
+ Own Id: OTP-13982 Aux Id: PR-1207 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The legacy option 'inet6fb4' for inets had stopped
+ working. This bug has now been corrected. Fix by Edwin
+ Fine in bugs.erlang.org ERL-200 and Github PR#1132.</p>
+ <p>
+ Own Id: OTP-13776 Aux Id: ERL-200 PR-1132 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ PUT and DELETE support has been added to mod_esi</p>
+ <p>
+ Own Id: OTP-13688 Aux Id: seq13149 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A debug message was accidently left enabled in the ftp
+ client.</p>
+ <p>
+ Own Id: OTP-13712 Aux Id: seq13143 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index bbf25f8e90..e0430654eb 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -100,14 +100,21 @@
ftp_extension = ?FTP_EXT_DEFAULT
}).
+-record(recv_chunk_closing, {
+ dconn_closed = false,
+ pos_compl_received = false,
+ client_called_us = false
+ }).
+
-type shortage_reason() :: 'etnospc' | 'epnospc'.
-type restriction_reason() :: 'epath' | 'efnamena' | 'elogin' | 'enotbinary'.
-type common_reason() :: 'econn' | 'eclosed' | term().
-type file_write_error_reason() :: term(). % See file:write for more info
-%%-define(DBG(F,A), 'n/a').
--define(DBG(F,A), io:format(F,A)).
+-define(DBG(F,A), 'n/a').
+%%-define(DBG(F,A), io:format(F,A)).
+%%-define(DBG(F,A), ct:pal("~p:~p " ++ if is_list(F) -> F; is_atom(F) -> atom_to_list(F) end, [?MODULE,?LINE|A])).
%%%=========================================================================
%%% API - CLIENT FUNCTIONS
@@ -1095,7 +1102,7 @@ init(Options) ->
erlang:monitor(process, Client),
%% Make sure inet is started
- inet_db:start(),
+ _ = inet_db:start(),
%% Where are we
{ok, Dir} = file:get_cwd(),
@@ -1105,15 +1112,17 @@ init(Options) ->
trace ->
dbg:tracer(),
dbg:p(all, [call]),
- dbg:tpl(ftp, [{'_', [], [{return_trace}]}]),
- dbg:tpl(ftp_response, [{'_', [], [{return_trace}]}]),
- dbg:tpl(ftp_progress, [{'_', [], [{return_trace}]}]);
+ {ok, _} = dbg:tpl(ftp, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tpl(ftp_response, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tpl(ftp_progress, [{'_', [], [{return_trace}]}]),
+ ok;
debug ->
dbg:tracer(),
dbg:p(all, [call]),
- dbg:tp(ftp, [{'_', [], [{return_trace}]}]),
- dbg:tp(ftp_response, [{'_', [], [{return_trace}]}]),
- dbg:tp(ftp_progress, [{'_', [], [{return_trace}]}]);
+ {ok, _} = dbg:tp(ftp, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tp(ftp_response, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tp(ftp_progress, [{'_', [], [{return_trace}]}]),
+ ok;
_ ->
%% Keep silent
ok
@@ -1295,8 +1304,7 @@ handle_call({_,{rmdir, Dir}}, From, #state{chunk = false} = State) ->
activate_ctrl_connection(State),
{noreply, State#state{client = From}};
-handle_call({_,{type, Type}}, From, #state{chunk = false}
- = State) ->
+handle_call({_,{type, Type}}, From, #state{chunk = false} = State) ->
case Type of
ascii ->
send_ctrl_message(State, mk_cmd("TYPE A", [])),
@@ -1341,6 +1349,25 @@ handle_call({_,{recv_chunk_start, RemoteFile}}, From, #state{chunk = false}
handle_call({_, recv_chunk}, _, #state{chunk = false} = State) ->
{reply, {error, "ftp:recv_chunk_start/2 not called"}, State};
+handle_call({_, recv_chunk}, _From, #state{chunk = true,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ pos_compl_received = true
+ }
+ } = State0) ->
+ %% The ftp:recv_chunk call was the last event we waited for, finnish and clean up
+ ?DBG("recv_chunk_closing ftp:recv_chunk, last event",[]),
+ activate_ctrl_connection(State0),
+ {reply, ok, State0#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+handle_call({_, recv_chunk}, From, #state{chunk = true,
+ caller = #recv_chunk_closing{} = R
+ } = State) ->
+ %% Waiting for more, don't care what
+ ?DBG("recv_chunk_closing ftp:recv_chunk, get more",[]),
+ {noreply, State#state{client = From, caller = R#recv_chunk_closing{client_called_us=true}}};
+
handle_call({_, recv_chunk}, From, #state{chunk = true} = State0) ->
State = activate_data_connection(State0),
{noreply, State#state{client = From, caller = recv_chunk}};
@@ -1454,7 +1481,7 @@ handle_info({Trpt, Socket, Data},
#state{dsock = {Trpt,Socket},
caller = {recv_file, Fd}} = State0) when Trpt==tcp;Trpt==ssl ->
?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State0]),
- file_write(binary_to_list(Data), Fd),
+ ok = file_write(binary_to_list(Data), Fd),
progress_report({binary, Data}, State0),
State = activate_data_connection(State0),
{noreply, State};
@@ -1473,24 +1500,29 @@ handle_info({Trpt, Socket, Data}, #state{dsock = {Trpt,Socket}} = State0) when T
Data/binary>>}};
handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
- caller = {recv_file, Fd}}
- = State) when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ caller = {recv_file, Fd}} = State)
+ when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
file_close(Fd),
progress_report({transfer_size, 0}, State),
activate_ctrl_connection(State),
+ ?DBG("Data channel close",[]),
{noreply, State#state{dsock = undefined, data = <<>>}};
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, client = From,
- caller = recv_chunk}
- = State) when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- gen_server:reply(From, ok),
- {noreply, State#state{dsock = undefined, client = undefined,
- data = <<>>, caller = undefined,
- chunk = false}};
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
+ client = Client,
+ caller = recv_chunk} = State)
+ when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close recv_chunk",[]),
+ activate_ctrl_connection(State),
+ {noreply, State#state{dsock = undefined,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ client_called_us = Client =/= undefined}
+ }};
handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
data = Data} = State)
when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close",[]),
activate_ctrl_connection(State),
{noreply, State#state{dsock = undefined, data = <<>>,
caller = {recv_bin, Data}}};
@@ -1498,6 +1530,7 @@ handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, data = Data,
caller = {handle_dir_result, Dir}}
= State) when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close",[]),
activate_ctrl_connection(State),
{noreply, State#state{dsock = undefined,
caller = {handle_dir_result, Dir, Data},
@@ -1599,13 +1632,13 @@ terminate(normal, State) ->
%% If terminate reason =/= normal the progress reporting process will
%% be killed by the exit signal.
progress_report(stop, State),
- do_termiante({error, econn}, State);
+ do_terminate({error, econn}, State);
terminate(Reason, State) ->
Report = io_lib:format("Ftp connection closed due to: ~p~n", [Reason]),
error_logger:error_report(Report),
- do_termiante({error, eclosed}, State).
+ do_terminate({error, eclosed}, State).
-do_termiante(ErrorMsg, State) ->
+do_terminate(ErrorMsg, State) ->
close_data_connection(State),
close_ctrl_connection(State),
case State#state.client of
@@ -2044,6 +2077,30 @@ handle_ctrl_result({pos_prel, _}, #state{client = From,
end;
%%--------------------------------------------------------------------------
+%% File handling - chunk_transfer complete
+
+handle_ctrl_result({pos_compl, _}, #state{client = From,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ client_called_us = true,
+ pos_compl_received = false
+ }}
+ = State0) when From =/= undefined ->
+ %% The pos_compl was the last event we waited for, finnish and clean up
+ ?DBG("recv_chunk_closing pos_compl, last event",[]),
+ gen_server:reply(From, ok),
+ activate_ctrl_connection(State0),
+ {noreply, State0#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+handle_ctrl_result({pos_compl, _}, #state{caller = #recv_chunk_closing{}=R}
+ = State0) ->
+ %% Waiting for more, don't care what
+ ?DBG("recv_chunk_closing pos_compl, wait more",[]),
+ {noreply, State0#state{caller = R#recv_chunk_closing{pos_compl_received=true}}};
+
+
+%%--------------------------------------------------------------------------
%% File handling - recv_file
handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State0) ->
case accept_data_connection(State0) of
@@ -2099,7 +2156,7 @@ handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_data, Bin}}
%%--------------------------------------------------------------------------
%% Default
-handle_ctrl_result({Status, Lines}, #state{client = From} = State)
+handle_ctrl_result({Status, _Lines}, #state{client = From} = State)
when From =/= undefined ->
ctrl_result_response(Status, State, {error, Status}).
@@ -2220,16 +2277,16 @@ setup_data_connection(#state{mode = active,
{ok, Port} = inet:port(LSock),
case FtpExt of
false ->
- {IP1, IP2, IP3, IP4} = IP,
- {Port1, Port2} = {Port div 256, Port rem 256},
- send_ctrl_message(State,
- mk_cmd("PORT ~w,~w,~w,~w,~w,~w",
- [IP1, IP2, IP3, IP4, Port1, Port2]));
- true ->
- IpAddress = inet_parse:ntoa(IP),
- Cmd = mk_cmd("EPRT |1|~s|~p|", [IpAddress, Port]),
- send_ctrl_message(State, Cmd)
- end,
+ {IP1, IP2, IP3, IP4} = IP,
+ {Port1, Port2} = {Port div 256, Port rem 256},
+ send_ctrl_message(State,
+ mk_cmd("PORT ~w,~w,~w,~w,~w,~w",
+ [IP1, IP2, IP3, IP4, Port1, Port2]));
+ true ->
+ IpAddress = inet_parse:ntoa(IP),
+ Cmd = mk_cmd("EPRT |1|~s|~p|", [IpAddress, Port]),
+ send_ctrl_message(State, Cmd)
+ end,
activate_ctrl_connection(State),
{noreply, State#state{caller = {setup_data_connection,
{LSock, Caller}}}}
@@ -2337,7 +2394,7 @@ accept_data_connection(#state{mode = passive} = State) ->
send_ctrl_message(_S=#state{csock = Socket, verbose = Verbose}, Message) ->
verbose(lists:flatten(Message),Verbose,send),
?DBG('<--ctrl ~p ---- ~s~p~n',[Socket,Message,_S]),
- send_message(Socket, Message).
+ _ = send_message(Socket, Message).
send_data_message(_S=#state{dsock = Socket}, Message) ->
?DBG('<==data ~p ==== ~s~n~p~n',[Socket,Message,_S]),
@@ -2358,24 +2415,34 @@ send_message({tcp, Socket}, Message) ->
send_message({ssl, Socket}, Message) ->
ssl:send(Socket, Message).
-activate_ctrl_connection(#state{csock = Socket, ctrl_data = {<<>>, _, _}}) ->
- activate_connection(Socket);
-activate_ctrl_connection(#state{csock = Socket}) ->
+activate_ctrl_connection(#state{csock = CSock, ctrl_data = {<<>>, _, _}}) ->
+ activate_connection(CSock);
+activate_ctrl_connection(#state{csock = CSock}) ->
+ activate_connection(CSock),
%% We have already received at least part of the next control message,
%% that has been saved in ctrl_data, process this first.
- self() ! {tcp, unwrap_socket(Socket), <<>>}.
-
-unwrap_socket({tcp,Socket}) -> Socket;
-unwrap_socket({ssl,Socket}) -> Socket;
-unwrap_socket(Socket) -> Socket.
-
+ self() ! {socket_type(CSock), unwrap_socket(CSock), <<>>},
+ ok.
-activate_data_connection(#state{dsock = Socket} = State) ->
- activate_connection(Socket),
+activate_data_connection(#state{dsock = DSock} = State) ->
+ activate_connection(DSock),
State.
-activate_connection({tcp, Socket}) -> inet:setopts(Socket, [{active, once}]);
-activate_connection({ssl, Socket}) -> ssl:setopts(Socket, [{active, once}]).
+activate_connection(Socket) ->
+ ignore_return_value(
+ case socket_type(Socket) of
+ tcp -> inet:setopts(unwrap_socket(Socket), [{active, once}]);
+ ssl -> ssl:setopts(unwrap_socket(Socket), [{active, once}])
+ end).
+
+
+ignore_return_value(_) -> ok.
+
+unwrap_socket({tcp,Socket}) -> Socket;
+unwrap_socket({ssl,Socket}) -> Socket.
+
+socket_type({tcp,_Socket}) -> tcp;
+socket_type({ssl,_Socket}) -> ssl.
close_ctrl_connection(#state{csock = undefined}) -> ok;
close_ctrl_connection(#state{csock = Socket}) -> close_connection(Socket).
@@ -2383,16 +2450,16 @@ close_ctrl_connection(#state{csock = Socket}) -> close_connection(Socket).
close_data_connection(#state{dsock = undefined}) -> ok;
close_data_connection(#state{dsock = Socket}) -> close_connection(Socket).
-close_connection({lsock,Socket}) -> gen_tcp:close(Socket);
-close_connection({tcp, Socket}) -> gen_tcp:close(Socket);
-close_connection({ssl, Socket}) -> ssl:close(Socket).
+close_connection({lsock,Socket}) -> ignore_return_value( gen_tcp:close(Socket) );
+close_connection({tcp, Socket}) -> ignore_return_value( gen_tcp:close(Socket) );
+close_connection({ssl, Socket}) -> ignore_return_value( ssl:close(Socket) ).
-%% ------------ FILE HANDELING ----------------------------------------
+%% ------------ FILE HANDLING ----------------------------------------
send_file(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State, Fd) ->
{noreply, State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, send_file, Fd}}};
send_file(State, Fd) ->
case file_read(Fd) of
- {ok, N, Bin} when N > 0->
+ {ok, N, Bin} when N > 0 ->
send_data_message(State, Bin),
progress_report({binary, Bin}, State),
send_file(State, Fd);
@@ -2412,7 +2479,7 @@ file_open(File, Option) ->
file:open(File, [raw, binary, Option]).
file_close(Fd) ->
- file:close(Fd).
+ ignore_return_value( file:close(Fd) ).
file_read(Fd) ->
case file:read(Fd, ?FILE_BUFSIZE) of
@@ -2504,7 +2571,7 @@ progress_report(stop, #state{progress = ProgressPid}) ->
ftp_progress:stop(ProgressPid);
progress_report({binary, Data}, #state{progress = ProgressPid}) ->
ftp_progress:report(ProgressPid, {transfer_size, size(Data)});
-progress_report(Report, #state{progress = ProgressPid}) ->
+progress_report(Report, #state{progress = ProgressPid}) ->
ftp_progress:report(ProgressPid, Report).
diff --git a/lib/inets/src/ftp/ftp_progress.erl b/lib/inets/src/ftp/ftp_progress.erl
index 68185a222d..a6263e5cd7 100644
--- a/lib/inets/src/ftp/ftp_progress.erl
+++ b/lib/inets/src/ftp/ftp_progress.erl
@@ -36,11 +36,11 @@
-include_lib("kernel/include/file.hrl").
-record(progress, {
- file, % string()
- cb_module, % atom()
- cb_function, % atom()
- init_progress_term, % term()
- current_progress_term % term()
+ file :: string() | 'undefined',
+ cb_module :: module(),
+ cb_function :: atom(),
+ init_progress_term :: term(),
+ current_progress_term :: term()
}).
%%%=========================================================================
@@ -53,13 +53,15 @@
%% Description: Starts the progress report process unless progress reporting
%% should not be performed.
%%--------------------------------------------------------------------------
+-type options() :: 'ignore' | {module(), atom(), term()}.
+-spec start_link(options()) -> 'ignore' | pid().
start_link(ignore) ->
ignore;
start_link(Options) ->
spawn_link(?MODULE, init, [Options]).
%%--------------------------------------------------------------------------
-%% report_progress(Pid, Report) -> _
+%% report_progress(Pid, Report) -> ok
%% Pid = pid()
%% Report = {local_file, File} | {remote_file, File} |
%% {transfer_size, Size}
@@ -68,17 +70,23 @@ start_link(Options) ->
%% Description: Reports progress to the reporting process that calls the
%% user defined callback function.
%%--------------------------------------------------------------------------
+-type report() :: {'local_file', string()} | {'remote_file', string()}
+ | {'transfer_size', non_neg_integer()}.
+-spec report(pid(), report()) -> 'ok'.
report(Pid, Report) ->
- Pid ! {progress_report, Report}.
+ Pid ! {progress_report, Report},
+ ok.
%%--------------------------------------------------------------------------
-%% stop(Pid) -> _
+%% stop(Pid) -> ok
%% Pid = pid()
%%
%% Description:
%%--------------------------------------------------------------------------
+-spec stop(pid()) -> 'ok'.
stop(Pid) ->
- Pid ! stop.
+ Pid ! stop,
+ ok.
%%%=========================================================================
%%% Internal functions
diff --git a/lib/inets/src/ftp/ftp_response.erl b/lib/inets/src/ftp/ftp_response.erl
index 7533bc4550..d54d97dc91 100644
--- a/lib/inets/src/ftp/ftp_response.erl
+++ b/lib/inets/src/ftp/ftp_response.erl
@@ -90,19 +90,23 @@ parse_lines(<<C1, C2, C3, ?WHITE_SPACE, Bin/binary>>, Lines, start) ->
parse_lines(Bin, [?WHITE_SPACE, C3, C2, C1 | Lines], finish);
%% Last line found
-parse_lines(<<C1, C2, C3, ?WHITE_SPACE, Rest/binary>>, Lines, {C1, C2, C3}) ->
- parse_lines(Rest, [?WHITE_SPACE, C3, C2, C1 | Lines], finish);
+parse_lines(<<?CR, ?LF, C1, C2, C3, ?WHITE_SPACE, Rest/binary>>, Lines, {C1, C2, C3}) ->
+ parse_lines(Rest, [?WHITE_SPACE, C3, C2, C1, ?LF, ?CR | Lines], finish);
%% Potential end found wait for more data
-parse_lines(<<C1, C2, C3>> = Bin, Lines, {C1, C2, C3}) ->
+parse_lines(<<?CR, ?LF, C1, C2, C3>> = Bin, Lines, {C1, C2, C3}) ->
{continue, {Bin, Lines, {C1, C2, C3}}};
%% Intermidate line begining with status code
-parse_lines(<<C1, C2, C3, Rest/binary>>, Lines, {C1, C2, C3}) ->
- parse_lines(Rest, [C3, C2, C1 | Lines], {C1, C2, C3});
+parse_lines(<<?CR, ?LF, C1, C2, C3, Rest/binary>>, Lines, {C1, C2, C3}) ->
+ parse_lines(Rest, [C3, C2, C1, ?LF, ?CR | Lines], {C1, C2, C3});
%% Potential last line wait for more data
-parse_lines(<<C1, C2>> = Data, Lines, {C1, C2, _} = StatusCode) ->
+parse_lines(<<?CR, ?LF, C1, C2>> = Data, Lines, {C1, C2, _} = StatusCode) ->
{continue, {Data, Lines, StatusCode}};
-parse_lines(<<C1>> = Data, Lines, {C1, _, _} = StatusCode) ->
+parse_lines(<<?CR, ?LF, C1>> = Data, Lines, {C1, _, _} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+parse_lines(<<?CR, ?LF>> = Data, Lines, {_,_,_} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+parse_lines(<<?LF>> = Data, Lines, {_,_,_} = StatusCode) ->
{continue, {Data, Lines, StatusCode}};
parse_lines(<<>> = Data, Lines, {_,_,_} = StatusCode) ->
{continue, {Data, Lines, StatusCode}};
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 91d87289a2..418b6247b0 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -147,6 +147,26 @@ request(Method, Request, HttpOptions, Options) ->
request(Method, Request, HttpOptions, Options, default_profile()).
request(Method,
+ {Url, Headers, ContentType, TupleBody},
+ HTTPOptions, Options, Profile)
+ when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse (Method =:= delete))
+ andalso (is_atom(Profile) orelse is_pid(Profile)) andalso
+ is_list(ContentType) andalso is_tuple(TupleBody)->
+ case check_body_gen(TupleBody) of
+ ok ->
+ do_request(Method, {Url, Headers, ContentType, TupleBody}, HTTPOptions, Options, Profile);
+ Error ->
+ Error
+ end;
+request(Method,
+ {Url, Headers, ContentType, Body},
+ HTTPOptions, Options, Profile)
+ when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse (Method =:= delete))
+ andalso (is_atom(Profile) orelse is_pid(Profile)) andalso
+ is_list(ContentType) andalso (is_list(Body) orelse is_binary(Body)) ->
+ do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile);
+
+request(Method,
{Url, Headers},
HTTPOptions, Options, Profile)
when (Method =:= options) orelse
@@ -155,12 +175,6 @@ request(Method,
(Method =:= delete) orelse
(Method =:= trace) andalso
(is_atom(Profile) orelse is_pid(Profile)) ->
- ?hcrt("request", [{method, Method},
- {url, Url},
- {headers, Headers},
- {http_options, HTTPOptions},
- {options, Options},
- {profile, Profile}]),
case uri_parse(Url, Options) of
{error, Reason} ->
{error, Reason};
@@ -172,21 +186,9 @@ request(Method,
handle_request(Method, Url, ParsedUrl, Headers, [], [],
HTTPOptions, Options, Profile)
end
- end;
-
-request(Method,
- {Url, Headers, ContentType, Body},
- HTTPOptions, Options, Profile)
- when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse
- (Method =:= delete)) andalso (is_atom(Profile) orelse is_pid(Profile)) ->
- ?hcrt("request", [{method, Method},
- {url, Url},
- {headers, Headers},
- {content_type, ContentType},
- {body, Body},
- {http_options, HTTPOptions},
- {options, Options},
- {profile, Profile}]),
+ end.
+
+do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile) ->
case uri_parse(Url, Options) of
{error, Reason} ->
{error, Reason};
@@ -196,7 +198,6 @@ request(Method,
HTTPOptions, Options, Profile)
end.
-
%%--------------------------------------------------------------------------
%% cancel_request(RequestId) -> ok
%% cancel_request(RequestId, Profile) -> ok
@@ -209,7 +210,6 @@ cancel_request(RequestId) ->
cancel_request(RequestId, Profile)
when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("cancel request", [{request_id, RequestId}, {profile, Profile}]),
httpc_manager:cancel_request(RequestId, profile_name(Profile)).
@@ -232,7 +232,6 @@ cancel_request(RequestId, Profile)
set_options(Options) ->
set_options(Options, default_profile()).
set_options(Options, Profile) when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("set options", [{options, Options}, {profile, Profile}]),
case validate_options(Options) of
{ok, Opts} ->
httpc_manager:set_options(Opts, profile_name(Profile));
@@ -272,7 +271,6 @@ get_options(all = _Options, Profile) ->
get_options(Options, Profile)
when (is_list(Options) andalso
(is_atom(Profile) orelse is_pid(Profile))) ->
- ?hcrt("get options", [{options, Options}, {profile, Profile}]),
case Options -- get_options() of
[] ->
try
@@ -314,9 +312,6 @@ store_cookies(SetCookieHeaders, Url) ->
store_cookies(SetCookieHeaders, Url, Profile)
when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("store cookies", [{set_cookie_headers, SetCookieHeaders},
- {url, Url},
- {profile, Profile}]),
try
begin
%% Since the Address part is not actually used
@@ -353,9 +348,6 @@ cookie_header(Url, Opts) when is_list(Opts) ->
cookie_header(Url, Opts, Profile)
when (is_list(Opts) andalso (is_atom(Profile) orelse is_pid(Profile))) ->
- ?hcrt("cookie header", [{url, Url},
- {opts, Opts},
- {profile, Profile}]),
try
begin
httpc_manager:which_cookies(Url, Opts, profile_name(Profile))
@@ -398,7 +390,6 @@ which_sessions() ->
which_sessions(default_profile()).
which_sessions(Profile) ->
- ?hcrt("which sessions", [{profile, Profile}]),
try
begin
httpc_manager:which_sessions(profile_name(Profile))
@@ -419,7 +410,6 @@ info() ->
info(default_profile()).
info(Profile) ->
- ?hcrt("info", [{profile, Profile}]),
try
begin
httpc_manager:info(profile_name(Profile))
@@ -440,7 +430,6 @@ reset_cookies() ->
reset_cookies(default_profile()).
reset_cookies(Profile) ->
- ?hcrt("reset cookies", [{profile, Profile}]),
try
begin
httpc_manager:reset_cookies(profile_name(Profile))
@@ -458,7 +447,6 @@ reset_cookies(Profile) ->
%% same behavior as active once for sockets.
%%-------------------------------------------------------------------------
stream_next(Pid) ->
- ?hcrt("stream next", [{handler, Pid}]),
httpc_handler:stream_next(Pid).
@@ -466,7 +454,6 @@ stream_next(Pid) ->
%%% Behaviour callbacks
%%%========================================================================
start_standalone(PropList) ->
- ?hcrt("start standalone", [{proplist, PropList}]),
case proplists:get_value(profile, PropList) of
undefined ->
{error, no_profile};
@@ -477,14 +464,11 @@ start_standalone(PropList) ->
end.
start_service(Config) ->
- ?hcrt("start service", [{config, Config}]),
httpc_profile_sup:start_child(Config).
stop_service(Profile) when is_atom(Profile) ->
- ?hcrt("stop service", [{profile, Profile}]),
httpc_profile_sup:stop_child(Profile);
stop_service(Pid) when is_pid(Pid) ->
- ?hcrt("stop service", [{pid, Pid}]),
case service_info(Pid) of
{ok, [{profile, Profile}]} ->
stop_service(Profile);
@@ -510,7 +494,6 @@ service_info(Pid) ->
%%%========================================================================
%%% Internal functions
%%%========================================================================
-
handle_request(Method, Url,
{Scheme, UserInfo, Host, Port, Path, Query},
Headers0, ContentType, Body0,
@@ -521,9 +504,6 @@ handle_request(Method, Url,
try
begin
- ?hcrt("begin processing", [{started, Started},
- {new_headers, NewHeaders0}]),
-
{NewHeaders, Body} =
case Body0 of
{chunkify, ProcessBody, Acc}
@@ -544,7 +524,7 @@ handle_request(Method, Url,
Options = request_options(Options0),
Sync = proplists:get_value(sync, Options),
Stream = proplists:get_value(stream, Options),
- Host2 = header_host(Scheme, Host, Port),
+ Host2 = http_request:normalize_host(Scheme, Host, Port),
HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
Receiver = proplists:get_value(receiver, Options),
SocketOpts = proplists:get_value(socket_opts, Options),
@@ -575,16 +555,13 @@ handle_request(Method, Url,
{ok, RequestId} ->
handle_answer(RequestId, Sync, Options);
{error, Reason} ->
- ?hcrd("request failed", [{reason, Reason}]),
{error, Reason}
end
end
catch
error:{noproc, _} ->
- ?hcrv("noproc", [{profile, Profile}]),
{error, {not_started, Profile}};
throw:Error ->
- ?hcrv("throw", [{error, Error}]),
Error
end.
@@ -620,15 +597,10 @@ handle_answer(RequestId, false, _) ->
handle_answer(RequestId, true, Options) ->
receive
{http, {RequestId, saved_to_file}} ->
- ?hcrt("received saved-to-file", [{request_id, RequestId}]),
{ok, saved_to_file};
{http, {RequestId, {_,_,_} = Result}} ->
- ?hcrt("received answer", [{request_id, RequestId},
- {result, Result}]),
return_answer(Options, Result);
{http, {RequestId, {error, Reason}}} ->
- ?hcrt("received error", [{request_id, RequestId},
- {reason, Reason}]),
{error, Reason}
end.
@@ -1063,14 +1035,6 @@ bad_option(Option, BadValue) ->
throw({error, {bad_option, Option, BadValue}}).
-header_host(https, Host, 443 = _Port) ->
- Host;
-header_host(http, Host, 80 = _Port) ->
- Host;
-header_host(_Scheme, Host, Port) ->
- Host ++ ":" ++ integer_to_list(Port).
-
-
header_record(NewHeaders, Host, #http_options{version = Version}) ->
header_record(NewHeaders, #http_request_h{}, Host, Version).
@@ -1257,18 +1221,14 @@ child_name(Pid, [{Name, Pid} | _]) ->
child_name(Pid, [_ | Children]) ->
child_name(Pid, Children).
-%% d(F) ->
-%% d(F, []).
-
-%% d(F, A) ->
-%% d(get(dbg), F, A).
-
-%% d(true, F, A) ->
-%% io:format(user, "~w:~w:" ++ F ++ "~n", [self(), ?MODULE | A]);
-%% d(_, _, _) ->
-%% ok.
-
host_address(Host, false) ->
Host;
host_address(Host, true) ->
string:strip(string:strip(Host, right, $]), left, $[).
+
+check_body_gen({Fun, _}) when is_function(Fun) ->
+ ok;
+check_body_gen({chunkify, Fun, _}) when is_function(Fun) ->
+ ok;
+check_body_gen(Gen) ->
+ {error, {bad_body_generator, Gen}}.
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index d1c52dcc78..c99200777b 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
%% Internal Application API
-export([
start_link/4,
- %% connect_and_send/2,
send/2,
cancel/2,
stream_next/1,
@@ -45,28 +44,30 @@
-record(timers,
{
- request_timers = [], % [ref()]
- queue_timer % ref()
+ request_timers = [] :: [reference()],
+ queue_timer :: reference() | 'undefined'
}).
+-type session_failed() :: {'connect_failed',term()} | {'send_failed',term()}.
+
-record(state,
{
- request, % #request{}
- session, % #session{}
+ request :: request() | 'undefined',
+ session :: session() | session_failed() | 'undefined',
status_line, % {Version, StatusCode, ReasonPharse}
- headers, % #http_response_h{}
- body, % binary()
+ headers :: http_response_h() | 'undefined',
+ body :: binary() | 'undefined',
mfa, % {Module, Function, Args}
- pipeline = queue:new(), % queue:queue()
- keep_alive = queue:new(), % queue:queue()
+ pipeline = queue:new() :: queue:queue(),
+ keep_alive = queue:new() :: queue:queue(),
status, % undefined | new | pipeline | keep_alive | close | {ssl_tunnel, Request}
canceled = [], % [RequestId]
- max_header_size = nolimit, % nolimit | integer()
- max_body_size = nolimit, % nolimit | integer()
- options, % #options{}
- timers = #timers{}, % #timers{}
- profile_name, % atom() - id of httpc_manager process.
- once = inactive % inactive | once
+ max_header_size = nolimit :: nolimit | integer(),
+ max_body_size = nolimit :: nolimit | integer(),
+ options :: options(),
+ timers = #timers{} :: #timers{},
+ profile_name :: atom(), % id of httpc_manager process.
+ once = inactive :: 'inactive' | 'once'
}).
@@ -113,7 +114,7 @@ send(Request, Pid) ->
%%--------------------------------------------------------------------
%% Function: cancel(RequestId, Pid) -> ok
-%% RequestId = ref()
+%% RequestId = reference()
%% Pid = pid() - the pid of the http-request handler process.
%%
%% Description: Cancels a request. Intended to be called by the httpc
@@ -163,14 +164,12 @@ info(Pid) ->
%%--------------------------------------------------------------------
%% Request should not be streamed
stream(BodyPart, #request{stream = none} = Request, _) ->
- ?hcrt("stream - none", []),
{false, BodyPart, Request};
%% Stream to caller
stream(BodyPart, #request{stream = Self} = Request, Code)
when ?IS_STREAMED(Code) andalso
((Self =:= self) orelse (Self =:= {self, once})) ->
- ?hcrt("stream - self", [{stream, Self}, {code, Code}]),
httpc_response:send(Request#request.from,
{Request#request.id, stream, BodyPart}),
{true, <<>>, Request};
@@ -180,10 +179,8 @@ stream(BodyPart, #request{stream = Self} = Request, Code)
%% We keep this for backward compatibillity...
stream(BodyPart, #request{stream = Filename} = Request, Code)
when ?IS_STREAMED(Code) andalso is_list(Filename) ->
- ?hcrt("stream - filename", [{stream, Filename}, {code, Code}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
{ok, Fd} ->
- ?hcrt("stream - file open ok", [{fd, Fd}]),
stream(BodyPart, Request#request{stream = Fd}, 200);
{error, Reason} ->
exit({stream_to_file_failed, Reason})
@@ -192,7 +189,6 @@ stream(BodyPart, #request{stream = Filename} = Request, Code)
%% Stream to file
stream(BodyPart, #request{stream = Fd} = Request, Code)
when ?IS_STREAMED(Code) ->
- ?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
ok ->
{true, <<>>, Request};
@@ -201,7 +197,6 @@ stream(BodyPart, #request{stream = Fd} = Request, Code)
end;
stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
- ?hcrt("stream - ignore", [{request, Request}]),
{false, BodyPart, Request}.
@@ -255,22 +250,148 @@ init([Parent, Request, Options, ProfileName]) ->
%% {stop, Reason, State} (terminate/2 is called)
%% Description: Handling call messages
%%--------------------------------------------------------------------
-handle_call(#request{address = Addr} = Request, _,
+handle_call(Request, From, State) ->
+ try do_handle_call(Request, From, State) of
+ Result ->
+ Result
+ catch
+ _:Reason ->
+ {stop, {shutdown, Reason} , State}
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(Msg, State) ->
+ try do_handle_cast(Msg, State) of
+ Result ->
+ Result
+ catch
+ _:Reason ->
+ {stop, {shutdown, Reason} , State}
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info(Info, State) ->
+ try do_handle_info(Info, State) of
+ Result ->
+ Result
+ catch
+ _:Reason ->
+ {stop, {shutdown, Reason} , State}
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: terminate(Reason, State) -> _ (ignored by gen_server)
+%% Description: Shutdown the httpc_handler
+%%--------------------------------------------------------------------
+
+%% Init error there is no socket to be closed.
+terminate(normal,
+ #state{request = Request,
+ session = {send_failed, _} = Reason} = State) ->
+ maybe_send_answer(Request,
+ httpc_response:error(Request, Reason),
+ State),
+ ok;
+
+terminate(normal,
+ #state{request = Request,
+ session = {connect_failed, _} = Reason} = State) ->
+ maybe_send_answer(Request,
+ httpc_response:error(Request, Reason),
+ State),
+ ok;
+
+terminate(normal, #state{session = undefined}) ->
+ ok;
+
+%% Init error sending, no session information has been setup but
+%% there is a socket that needs closing.
+terminate(normal,
+ #state{session = #session{id = undefined} = Session}) ->
+ close_socket(Session);
+
+%% Socket closed remotely
+terminate(normal,
+ #state{session = #session{socket = {remote_close, Socket},
+ socket_type = SocketType,
+ id = Id},
+ profile_name = ProfileName,
+ request = Request,
+ timers = Timers,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
+ %% Clobber session
+ (catch httpc_manager:delete_session(Id, ProfileName)),
+
+ maybe_retry_queue(Pipeline, State),
+ maybe_retry_queue(KeepAlive, State),
+
+ %% Cancel timers
+ cancel_timers(Timers),
+
+ %% Maybe deliver answers to requests
+ deliver_answer(Request),
+
+ %% And, just in case, close our side (**really** overkill)
+ http_transport:close(SocketType, Socket);
+
+terminate(_Reason, #state{session = #session{id = Id,
+ socket = Socket,
+ socket_type = SocketType},
+ request = undefined,
+ profile_name = ProfileName,
+ timers = Timers,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
+
+ %% Clobber session
+ (catch httpc_manager:delete_session(Id, ProfileName)),
+
+ maybe_retry_queue(Pipeline, State),
+ maybe_retry_queue(KeepAlive, State),
+
+ cancel_timer(Timers#timers.queue_timer, timeout_queue),
+ http_transport:close(SocketType, Socket);
+
+terminate(_Reason, #state{request = undefined}) ->
+ ok;
+
+terminate(Reason, #state{request = Request} = State) ->
+ NewState = maybe_send_answer(Request,
+ httpc_response:error(Request, Reason),
+ State),
+ terminate(Reason, NewState#state{request = undefined}).
+
+%%--------------------------------------------------------------------
+%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
+%% Purpose: Convert process state when code is changed
+%%--------------------------------------------------------------------
+
+code_change(_, State, _) ->
+ {ok, State}.
+
+%%%--------------------------------------------------------------------
+%%% Internal functions
+%%%--------------------------------------------------------------------
+do_handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #session{type = pipeline} = Session,
timers = Timers,
options = #options{proxy = Proxy} = _Options,
profile_name = ProfileName} = State0)
when Status =/= undefined ->
-
- ?hcrv("new request on a pipeline session",
- [{request, Request},
- {profile, ProfileName},
- {status, Status},
- {timers, Timers}]),
-
Address = handle_proxy(Addr, Proxy),
-
case httpc_request:send(Address, Session, Request) of
ok ->
@@ -285,9 +406,8 @@ handle_call(#request{address = Addr} = Request, _,
case State0#state.request of
#request{} = OldRequest -> %% Old request not yet finished
- ?hcrd("old request still not finished", []),
%% Make sure to use the new value of timers in state
- NewTimers = State1#state.timers,
+ NewTimers = State1#state.timers,
NewPipeline = queue:in(Request, State1#state.pipeline),
NewSession =
Session#session{queue_length =
@@ -295,7 +415,6 @@ handle_call(#request{address = Addr} = Request, _,
queue:len(NewPipeline) + 1,
client_close = ClientClose},
insert_session(NewSession, ProfileName),
- ?hcrd("session updated", []),
{reply, ok, State1#state{
request = OldRequest,
pipeline = NewPipeline,
@@ -304,7 +423,6 @@ handle_call(#request{address = Addr} = Request, _,
undefined ->
%% Note: tcp-message receiving has already been
%% activated by handle_pipeline/2.
- ?hcrd("no current request", []),
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
NewSession =
@@ -312,18 +430,16 @@ handle_call(#request{address = Addr} = Request, _,
client_close = ClientClose},
httpc_manager:insert_session(NewSession, ProfileName),
NewTimers = Timers#timers{queue_timer = undefined},
- ?hcrd("session created", []),
State = init_wait_for_response_state(Request, State1#state{session = NewSession,
timers = NewTimers}),
{reply, ok, State}
end;
{error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
NewPipeline = queue:in(Request, State0#state.pipeline),
- {stop, shutdown, {pipeline_failed, Reason}, State0#state{pipeline = NewPipeline}}
+ {stop, {shutdown, {pipeline_failed, Reason}}, State0#state{pipeline = NewPipeline}}
end;
-handle_call(#request{address = Addr} = Request, _,
+do_handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #session{type = keep_alive} = Session,
timers = Timers,
@@ -331,17 +447,11 @@ handle_call(#request{address = Addr} = Request, _,
profile_name = ProfileName} = State0)
when Status =/= undefined ->
- ?hcrv("new request on a keep-alive session",
- [{request, Request},
- {profile, ProfileName},
- {status, Status}]),
-
ClientClose = httpc_request:is_client_closing(Request#request.headers),
case State0#state.request of
#request{} -> %% Old request not yet finished
%% Make sure to use the new value of timers in state
- ?hcrd("old request still not finished", []),
NewKeepAlive = queue:in(Request, State0#state.keep_alive),
NewSession =
Session#session{queue_length =
@@ -349,13 +459,11 @@ handle_call(#request{address = Addr} = Request, _,
queue:len(NewKeepAlive) + 1,
client_close = ClientClose},
insert_session(NewSession, ProfileName),
- ?hcrd("session updated", []),
{reply, ok, State0#state{keep_alive = NewKeepAlive,
session = NewSession}};
undefined ->
%% Note: tcp-message receiving has already been
%% activated by handle_pipeline/2.
- ?hcrd("no current request", []),
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
NewTimers = Timers#timers{queue_timer = undefined},
@@ -363,8 +471,6 @@ handle_call(#request{address = Addr} = Request, _,
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, Request) of
ok ->
- ?hcrd("request sent", []),
-
%% Activate the request time out for the new request
State2 =
activate_request_timeout(State1#state{request = Request}),
@@ -375,22 +481,13 @@ handle_call(#request{address = Addr} = Request, _,
State = init_wait_for_response_state(Request, State2#state{session = NewSession}),
{reply, ok, State};
{error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
- {stop, shutdown, {keepalive_failed, Reason}, State1}
+ {stop, {shutdown, {keepalive_failed, Reason}}, State1}
end
end;
-
-handle_call(info, _, State) ->
+do_handle_call(info, _, State) ->
Info = handler_info(State),
{reply, Info, State}.
-%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State} (terminate/2 is called)
-%% Description: Handling cast messages
-%%--------------------------------------------------------------------
-
%% When the request in process has been canceled the handler process is
%% stopped and the pipelined requests will be reissued or remaining
%% requests will be sent on a new connection. This is is
@@ -403,145 +500,102 @@ handle_call(info, _, State) ->
%% handle_keep_alive_queue/2 on the other hand will just skip the
%% request as if it was never issued as in this case the request will
%% not have been sent.
-handle_cast({cancel, RequestId},
+do_handle_cast({cancel, RequestId},
#state{request = #request{id = RequestId} = Request,
- profile_name = ProfileName,
canceled = Canceled} = State) ->
- ?hcrv("cancel current request", [{request_id, RequestId},
- {profile, ProfileName},
- {canceled, Canceled}]),
{stop, normal,
State#state{canceled = [RequestId | Canceled],
request = Request#request{from = answer_sent}}};
-handle_cast({cancel, RequestId},
- #state{profile_name = ProfileName,
- request = #request{id = CurrId},
- canceled = Canceled} = State) ->
- ?hcrv("cancel", [{request_id, RequestId},
- {curr_req_id, CurrId},
- {profile, ProfileName},
- {canceled, Canceled}]),
+do_handle_cast({cancel, RequestId},
+ #state{request = #request{},
+ canceled = Canceled} = State) ->
{noreply, State#state{canceled = [RequestId | Canceled]}};
-handle_cast({cancel, RequestId},
- #state{profile_name = ProfileName,
- request = undefined,
- canceled = Canceled} = State) ->
- ?hcrv("cancel", [{request_id, RequestId},
- {curr_req_id, undefined},
- {profile, ProfileName},
- {canceled, Canceled}]),
+do_handle_cast({cancel, _},
+ #state{request = undefined} = State) ->
{noreply, State};
-
-handle_cast(stream_next, #state{session = Session} = State) ->
+do_handle_cast(stream_next, #state{session = Session} = State) ->
activate_once(Session),
%% Inactivate the #state.once here because we don't want
%% next_body_chunk/1 to activate the socket twice.
{noreply, State#state{once = inactive}}.
-
-%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State} (terminate/2 is called)
-%% Description: Handling all non call/cast messages
-%%--------------------------------------------------------------------
-handle_info({Proto, _Socket, Data},
+do_handle_info({Proto, _Socket, Data},
#state{mfa = {Module, Function, Args},
- request = #request{method = Method,
- stream = Stream} = Request,
+ request = #request{method = Method} = Request,
session = Session,
status_line = StatusLine} = State)
when (Proto =:= tcp) orelse
(Proto =:= ssl) orelse
(Proto =:= httpc_handler) ->
- ?hcri("received data", [{proto, Proto},
- {module, Module},
- {function, Function},
- {method, Method},
- {stream, Stream},
- {session, Session},
- {status_line, StatusLine}]),
-
- FinalResult =
- try Module:Function([Data | Args]) of
- {ok, Result} ->
- ?hcrd("data processed - ok", []),
- handle_http_msg(Result, State);
- {_, whole_body, _} when Method =:= head ->
- ?hcrd("data processed - whole body", []),
- handle_response(State#state{body = <<>>});
- {Module, whole_body, [Body, Length]} ->
- ?hcrd("data processed - whole body", [{length, Length}]),
- {_, Code, _} = StatusLine,
- {Streamed, NewBody, NewRequest} = stream(Body, Request, Code),
- %% When we stream we will not keep the already
- %% streamed data, that would be a waste of memory.
- NewLength =
- case Streamed of
- false ->
- Length;
- true ->
- Length - size(Body)
- end,
-
- NewState = next_body_chunk(State, Code),
- NewMFA = {Module, whole_body, [NewBody, NewLength]},
- {noreply, NewState#state{mfa = NewMFA,
- request = NewRequest}};
- {Module, decode_size,
- [TotalChunk, HexList,
+ try Module:Function([Data | Args]) of
+ {ok, Result} ->
+ handle_http_msg(Result, State);
+ {_, whole_body, _} when Method =:= head ->
+ handle_response(State#state{body = <<>>});
+ {Module, whole_body, [Body, Length]} ->
+ {_, Code, _} = StatusLine,
+ {Streamed, NewBody, NewRequest} = stream(Body, Request, Code),
+ %% When we stream we will not keep the already
+ %% streamed data, that would be a waste of memory.
+ NewLength =
+ case Streamed of
+ false ->
+ Length;
+ true ->
+ Length - size(Body)
+ end,
+
+ NewState = next_body_chunk(State, Code),
+ NewMFA = {Module, whole_body, [NewBody, NewLength]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
+ {Module, decode_size,
+ [TotalChunk, HexList, AccHeaderSize,
{MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
- when BodySoFar =/= <<>> ->
- ?hcrd("data processed - decode_size", []),
- %% The response body is chunk-encoded. Steal decoded
- %% chunks as much as possible to stream.
- {_, Code, _} = StatusLine,
- {_, NewBody, NewRequest} = stream(BodySoFar, Request, Code),
- NewState = next_body_chunk(State, Code),
- NewMFA = {Module, decode_size,
- [TotalChunk, HexList,
+ when BodySoFar =/= <<>> ->
+ %% The response body is chunk-encoded. Steal decoded
+ %% chunks as much as possible to stream.
+ {_, Code, _} = StatusLine,
+ {_, NewBody, NewRequest} = stream(BodySoFar, Request, Code),
+ NewState = next_body_chunk(State, Code),
+ NewMFA = {Module, decode_size,
+ [TotalChunk, HexList, AccHeaderSize,
{MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
+ {Module, decode_data,
+ [ChunkSize, TotalChunk,
+ {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
+ when TotalChunk =/= <<>> orelse BodySoFar =/= <<>> ->
+ %% The response body is chunk-encoded. Steal decoded
+ %% chunks as much as possible to stream.
+ ChunkSizeToSteal = min(ChunkSize, byte_size(TotalChunk)),
+ <<StolenChunk:ChunkSizeToSteal/binary, NewTotalChunk/binary>> = TotalChunk,
+ StolenBody = <<BodySoFar/binary, StolenChunk/binary>>,
+ NewChunkSize = ChunkSize - ChunkSizeToSteal,
+ {_, Code, _} = StatusLine,
+
+ {_, NewBody, NewRequest} = stream(StolenBody, Request, Code),
+ NewState = next_body_chunk(State, Code),
+ NewMFA = {Module, decode_data,
+ [NewChunkSize, NewTotalChunk,
+ {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
{noreply, NewState#state{mfa = NewMFA,
request = NewRequest}};
- {Module, decode_data,
- [ChunkSize, TotalChunk,
- {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
- when TotalChunk =/= <<>> orelse BodySoFar =/= <<>> ->
- ?hcrd("data processed - decode_data", []),
- %% The response body is chunk-encoded. Steal decoded
- %% chunks as much as possible to stream.
- ChunkSizeToSteal = min(ChunkSize, byte_size(TotalChunk)),
- <<StolenChunk:ChunkSizeToSteal/binary, NewTotalChunk/binary>> = TotalChunk,
- StolenBody = <<BodySoFar/binary, StolenChunk/binary>>,
- NewChunkSize = ChunkSize - ChunkSizeToSteal,
- {_, Code, _} = StatusLine,
-
- {_, NewBody, NewRequest} = stream(StolenBody, Request, Code),
- NewState = next_body_chunk(State, Code),
- NewMFA = {Module, decode_data,
- [NewChunkSize, NewTotalChunk,
- {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
- {noreply, NewState#state{mfa = NewMFA,
- request = NewRequest}};
- NewMFA ->
- ?hcrd("data processed - new mfa", []),
- activate_once(Session),
- {noreply, State#state{mfa = NewMFA}}
- catch
- _:_Reason ->
- ?hcrd("data processing exit", [{exit, _Reason}]),
- ClientReason = {could_not_parse_as_http, Data},
- ClientErrMsg = httpc_response:error(Request, ClientReason),
- NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState}
- end,
- ?hcri("data processed", [{final_result, FinalResult}]),
- FinalResult;
-
+ NewMFA ->
+ activate_once(Session),
+ {noreply, State#state{mfa = NewMFA}}
+ catch
+ _:Reason ->
+ ClientReason = {could_not_parse_as_http, Data},
+ ClientErrMsg = httpc_response:error(Request, ClientReason),
+ NewState = answer_request(Request, ClientErrMsg, State),
+ {stop, {shutdown, Reason}, NewState}
+ end;
-handle_info({Proto, Socket, Data},
+do_handle_info({Proto, Socket, Data},
#state{mfa = MFA,
request = Request,
session = Session,
@@ -566,200 +620,107 @@ handle_info({Proto, Socket, Data},
{noreply, State};
-
%% The Server may close the connection to indicate that the
%% whole body is now sent instead of sending an length
%% indicator.
-handle_info({tcp_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
+do_handle_info({tcp_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
handle_response(State#state{body = hd(Args)});
-handle_info({ssl_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
+do_handle_info({ssl_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
handle_response(State#state{body = hd(Args)});
%%% Server closes idle pipeline
-handle_info({tcp_closed, _}, State = #state{request = undefined}) ->
+do_handle_info({tcp_closed, _}, State = #state{request = undefined}) ->
{stop, normal, State};
-handle_info({ssl_closed, _}, State = #state{request = undefined}) ->
+do_handle_info({ssl_closed, _}, State = #state{request = undefined}) ->
{stop, normal, State};
%%% Error cases
-handle_info({tcp_closed, _}, #state{session = Session0} = State) ->
+do_handle_info({tcp_closed, _}, #state{session = Session0} = State) ->
Socket = Session0#session.socket,
Session = Session0#session{socket = {remote_close, Socket}},
%% {stop, session_remotly_closed, State};
{stop, normal, State#state{session = Session}};
-handle_info({ssl_closed, _}, #state{session = Session0} = State) ->
+do_handle_info({ssl_closed, _}, #state{session = Session0} = State) ->
Socket = Session0#session.socket,
Session = Session0#session{socket = {remote_close, Socket}},
%% {stop, session_remotly_closed, State};
{stop, normal, State#state{session = Session}};
-handle_info({tcp_error, _, _} = Reason, State) ->
+do_handle_info({tcp_error, _, _} = Reason, State) ->
{stop, Reason, State};
-handle_info({ssl_error, _, _} = Reason, State) ->
+do_handle_info({ssl_error, _, _} = Reason, State) ->
{stop, Reason, State};
%% Timeouts
%% Internally, to a request handling process, a request timeout is
%% seen as a canceled request.
-handle_info({timeout, RequestId},
+do_handle_info({timeout, RequestId},
#state{request = #request{id = RequestId} = Request,
canceled = Canceled,
profile_name = ProfileName} = State) ->
- ?hcri("timeout of current request", [{id, RequestId}]),
httpc_response:send(Request#request.from,
httpc_response:error(Request, timeout)),
httpc_manager:request_done(RequestId, ProfileName),
- ?hcrv("response (timeout) sent - now terminate", []),
{stop, normal,
State#state{request = Request#request{from = answer_sent},
canceled = [RequestId | Canceled]}};
-handle_info({timeout, RequestId},
+do_handle_info({timeout, RequestId},
#state{canceled = Canceled,
profile_name = ProfileName} = State) ->
- ?hcri("timeout", [{id, RequestId}]),
Filter =
fun(#request{id = Id, from = From} = Request) when Id =:= RequestId ->
- ?hcrv("found request", [{id, Id}, {from, From}]),
%% Notify the owner
httpc_response:send(From,
httpc_response:error(Request, timeout)),
httpc_manager:request_done(RequestId, ProfileName),
- ?hcrv("response (timeout) sent", []),
[Request#request{from = answer_sent}];
(_) ->
true
end,
case State#state.status of
pipeline ->
- ?hcrd("pipeline", []),
Pipeline = queue:filter(Filter, State#state.pipeline),
{noreply, State#state{canceled = [RequestId | Canceled],
pipeline = Pipeline}};
keep_alive ->
- ?hcrd("keep_alive", []),
KeepAlive = queue:filter(Filter, State#state.keep_alive),
{noreply, State#state{canceled = [RequestId | Canceled],
keep_alive = KeepAlive}}
end;
-handle_info(timeout_queue, State = #state{request = undefined}) ->
+do_handle_info(timeout_queue, State = #state{request = undefined}) ->
{stop, normal, State};
%% Timing was such as the queue_timeout was not canceled!
-handle_info(timeout_queue, #state{timers = Timers} = State) ->
+do_handle_info(timeout_queue, #state{timers = Timers} = State) ->
{noreply, State#state{timers =
Timers#timers{queue_timer = undefined}}};
%% Setting up the connection to the server somehow failed.
-handle_info({init_error, Tag, ClientErrMsg},
+do_handle_info({init_error, Reason, ClientErrMsg},
State = #state{request = Request}) ->
- ?hcrv("init error", [{tag, Tag}, {client_error, ClientErrMsg}]),
NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState};
-
+ {stop, {shutdown, Reason}, NewState};
%%% httpc_manager process dies.
-handle_info({'EXIT', _, _}, State = #state{request = undefined}) ->
+do_handle_info({'EXIT', _, _}, State = #state{request = undefined}) ->
{stop, normal, State};
%%Try to finish the current request anyway,
%% there is a fairly high probability that it can be done successfully.
%% Then close the connection, hopefully a new manager is started that
%% can retry requests in the pipeline.
-handle_info({'EXIT', _, _}, State) ->
+do_handle_info({'EXIT', _, _}, State) ->
{noreply, State#state{status = close}}.
-%%--------------------------------------------------------------------
-%% Function: terminate(Reason, State) -> _ (ignored by gen_server)
-%% Description: Shutdown the httpc_handler
-%%--------------------------------------------------------------------
-
-%% Init error there is no socket to be closed.
-terminate(normal,
- #state{request = Request,
- session = {send_failed, AReason} = Reason} = State) ->
- ?hcrd("terminate", [{send_reason, AReason}, {request, Request}]),
- maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- ok;
-
-terminate(normal,
- #state{request = Request,
- session = {connect_failed, AReason} = Reason} = State) ->
- ?hcrd("terminate", [{connect_reason, AReason}, {request, Request}]),
- maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- ok;
-
-terminate(normal, #state{session = undefined}) ->
- ok;
-
-%% Init error sending, no session information has been setup but
-%% there is a socket that needs closing.
-terminate(normal,
- #state{session = #session{id = undefined} = Session}) ->
- close_socket(Session);
-
-%% Socket closed remotely
-terminate(normal,
- #state{session = #session{socket = {remote_close, Socket},
- socket_type = SocketType,
- id = Id},
- profile_name = ProfileName,
- request = Request,
- timers = Timers,
- pipeline = Pipeline,
- keep_alive = KeepAlive} = State) ->
- ?hcrt("terminate(normal) - remote close",
- [{id, Id}, {profile, ProfileName}]),
-
- %% Clobber session
- (catch httpc_manager:delete_session(Id, ProfileName)),
-
- maybe_retry_queue(Pipeline, State),
- maybe_retry_queue(KeepAlive, State),
-
- %% Cancel timers
- cancel_timers(Timers),
-
- %% Maybe deliver answers to requests
- deliver_answer(Request),
-
- %% And, just in case, close our side (**really** overkill)
- http_transport:close(SocketType, Socket);
-
-terminate(Reason, #state{session = #session{id = Id,
- socket = Socket,
- socket_type = SocketType},
- request = undefined,
- profile_name = ProfileName,
- timers = Timers,
- pipeline = Pipeline,
- keep_alive = KeepAlive} = State) ->
- ?hcrt("terminate",
- [{id, Id}, {profile, ProfileName}, {reason, Reason}]),
-
- %% Clobber session
- (catch httpc_manager:delete_session(Id, ProfileName)),
-
- maybe_retry_queue(Pipeline, State),
- maybe_retry_queue(KeepAlive, State),
-
- cancel_timer(Timers#timers.queue_timer, timeout_queue),
- http_transport:close(SocketType, Socket);
+call(Msg, Pid) ->
+ call(Msg, Pid, infinity).
-terminate(Reason, #state{request = undefined}) ->
- ?hcrt("terminate", [{reason, Reason}]),
- ok;
+call(Msg, Pid, Timeout) ->
+ gen_server:call(Pid, Msg, Timeout).
-terminate(Reason, #state{request = Request} = State) ->
- ?hcrd("terminate", [{reason, Reason}, {request, Request}]),
- NewState = maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- terminate(Reason, NewState#state{request = undefined}).
+cast(Msg, Pid) ->
+ gen_server:cast(Pid, Msg).
maybe_retry_queue(Q, State) ->
case queue:is_empty(Q) of
@@ -774,86 +735,13 @@ maybe_send_answer(#request{from = answer_sent}, _Reason, State) ->
maybe_send_answer(Request, Answer, State) ->
answer_request(Request, Answer, State).
-deliver_answer(#request{id = Id, from = From} = Request)
+deliver_answer(#request{from = From} = Request)
when is_pid(From) ->
Response = httpc_response:error(Request, socket_closed_remotely),
- ?hcrd("deliver answer", [{id, Id}, {from, From}, {response, Response}]),
httpc_response:send(From, Response);
-deliver_answer(Request) ->
- ?hcrd("skip deliver answer", [{request, Request}]),
+deliver_answer(_Request) ->
ok.
-
-%%--------------------------------------------------------------------
-%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
-%% Purpose: Convert process state when code is changed
-%%--------------------------------------------------------------------
-
-code_change(_,
- #state{session = OldSession,
- profile_name = ProfileName} = State,
- upgrade_from_pre_5_8_1) ->
- case OldSession of
- {session,
- Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} ->
- NewSession = #session{id = Id,
- client_close = ClientClose,
- scheme = Scheme,
- socket = Socket,
- socket_type = SocketType,
- queue_length = QueueLen,
- type = Type},
- insert_session(NewSession, ProfileName),
- {ok, State#state{session = NewSession}};
- _ ->
- {ok, State}
- end;
-
-code_change(_,
- #state{session = OldSession,
- profile_name = ProfileName} = State,
- downgrade_to_pre_5_8_1) ->
- case OldSession of
- #session{id = Id,
- client_close = ClientClose,
- scheme = Scheme,
- socket = Socket,
- socket_type = SocketType,
- queue_length = QueueLen,
- type = Type} ->
- NewSession = {session,
- Id, ClientClose, Scheme, Socket, SocketType,
- QueueLen, Type},
- insert_session(NewSession, ProfileName),
- {ok, State#state{session = NewSession}};
- _ ->
- {ok, State}
- end;
-
-code_change(_, State, _) ->
- {ok, State}.
-
-
-%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
-%% Auth, Relaxed}) ->
-%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
-%% Auth, Relaxed}.
-
-%% old_http_options({http_options, _, TimeOut, AutoRedirect,
-%% SslOpts, Auth, Relaxed}) ->
-%% {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
-
-%% new_queue(Queue, Fun) ->
-%% List = queue:to_list(Queue),
-%% NewList =
-%% lists:map(fun(Request) ->
-%% Settings =
-%% Fun(Request#request.settings),
-%% Request#request{settings = Settings}
-%% end, List),
-%% queue:from_list(NewList).
-
-
%%%--------------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
@@ -911,31 +799,25 @@ connect(SocketType, ToAddress,
connect_and_send_first_request(Address, Request, #state{options = Options} = State) ->
SocketType = socket_type(Request),
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
- ?hcri("connect",
- [{address, Address}, {request, Request}, {options, Options}]),
case connect(SocketType, Address, Options, ConnTimeout) of
{ok, Socket} ->
ClientClose =
- httpc_request:is_client_closing(
- Request#request.headers),
+ httpc_request:is_client_closing(
+ Request#request.headers),
SessionType = httpc_manager:session_type(Options),
SocketType = socket_type(Request),
Session = #session{id = {Request#request.address, self()},
scheme = Request#request.scheme,
socket = Socket,
- socket_type = SocketType,
- client_close = ClientClose,
- type = SessionType},
- ?hcri("connected - now send first request", [{socket, Socket}]),
-
+ socket_type = SocketType,
+ client_close = ClientClose,
+ type = SessionType},
case httpc_request:send(Address, Session, Request) of
ok ->
- ?hcri("first request sent", []),
TmpState = State#state{request = Request,
session = Session,
mfa = init_mfa(Request, State),
- status_line =
- init_status_line(Request),
+ status_line = init_status_line(Request),
headers = undefined,
body = undefined,
status = new},
@@ -947,8 +829,7 @@ connect_and_send_first_request(Address, Request, #state{options = Options} = Sta
self() ! {init_error, error_sending,
httpc_response:error(Request, Reason)},
{ok, State#state{request = Request,
- session =
- #session{socket = Socket}}}
+ session = #session{socket = Socket}}}
end;
{error, Reason} ->
self() ! {init_error, error_connecting,
@@ -990,12 +871,6 @@ handler_info(#state{request = Request,
options = _Options,
timers = _Timers} = _State) ->
- ?hcrt("handler info", [{request, Request},
- {session, Session},
- {pipeline, Pipeline},
- {keep_alive, KeepAlive},
- {status, Status}]),
-
%% Info about the current request
RequestInfo =
case Request of
@@ -1006,8 +881,6 @@ handler_info(#state{request = Request,
[{id, Id}, {started, ReqStarted}]
end,
- ?hcrt("handler info", [{request_info, RequestInfo}]),
-
%% Info about the current session/socket
SessionType = Session#session.type,
QueueLen = case SessionType of
@@ -1020,22 +893,12 @@ handler_info(#state{request = Request,
Socket = Session#session.socket,
SocketType = Session#session.socket_type,
- ?hcrt("handler info", [{session_type, SessionType},
- {queue_length, QueueLen},
- {scheme, Scheme},
- {socket, Socket}]),
-
SocketOpts = http_transport:getopts(SocketType, Socket),
SocketStats = http_transport:getstat(SocketType, Socket),
Remote = http_transport:peername(SocketType, Socket),
Local = http_transport:sockname(SocketType, Socket),
- ?hcrt("handler info", [{remote, Remote},
- {local, Local},
- {socket_opts, SocketOpts},
- {socket_stats, SocketStats}]),
-
SocketInfo = [{remote, Remote},
{local, Local},
{socket_opts, SocketOpts},
@@ -1055,7 +918,6 @@ handler_info(#state{request = Request,
handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
State = #state{request = Request}) ->
- ?hcrt("handle_http_msg", [{headers, Headers}]),
case Headers#http_response_h.'content-type' of
"multipart/byteranges" ++ _Param ->
exit({not_yet_implemented, multypart_byteranges});
@@ -1069,15 +931,12 @@ handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
end;
handle_http_msg({ChunkedHeaders, Body},
#state{status_line = {_, Code, _}, headers = Headers} = State) ->
- ?hcrt("handle_http_msg",
- [{chunked_headers, ChunkedHeaders}, {headers, Headers}]),
NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders),
{_, NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{headers = NewHeaders,
body = NewBody,
request = NewRequest});
handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
- ?hcrt("handle_http_msg", [{code, Code}]),
{_, NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{body = NewBody, request = NewRequest}).
@@ -1092,41 +951,28 @@ handle_http_body(_, #state{status = {ssl_tunnel, Request},
{stop, normal, NewState};
handle_http_body(<<>>, #state{status_line = {_,304, _}} = State) ->
- ?hcrt("handle_http_body - 304", []),
handle_response(State#state{body = <<>>});
handle_http_body(<<>>, #state{status_line = {_,204, _}} = State) ->
- ?hcrt("handle_http_body - 204", []),
handle_response(State#state{body = <<>>});
handle_http_body(<<>>, #state{request = #request{method = head}} = State) ->
- ?hcrt("handle_http_body - head", []),
handle_response(State#state{body = <<>>});
handle_http_body(Body, #state{headers = Headers,
max_body_size = MaxBodySize,
status_line = {_,Code, _},
request = Request} = State) ->
- ?hcrt("handle_http_body",
- [{max_body_size, MaxBodySize}, {headers, Headers}, {code, Code}]),
TransferEnc = Headers#http_response_h.'transfer-encoding',
case case_insensitive_header(TransferEnc) of
"chunked" ->
- ?hcrt("handle_http_body - chunked", []),
try http_chunk:decode(Body, State#state.max_body_size,
State#state.max_header_size) of
{Module, Function, Args} ->
- ?hcrt("handle_http_body - new mfa",
- [{module, Module},
- {function, Function},
- {args, Args}]),
NewState = next_body_chunk(State, Code),
{noreply, NewState#state{mfa =
{Module, Function, Args}}};
{ok, {ChunkedHeaders, NewBody}} ->
- ?hcrt("handle_http_body - new body",
- [{chunked_headers, ChunkedHeaders},
- {new_body, NewBody}]),
NewHeaders = http_chunk:handle_headers(Headers,
ChunkedHeaders),
case Body of
@@ -1148,7 +994,6 @@ handle_http_body(Body, #state{headers = Headers,
{stop, normal, NewState}
end;
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
@@ -1172,7 +1017,6 @@ handle_http_body(Body, #state{headers = Headers,
{stop, normal, NewState}
end;
Encoding when is_list(Encoding) ->
- ?hcrt("handle_http_body - other", [{encoding, Encoding}]),
NewState = answer_request(Request,
httpc_response:error(Request,
unknown_encoding),
@@ -1193,18 +1037,10 @@ handle_response(#state{request = Request,
options = Options,
profile_name = ProfileName} = State)
when Status =/= new ->
-
- ?hcrd("handle response", [{profile, ProfileName},
- {status, Status},
- {request, Request},
- {session, Session},
- {status_line, StatusLine}]),
-
handle_cookies(Headers, Request, Options, ProfileName),
case httpc_response:result({StatusLine, Headers, Body}, Request) of
%% 100-continue
continue ->
- ?hcrd("handle response - continue", []),
%% Send request body
{_, RequestBody} = Request#request.content,
send_raw(Session, RequestBody),
@@ -1221,7 +1057,6 @@ handle_response(#state{request = Request,
%% Ignore unexpected 100-continue response and receive the
%% actual response that the server will send right away.
{ignore, Data} ->
- ?hcrd("handle response - ignore", [{data, Data}]),
Relaxed = (Request#request.settings)#http_options.relaxed,
MFA = {httpc_response, parse,
[State#state.max_header_size, Relaxed]},
@@ -1235,23 +1070,17 @@ handle_response(#state{request = Request,
%% obsolete and the manager will create a new request
%% with the same id as the current.
{redirect, NewRequest, Data} ->
- ?hcrt("handle response - redirect",
- [{new_request, NewRequest}, {data, Data}]),
ok = httpc_manager:redirect_request(NewRequest, ProfileName),
handle_queue(State#state{request = undefined}, Data);
{retry, TimeNewRequest, Data} ->
- ?hcrt("handle response - retry",
- [{time_new_request, TimeNewRequest}, {data, Data}]),
ok = httpc_manager:retry_request(TimeNewRequest, ProfileName),
handle_queue(State#state{request = undefined}, Data);
{ok, Msg, Data} ->
- ?hcrd("handle response - ok", []),
stream_remaining_body(Body, Request, StatusLine),
end_stream(StatusLine, Request),
NewState = maybe_send_answer(Request, Msg, State),
handle_queue(NewState, Data);
{stop, Msg} ->
- ?hcrd("handle response - stop", [{msg, Msg}]),
end_stream(StatusLine, Request),
NewState = maybe_send_answer(Request, Msg, State),
{stop, normal, NewState}
@@ -1286,28 +1115,19 @@ handle_pipeline(#state{status = pipeline,
profile_name = ProfileName,
options = #options{pipeline_timeout = TimeOut}} = State,
Data) ->
-
- ?hcrd("handle pipeline", [{profile, ProfileName},
- {session, Session},
- {timeout, TimeOut}]),
-
case queue:out(State#state.pipeline) of
{empty, _} ->
- ?hcrd("pipeline queue empty", []),
handle_empty_queue(Session, ProfileName, TimeOut, State);
{{value, NextRequest}, Pipeline} ->
- ?hcrd("pipeline queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
- ?hcrv("next request had been cancelled", []),
%% See comment for handle_cast({cancel, RequestId})
{stop, normal,
State#state{request =
NextRequest#request{from = answer_sent},
pipeline = Pipeline}};
false ->
- ?hcrv("next request", [{request, NextRequest}]),
NewSession =
Session#session{queue_length =
%% Queue + current
@@ -1324,25 +1144,16 @@ handle_keep_alive_queue(#state{status = keep_alive,
options = #options{keep_alive_timeout = TimeOut,
proxy = Proxy}} = State,
Data) ->
-
- ?hcrd("handle keep_alive", [{profile, ProfileName},
- {session, Session},
- {timeout, TimeOut}]),
-
case queue:out(State#state.keep_alive) of
{empty, _} ->
- ?hcrd("keep_alive queue empty", []),
handle_empty_queue(Session, ProfileName, TimeOut, State);
{{value, NextRequest}, KeepAlive} ->
- ?hcrd("keep_alive queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
- ?hcrv("next request has already been canceled", []),
handle_keep_alive_queue(
State#state{keep_alive = KeepAlive}, Data);
false ->
- ?hcrv("next request", [{request, NextRequest}]),
#request{address = Addr} = NextRequest,
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, NextRequest) of
@@ -1355,7 +1166,6 @@ handle_keep_alive_queue(#state{status = keep_alive,
end
end
end.
-
handle_empty_queue(Session, ProfileName, TimeOut, State) ->
%% The server may choose too terminate an idle pipline| keep_alive session
%% in this case we want to receive the close message
@@ -1391,7 +1201,6 @@ init_wait_for_response_state(Request, State) ->
status_line = undefined,
headers = undefined,
body = undefined}.
-
gather_data(<<>>, Session, State) ->
activate_once(Session),
{noreply, State};
@@ -1422,10 +1231,6 @@ activate_request_timeout(
State;
_ ->
ReqId = Request#request.id,
- ?hcrt("activate request timer",
- [{request_id, ReqId},
- {time_consumed, t() - Request#request.started},
- {timeout, Timeout}]),
Msg = {timeout, ReqId},
Ref = erlang:send_after(Timeout, self(), Msg),
Request2 = Request#request{timer = Ref},
@@ -1468,10 +1273,6 @@ try_to_enable_pipeline_or_keep_alive(
status_line = {Version, _, _},
headers = Headers,
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
true ->
@@ -1496,7 +1297,6 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
#state{session = Session,
timers = Timers,
profile_name = ProfileName} = State) ->
- ?hcrt("answer request", [{request, Request}, {msg, Msg}]),
httpc_response:send(From, Msg),
RequestTimers = Timers#timers.request_timers,
TimerRef =
@@ -1643,42 +1443,32 @@ socket_type(#request{scheme = http}) ->
ip_comm;
socket_type(#request{scheme = https, settings = Settings}) ->
Settings#http_options.ssl.
-%% socket_type(http) ->
-%% ip_comm;
-%% socket_type(https) ->
-%% {ssl1, []}. %% Dummy value ok for ex setopts that does not use this value
start_stream({_Version, _Code, _ReasonPhrase}, _Headers,
#request{stream = none} = Request) ->
- ?hcrt("start stream - none", []),
{ok, Request};
start_stream({_Version, Code, _ReasonPhrase}, Headers,
#request{stream = self} = Request)
when ?IS_STREAMED(Code) ->
- ?hcrt("start stream - self", [{code, Code}]),
Msg = httpc_response:stream_start(Headers, Request, ignore),
httpc_response:send(Request#request.from, Msg),
{ok, Request};
start_stream({_Version, Code, _ReasonPhrase}, Headers,
#request{stream = {self, once}} = Request)
when ?IS_STREAMED(Code) ->
- ?hcrt("start stream - self:once", [{code, Code}]),
Msg = httpc_response:stream_start(Headers, Request, self()),
httpc_response:send(Request#request.from, Msg),
{ok, Request};
start_stream({_Version, Code, _ReasonPhrase}, _Headers,
#request{stream = Filename} = Request)
when ?IS_STREAMED(Code) andalso is_list(Filename) ->
- ?hcrt("start stream", [{code, Code}, {filename, Filename}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
{ok, Fd} ->
- ?hcri("start stream - file open ok", [{fd, Fd}]),
{ok, Request#request{stream = Fd}};
{error, Reason} ->
exit({stream_to_file_failed, Reason})
end;
start_stream(_StatusLine, _Headers, Request) ->
- ?hcrt("start stream - no op", []),
{ok, Request}.
stream_remaining_body(<<>>, _, _) ->
@@ -1689,16 +1479,12 @@ stream_remaining_body(Body, Request, {_, Code, _}) ->
%% Note the end stream message is handled by httpc_response and will
%% be sent by answer_request
end_stream(_, #request{stream = none}) ->
- ?hcrt("end stream - none", []),
ok;
end_stream(_, #request{stream = self}) ->
- ?hcrt("end stream - self", []),
ok;
end_stream(_, #request{stream = {self, once}}) ->
- ?hcrt("end stream - self:once", []),
ok;
end_stream({_,200,_}, #request{stream = Fd}) ->
- ?hcrt("end stream - 200", [{stream, Fd}]),
case file:close(Fd) of
ok ->
ok;
@@ -1706,15 +1492,13 @@ end_stream({_,200,_}, #request{stream = Fd}) ->
file:close(Fd)
end;
end_stream({_,206,_}, #request{stream = Fd}) ->
- ?hcrt("end stream - 206", [{stream, Fd}]),
case file:close(Fd) of
ok ->
ok;
{error, enospc} -> % Could be due to delayed_write
file:close(Fd)
end;
-end_stream(SL, R) ->
- ?hcrt("end stream", [{status_line, SL}, {request, R}]),
+end_stream(_, _) ->
ok.
@@ -1743,11 +1527,8 @@ handle_verbose(trace) ->
handle_verbose(_) ->
ok.
-
-
send_raw(#session{socket = Socket, socket_type = SocketType},
{ProcessBody, Acc}) when is_function(ProcessBody, 1) ->
- ?hcrt("send raw", [{acc, Acc}]),
send_raw(SocketType, Socket, ProcessBody, Acc);
send_raw(#session{socket = Socket, socket_type = SocketType}, Body) ->
http_transport:send(SocketType, Socket, Body).
@@ -1758,7 +1539,6 @@ send_raw(SocketType, Socket, ProcessBody, Acc) ->
ok;
{ok, Data, NewAcc} ->
DataBin = iolist_to_binary(Data),
- ?hcrd("send", [{data, DataBin}]),
case http_transport:send(SocketType, Socket, DataBin) of
ok ->
send_raw(SocketType, Socket, ProcessBody, NewAcc);
@@ -1790,14 +1570,16 @@ tls_tunnel(Address, Request, #state{session = #session{socket = Socket,
tls_tunnel_request(#request{headers = Headers,
settings = Options,
+ id = RequestId,
+ from = From,
address = {Host, Port}= Adress,
ipv6_host_with_brackets = IPV6}) ->
URI = Host ++":" ++ integer_to_list(Port),
#request{
- id = make_ref(),
- from = self(),
+ id = RequestId,
+ from = From,
scheme = http, %% Use tcp-first and then upgrade!
address = Adress,
path = URI,
@@ -1887,10 +1669,13 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
httpc_manager:update_session(ProfileName, SessionId, Pos, Value)
end
catch
- error:undef -> % This could happen during code upgrade
+ error:undef -> %% This could happen during code upgrade
Session2 = erlang:setelement(Pos, Session, Value),
insert_session(Session2, ProfileName);
- T:E ->
+ error:badarg ->
+ exit(normal); %% Manager has been shutdown
+ T:E ->
+ %% Unexpected this must be an error!
Stacktrace = erlang:get_stacktrace(),
error_logger:error_msg("Failed updating session: "
"~n ProfileName: ~p"
@@ -1919,16 +1704,3 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
end.
-%% ---------------------------------------------------------------------
-
-call(Msg, Pid) ->
- Timeout = infinity,
- call(Msg, Pid, Timeout).
-call(Msg, Pid, Timeout) ->
- gen_server:call(Pid, Msg, Timeout).
-
-cast(Msg, Pid) ->
- gen_server:cast(Pid, Msg).
-
-t() ->
- http_util:timestamp().
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index f4e69cc1fa..5f8c70f28d 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -43,32 +43,32 @@
%%% HTTP Client per request settings
-record(http_options,
{
- %% string() - "HTTP/1.1" | "HTTP/1.0" | "HTTP/0.9"
- version,
+ %% "HTTP/1.1" | "HTTP/1.0" | "HTTP/0.9"
+ version :: 'undefined' | string(),
- %% integer() | infinity - ms before a request times out
- timeout = ?HTTP_REQUEST_TIMEOUT,
+ %% ms before a request times out
+ timeout = ?HTTP_REQUEST_TIMEOUT :: timeout(),
- %% bool() - true if auto redirect on 30x response
- autoredirect = true,
+ %% true if auto redirect on 30x response
+ autoredirect = true :: boolean(),
%% ssl socket options
- ssl = [],
+ ssl = [],
%% {User, Password} = {string(), string()}
proxy_auth,
- %% bool() - true if not strictly std compliant
- relaxed = false,
+ %% true if not strictly std compliant
+ relaxed = false :: boolean(),
%% integer() - ms before a connect times out
- connect_timeout = ?HTTP_REQUEST_CTIMEOUT,
-
- %% bool() - Use %-encoding rfc 2396
- url_encode
+ connect_timeout = ?HTTP_REQUEST_CTIMEOUT :: timeout(),
+ %% Use %-encoding rfc 2396
+ url_encode :: 'undefined' | boolean()
}
).
+-type http_options() :: #http_options{}.
%%% HTTP Client per profile setting.
-record(options,
@@ -82,18 +82,19 @@
keep_alive_timeout = ?HTTP_KEEP_ALIVE_TIMEOUT, % Used when pipeline_timeout = 0
max_sessions = ?HTTP_MAX_TCP_SESSIONS,
cookies = disabled, % enabled | disabled | verify
- verbose = false,
+ verbose = false, % boolean(),
ipfamily = inet, % inet | inet6 | inet6fb4
ip = default, % specify local interface
port = default, % specify local port
socket_opts = [] % other socket options
}
).
+-type options() :: #options{}.
%%% All data associated to a specific HTTP request
-record(request,
{
- id, % ref() - Request Id
+ id :: 'undefined' | reference(), % Request Id
from, % pid() - Caller
redircount = 0,% Number of redirects made for this request
scheme, % http | https
@@ -103,7 +104,7 @@
method, % atom() - HTTP request Method
headers, % #http_request_h{}
content, % {ContentType, Body} - Current HTTP request
- settings, % #http_options{} - User defined settings
+ settings :: http_options(), % User defined settings
abs_uri, % string() ex: "http://www.erlang.org"
userinfo, % string() - optinal "<userinfo>@<host>:<port>"
stream, % boolean() - stream async reply?
@@ -112,20 +113,19 @@
% for testing purposes.
started, % integer() > 0 - When we started processing the
% request
- timer, % undefined | ref()
+ timer :: undefined | reference(),
socket_opts, % undefined | [socket_option()]
ipv6_host_with_brackets % boolean()
}
- ).
-
+ ).
+-type request() :: #request{}.
-record(session,
{
%% {{Host, Port}, HandlerPid}
id,
- %% true | false
- client_close,
+ client_close :: 'undefined' | boolean(),
%% http (HTTP/TCP) | https (HTTP/SSL/TCP)
scheme,
@@ -140,14 +140,13 @@
queue_length = 1,
%% pipeline | keep_alive (wait for response before sending new request)
- type,
+ type :: 'undefined' | 'pipeline' | 'keep_alive',
- %% true | false
%% This will be true, when a response has been received for
%% the first request. See type above.
- available = false
+ available = false :: boolean()
}).
-
+-type session() :: #session{}.
-record(http_cookie,
{
@@ -162,7 +161,7 @@
secure = false,
version = "0"
}).
-
+-type http_cookie() :: #http_cookie{}.
%% -record(parsed_uri,
%% {
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 4cb6f005ad..a63864493f 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -137,7 +137,7 @@ redirect_request(Request, ProfileName) ->
%%--------------------------------------------------------------------
%% Function: cancel_request(RequestId, ProfileName) -> ok
-%% RequestId - ref()
+%% RequestId - reference()
%% ProfileName = atom()
%%
%% Description: Cancels the request with <RequestId>.
@@ -148,7 +148,7 @@ cancel_request(RequestId, ProfileName) ->
%%--------------------------------------------------------------------
%% Function: request_done(RequestId, ProfileName) -> ok
-%% RequestId - ref()
+%% RequestId - reference()
%% ProfileName = atom()
%%
%% Description: Inform tha manager that a request has been completed.
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index e8d020c165..89872a3831 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -88,9 +88,11 @@ send(SendAddr, Socket, SocketType,
case Address of
SendAddr ->
{TmpHdrs2, Path ++ Query};
- _Proxy ->
+ _Proxy when SocketType == ip_comm ->
TmpHdrs3 = handle_proxy(HttpOptions, TmpHdrs2),
- {TmpHdrs3, AbsUri}
+ {TmpHdrs3, AbsUri};
+ _ ->
+ {TmpHdrs2, Path ++ Query}
end,
FinalHeaders =
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 91256fa6a2..5fbceb8ad0 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -110,27 +110,30 @@ result(Response = {{_, 300, _}, _, _},
redirect(Response, Request);
result(Response = {{_, Code, _}, _, _},
+ Request = #request{settings =
+ #http_options{autoredirect = true},
+ method = post}) when (Code =:= 301) orelse
+ (Code =:= 302) orelse
+ (Code =:= 303) ->
+ redirect(Response, Request#request{method = get});
+result(Response = {{_, Code, _}, _, _},
+ Request = #request{settings =
+ #http_options{autoredirect = true},
+ method = post}) when (Code =:= 307) ->
+ redirect(Response, Request);
+result(Response = {{_, Code, _}, _, _},
Request = #request{settings =
#http_options{autoredirect = true},
- method = head}) when (Code =:= 301) orelse
+ method = Method}) when (Code =:= 301) orelse
(Code =:= 302) orelse
(Code =:= 303) orelse
(Code =:= 307) ->
- redirect(Response, Request);
-result(Response = {{_, Code, _}, _, _},
- Request = #request{settings =
- #http_options{autoredirect = true},
- method = get}) when (Code =:= 301) orelse
- (Code =:= 302) orelse
- (Code =:= 303) orelse
- (Code =:= 307) ->
- redirect(Response, Request);
-result(Response = {{_, 303, _}, _, _},
- Request = #request{settings =
- #http_options{autoredirect = true},
- method = post}) ->
- redirect(Response, Request#request{method = get});
-
+ case lists:member(Method, [get, head, options, trace]) of
+ true ->
+ redirect(Response, Request);
+ false ->
+ transparent(Response, Request)
+ end;
result(Response = {{_,503,_}, _, _}, Request) ->
status_service_unavailable(Response, Request);
@@ -359,8 +362,9 @@ redirect(Response = {StatusLine, Headers, Body}, Request) ->
{ok, error(Request, Reason), Data};
%% Automatic redirection
{ok, {Scheme, _, Host, Port, Path, Query}} ->
+ HostPort = http_request:normalize_host(Scheme, Host, Port),
NewHeaders =
- (Request#request.headers)#http_request_h{host = Host},
+ (Request#request.headers)#http_request_h{host = HostPort},
NewRequest =
Request#request{redircount =
Request#request.redircount+1,
diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl
index ae92b5df8f..ca1dad07cd 100644
--- a/lib/inets/src/http_lib/http_internal.hrl
+++ b/lib/inets/src/http_lib/http_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@
'last-modified',
other=[] % list() - Key/Value list with other headers
}).
-
+-type http_response_h() :: #http_response_h{}.
%%% Request headers
-record(http_request_h,{
@@ -118,5 +118,6 @@
'last-modified',
other=[] % list() - Key/Value list with other headers
}).
+-type http_request_h() :: #http_request_h{}.
-endif. % -ifdef(http_internal_hrl).
diff --git a/lib/inets/src/http_lib/http_request.erl b/lib/inets/src/http_lib/http_request.erl
index c77b616f0d..4c50edb5ef 100644
--- a/lib/inets/src/http_lib/http_request.erl
+++ b/lib/inets/src/http_lib/http_request.erl
@@ -22,7 +22,7 @@
-include("http_internal.hrl").
--export([headers/2, http_headers/1, is_absolut_uri/1, key_value/1]).
+-export([headers/2, http_headers/1, is_absolut_uri/1, key_value/1, normalize_host/3]).
key_value(KeyValueStr) ->
@@ -85,6 +85,22 @@ is_absolut_uri("https://" ++ _) ->
is_absolut_uri(_) ->
false.
+%%-------------------------------------------------------------------------
+%% normalize_host(Scheme, Host, Port) -> string()
+%% Scheme - http | https
+%% Host - string()
+%% Port - integer()
+%%
+%% Description: returns a normalized Host header value, with the port
+%% number omitted for well-known ports
+%%-------------------------------------------------------------------------
+normalize_host(https, Host, 443 = _Port) ->
+ Host;
+normalize_host(http, Host, 80 = _Port) ->
+ Host;
+normalize_host(_Scheme, Host, Port) ->
+ Host ++ ":" ++ integer_to_list(Port).
+
%%%========================================================================
%%% Internal functions
%%%========================================================================
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index e5182ca23c..9e54f2b2c5 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -395,7 +395,8 @@ validate_properties(Properties) ->
%% That is, if property A depends on property B.
%% The only sunch preperty at this time is bind_address that depends
%% on ipfamily.
-validate_properties2(Properties) ->
+validate_properties2(Properties0) ->
+ Properties = fix_ipfamily(Properties0),
case proplists:get_value(bind_address, Properties) of
undefined ->
case proplists:get_value(sock_type, Properties, ip_comm) of
@@ -422,6 +423,15 @@ validate_properties2(Properties) ->
end
end.
+fix_ipfamily(Properties) ->
+ case proplists:get_value(ipfamily, Properties) of
+ undefined ->
+ Properties;
+ IpFamily ->
+ NewProps = proplists:delete(ipfamily, Properties),
+ [{ipfamily, validate_ipfamily(IpFamily)} | NewProps]
+ end.
+
add_inet_defaults(Properties) ->
case proplists:get_value(ipfamily, Properties) of
undefined ->
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl
index 424d269859..c893b10dca 100644
--- a/lib/inets/src/http_server/httpd_example.erl
+++ b/lib/inets/src/http_server/httpd_example.erl
@@ -20,7 +20,7 @@
%%
-module(httpd_example).
-export([print/1]).
--export([get/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2]).
+-export([get/2, put/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2]).
-export([newformat/3]).
%% These are used by the inets test-suite
@@ -59,6 +59,11 @@ get(_Env,[]) ->
get(Env,Input) ->
default(Env,Input).
+put(Env,{Input,_Body}) ->
+ default(Env,Input);
+put(Env,Input) ->
+ default(Env,Input).
+
get_bin(_Env,_Input) ->
[list_to_binary(header()),
list_to_binary(top("GET Example")),
@@ -94,7 +99,7 @@ default(Env,Input) ->
io_lib:format("~p",[httpd:parse_query(Input)]),"\n",
footer()].
-peer(Env, Input) ->
+peer(Env, _Input) ->
Header =
case proplists:get_value(peer_cert, Env) of
undefined ->
@@ -161,7 +166,7 @@ sleep(T) -> receive after T -> ok end.
%% ------------------------------------------------------
-chunk_timeout(SessionID, _, StrInt) ->
+chunk_timeout(SessionID, _, _StrInt) ->
mod_esi:deliver(SessionID, "Tranfer-Encoding:chunked/html\r\n\r\n"),
mod_esi:deliver(SessionID, top("Test chunk encoding timeout")),
timer:sleep(20000),
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index 071fa94ef6..538d52b98d 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,18 +37,19 @@
-include("httpd_internal.hrl").
-define(HANDSHAKE_TIMEOUT, 5000).
+
-record(state, {mod, %% #mod{}
manager, %% pid()
status, %% accept | busy | blocked
mfa, %% {Module, Function, Args}
max_keep_alive_request = infinity, %% integer() | infinity
- response_sent = false, %% true | false
- timeout, %% infinity | integer() > 0
- timer, %% ref() - Request timer
- headers, %% #http_request_h{}
+ response_sent = false :: boolean(),
+ timeout, %% infinity | integer() > 0
+ timer :: 'undefined' | reference(), % Request timer
+ headers, %% #http_request_h{}
body, %% binary()
data, %% The total data received in bits, checked after 10s
- byte_limit %% Bit limit per second before kick out
+ byte_limit %% Bit limit per second before kick out
}).
%%====================================================================
@@ -240,9 +241,9 @@ handle_info({tcp_closed, _}, State) ->
handle_info({ssl_closed, _}, State) ->
{stop, normal, State};
handle_info({tcp_error, _, _} = Reason, State) ->
- {stop, Reason, State};
+ {stop, {shutdown, Reason}, State};
handle_info({ssl_error, _, _} = Reason, State) ->
- {stop, Reason, State};
+ {stop, {shutdown, Reason}, State};
%% Timeouts
handle_info(timeout, #state{mfa = {_, parse, _}} = State) ->
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index 1374b7e85e..effa273e92 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_auth_server.erl b/lib/inets/src/http_server/mod_auth_server.erl
index 93d8145821..90d9ee34b1 100644
--- a/lib/inets/src/http_server/mod_auth_server.erl
+++ b/lib/inets/src/http_server/mod_auth_server.erl
@@ -128,7 +128,7 @@ list_group_members(Addr, Port, Dir, Group, Password) ->
list_group_members(Addr, Port, ?DEFAULT_PROFILE, Dir, Group, Password).
list_group_members(Addr, Port, Profile, Dir, Group, Password) ->
Name = make_name(Addr, Port, Profile),
- Req = {list_group_members, Addr, Port, Dir, Group, Password},
+ Req = {list_group_members, Addr, Port, Profile, Dir, Group, Password},
call(Name, Req).
delete_group(Addr, Port, Dir, GroupName, Password) ->
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 2800250727..b21af1418c 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -241,7 +241,7 @@ alias_match_str(Alias, eval_script_alias) ->
%%------------------------ Erl mechanism --------------------------------
erl(#mod{method = Method} = ModData, ESIBody, Modules)
- when (Method =:= "GET") orelse (Method =:= "HEAD") ->
+ when (Method =:= "GET") orelse (Method =:= "HEAD") orelse (Method =:= "DELETE") ->
?hdrt("erl", [{method, Method}]),
case httpd_util:split(ESIBody,":|%3A|/",2) of
{ok, [ModuleName, FuncAndInput]} ->
@@ -264,35 +264,32 @@ erl(#mod{method = Method} = ModData, ESIBody, Modules)
{proceed, [{status,{400, none, BadRequest}} | ModData#mod.data]}
end;
-erl(#mod{request_uri = ReqUri,
- method = "PUT",
- http_version = Version,
- data = Data}, _ESIBody, _Modules) ->
- ?hdrt("erl", [{method, put}]),
- {proceed, [{status,{501,{"PUT", ReqUri, Version},
- ?NICE("Erl mechanism doesn't support method PUT")}}|
- Data]};
-
-erl(#mod{request_uri = ReqUri,
- method = "DELETE",
- http_version = Version,
- data = Data}, _ESIBody, _Modules) ->
- ?hdrt("erl", [{method, delete}]),
- {proceed,[{status,{501,{"DELETE", ReqUri, Version},
- ?NICE("Erl mechanism doesn't support method DELETE")}}|
- Data]};
-
-erl(#mod{request_uri = ReqUri,
- method = "PATCH",
- http_version = Version,
- data = Data}, _ESIBody, _Modules) ->
- ?hdrt("erl", [{method, patch}]),
- {proceed, [{status,{501,{"PATCH", ReqUri, Version},
- ?NICE("Erl mechanism doesn't support method PATCH")}}|
- Data]};
+erl(#mod{method = "PUT", entity_body = Body} = ModData,
+ ESIBody, Modules) ->
+ case httpd_util:split(ESIBody,":|%3A|/",2) of
+ {ok, [ModuleName, FuncAndInput]} ->
+ case httpd_util:split(FuncAndInput,"[\?/]",2) of
+ {ok, [FunctionName, Input]} ->
+ generate_webpage(ModData, ESIBody, Modules,
+ list_to_atom(ModuleName),
+ FunctionName, {Input,Body},
+ [{entity_body, Body} |
+ script_elements(FuncAndInput, Input)]);
+ {ok, [FunctionName]} ->
+ generate_webpage(ModData, ESIBody, Modules,
+ list_to_atom(ModuleName),
+ FunctionName, {undefined,Body},
+ [{entity_body, Body} |
+ script_elements(FuncAndInput, "")]);
+ {ok, BadRequest} ->
+ {proceed,[{status,{400,none, BadRequest}} |
+ ModData#mod.data]}
+ end;
+ {ok, BadRequest} ->
+ {proceed, [{status,{400, none, BadRequest}} | ModData#mod.data]}
+ end;
-erl(#mod{method = "POST",
- entity_body = Body} = ModData, ESIBody, Modules) ->
+erl(#mod{method = "POST", entity_body = Body} = ModData, ESIBody, Modules) ->
?hdrt("erl", [{method, post}]),
case httpd_util:split(ESIBody,":|%3A|/",2) of
{ok,[ModuleName, Function]} ->
@@ -301,7 +298,16 @@ erl(#mod{method = "POST",
Function, Body, [{entity_body, Body}]);
{ok, BadRequest} ->
{proceed,[{status, {400, none, BadRequest}} | ModData#mod.data]}
- end.
+ end;
+
+erl(#mod{request_uri = ReqUri,
+ method = "PATCH",
+ http_version = Version,
+ data = Data}, _ESIBody, _Modules) ->
+ ?hdrt("erl", [{method, patch}]),
+ {proceed, [{status,{501,{"PATCH", ReqUri, Version},
+ ?NICE("Erl mechanism doesn't support method PATCH")}}|
+ Data]}.
generate_webpage(ModData, ESIBody, [all], Module, FunctionName,
Input, ScriptElements) ->
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 3a31daeb20..f9ad8709d9 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,14 @@
%% %CopyrightEnd%
{"%VSN%",
[
+ {<<"6.2.4">>, [{load_module, httpd_request_handler,
+ soft_purge, soft_purge, []}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
],
[
+ {<<"6.2.4">>, [{load_module, httpd_request_handler,
+ soft_purge, soft_purge, []}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
]
diff --git a/lib/inets/src/inets_app/inets_lib.erl b/lib/inets/src/inets_app/inets_lib.erl
index 8993be29e4..3fae376a9f 100644
--- a/lib/inets/src/inets_app/inets_lib.erl
+++ b/lib/inets/src/inets_app/inets_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl
index e2dec0c42a..1a79cb58ed 100644
--- a/lib/inets/test/ftp_SUITE.erl
+++ b/lib/inets/test/ftp_SUITE.erl
@@ -93,8 +93,11 @@ ftp_tests()->
append_chunk,
recv,
recv_3,
- recv_bin,
+ recv_bin,
+ recv_bin_twice,
recv_chunk,
+ recv_chunk_twice,
+ recv_chunk_three_times,
type,
quote,
error_elogin,
@@ -533,15 +536,19 @@ append_chunk(Config0) ->
recv() ->
[{doc, "Receive a file using recv/2"}].
recv(Config0) ->
- File = "f_dst.txt",
+ File1 = "f_dst1.txt",
+ File2 = "f_dst2.txt",
SrcDir = "a_dir",
- Contents = <<"ftp_SUITE test ...">>,
- Config = set_state([reset, {mkfile,[SrcDir,File],Contents}], Config0),
+ Contents1 = <<"1 ftp_SUITE test ...">>,
+ Contents2 = <<"2 ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,[SrcDir,File1],Contents1}, {mkfile,[SrcDir,File2],Contents2}], Config0),
Pid = proplists:get_value(ftp, Config),
ok = ftp:cd(Pid, id2ftp(SrcDir,Config)),
ok = ftp:lcd(Pid, id2ftp("",Config)),
- ok = ftp:recv(Pid, File),
- chk_file(File, Contents, Config),
+ ok = ftp:recv(Pid, File1),
+ chk_file(File1, Contents1, Config),
+ ok = ftp:recv(Pid, File2),
+ chk_file(File2, Contents2, Config),
{error,epath} = ftp:recv(Pid, "non_existing_file"),
ok.
@@ -572,6 +579,25 @@ recv_bin(Config0) ->
ok.
%%-------------------------------------------------------------------------
+recv_bin_twice() ->
+ [{doc, "Receive two files as a binaries."}].
+recv_bin_twice(Config0) ->
+ File1 = "f_dst1.txt",
+ File2 = "f_dst2.txt",
+ Contents1 = <<"1 ftp_SUITE test ...">>,
+ Contents2 = <<"2 ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
+ ct:log("First transfer",[]),
+ Pid = proplists:get_value(ftp, Config),
+ {ok,Received1} = ftp:recv_bin(Pid, id2ftp(File1,Config)),
+ find_diff(Received1, Contents1),
+ ct:log("Second transfer",[]),
+ {ok,Received2} = ftp:recv_bin(Pid, id2ftp(File2,Config)),
+ find_diff(Received2, Contents2),
+ ct:log("Transfers ready!",[]),
+ {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
+ ok.
+%%-------------------------------------------------------------------------
recv_chunk() ->
[{doc, "Receive a file using chunk-wise."}].
recv_chunk(Config0) ->
@@ -584,13 +610,74 @@ recv_chunk(Config0) ->
{ok, ReceivedContents, _Ncunks} = recv_chunk(Pid, <<>>),
find_diff(ReceivedContents, Contents).
+recv_chunk_twice() ->
+ [{doc, "Receive two files using chunk-wise."}].
+recv_chunk_twice(Config0) ->
+ File1 = "big_file1.txt",
+ File2 = "big_file2.txt",
+ Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
+ Contents2 = crypto:strong_rand_bytes(1200),
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
+ {ok, ReceivedContents1, _Ncunks1} = recv_chunk(Pid, <<>>),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
+ {ok, ReceivedContents2, _Ncunks2} = recv_chunk(Pid, <<>>),
+ find_diff(ReceivedContents1, Contents1),
+ find_diff(ReceivedContents2, Contents2).
+
+recv_chunk_three_times() ->
+ [{doc, "Receive two files using chunk-wise."},
+ {timetrap,{seconds,120}}].
+recv_chunk_three_times(Config0) ->
+ File1 = "big_file1.txt",
+ File2 = "big_file2.txt",
+ File3 = "big_file3.txt",
+ Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
+ Contents2 = crypto:strong_rand_bytes(1200),
+ Contents3 = list_to_binary( lists:duplicate(1000, lists:seq(255,0,-1)) ),
+
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}, {mkfile,File3,Contents3}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>),
+
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
+ {ok, ReceivedContents1, Nchunks1} = recv_chunk(Pid, <<>>),
+
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
+ {ok, ReceivedContents2, _Nchunks2} = recv_chunk(Pid, <<>>),
+
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File3,Config)),
+ {ok, ReceivedContents3, _Nchunks3} = recv_chunk(Pid, <<>>, 10000, 0, Nchunks1),
+
+ find_diff(ReceivedContents1, Contents1),
+ find_diff(ReceivedContents2, Contents2),
+ find_diff(ReceivedContents3, Contents3).
+
+
+
recv_chunk(Pid, Acc) ->
- recv_chunk(Pid, Acc, 0).
+ recv_chunk(Pid, Acc, 0, 0, undefined).
+
+
+
+%% ExpectNchunks :: integer() | undefined
+recv_chunk(Pid, Acc, DelayMilliSec, N, ExpectNchunks) when N+1 < ExpectNchunks ->
+ %% for all I in integer(), I < undefined
+ recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks);
+
+recv_chunk(Pid, Acc, DelayMilliSec, N, ExpectNchunks) ->
+ %% N >= ExpectNchunks-1
+ timer:sleep(DelayMilliSec),
+ recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks).
+
-recv_chunk(Pid, Acc, N) ->
+recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks) ->
+ ct:log("Call ftp:recv_chunk",[]),
case ftp:recv_chunk(Pid) of
ok -> {ok, Acc, N};
- {ok, Bin} -> recv_chunk(Pid, <<Acc/binary, Bin/binary>>, N+1);
+ {ok, Bin} -> recv_chunk(Pid, <<Acc/binary, Bin/binary>>, DelayMilliSec, N+1, ExpectNchunks);
Error -> {Error, N}
end.
diff --git a/lib/inets/test/ftp_format_SUITE.erl b/lib/inets/test/ftp_format_SUITE.erl
index a33b31f46f..95d594a44b 100644
--- a/lib/inets/test/ftp_format_SUITE.erl
+++ b/lib/inets/test/ftp_format_SUITE.erl
@@ -38,8 +38,8 @@ all() ->
groups() ->
[{ftp_response, [],
[ftp_150, ftp_200, ftp_220, ftp_226, ftp_257, ftp_331,
- ftp_425, ftp_other_status_codes, ftp_multiple_lines,
- ftp_multipel_ctrl_messages]}].
+ ftp_425, ftp_other_status_codes, ftp_multiple_lines_status_in_msg,
+ ftp_multiple_lines, ftp_multipel_ctrl_messages]}].
init_per_suite(Config) ->
Config.
@@ -141,6 +141,15 @@ ftp_425(Config) when is_list(Config) ->
{trans_neg_compl, _} = ftp_response:interpret(Msg),
ok.
+ftp_multiple_lines_status_in_msg() ->
+ [{doc, "check that multiple lines gets parsed correct, even if we have "
+ " the status code within the msg being sent"}].
+ftp_multiple_lines_status_in_msg(Config) when is_list(Config) ->
+ ML = "230-User usr-230 is logged in\r\n" ++
+ "230 OK. Current directory is /\r\n",
+ {ok, ML, <<>>} = ftp_response:parse_lines(list_to_binary(ML), [], start),
+ ok.
+
ftp_multiple_lines() ->
[{doc, "Especially check multiple lines devided in significant places"}].
ftp_multiple_lines(Config) when is_list(Config) ->
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index a2b463e98c..4e10a97f58 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 932567ec55..8aea38037d 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -88,7 +88,8 @@ real_requests()->
stream_through_mfa,
streaming_error,
inet_opts,
- invalid_headers
+ invalid_headers,
+ invalid_body
].
only_simulated() ->
@@ -125,7 +126,9 @@ only_simulated() ->
redirect_see_other,
redirect_temporary_redirect,
port_in_host_header,
- relaxed
+ redirect_port_in_host_header,
+ relaxed,
+ multipart_chunks
].
misc() ->
@@ -500,10 +503,11 @@ redirect_multiple_choises(Config) when is_list(Config) ->
httpc:request(get, {URL300, []}, [{autoredirect, false}], []).
%%-------------------------------------------------------------------------
redirect_moved_permanently() ->
- [{doc, "If the 301 status code is received in response to a request other "
- "than GET or HEAD, the user agent MUST NOT automatically redirect the request "
- "unless it can be confirmed by the user, since this might change "
- "the conditions under which the request was issued."}].
+ [{doc, "The server SHOULD generate a Location header field in the response "
+ "containing a preferred URI reference for the new permanent URI. The user "
+ "agent MAY use the Location field value for automatic redirection. The server's "
+ "response payload usually contains a short hypertext note with a "
+ "hyperlink to the new URI(s)."}].
redirect_moved_permanently(Config) when is_list(Config) ->
URL301 = url(group_name(Config), "/301.html", Config),
@@ -514,15 +518,16 @@ redirect_moved_permanently(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], []}}
= httpc:request(head, {URL301, []}, [], []),
- {ok, {{_,301,_}, [_ | _], [_|_]}}
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
= httpc:request(post, {URL301, [],"text/plain", "foobar"},
[], []).
%%-------------------------------------------------------------------------
redirect_found() ->
- [{doc," If the 302 status code is received in response to a request other "
- "than GET or HEAD, the user agent MUST NOT automatically redirect the "
- "request unless it can be confirmed by the user, since this might change "
- "the conditions under which the request was issued."}].
+ [{doc, "The server SHOULD generate a Location header field in the response "
+ "containing a URI reference for the different URI. The user agent MAY "
+ "use the Location field value for automatic redirection. The server's "
+ "response payload usually contains a short hypertext note with a "
+ "hyperlink to the different URI(s)."}].
redirect_found(Config) when is_list(Config) ->
URL302 = url(group_name(Config), "/302.html", Config),
@@ -533,14 +538,14 @@ redirect_found(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], []}}
= httpc:request(head, {URL302, []}, [], []),
- {ok, {{_,302,_}, [_ | _], [_|_]}}
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
= httpc:request(post, {URL302, [],"text/plain", "foobar"},
[], []).
%%-------------------------------------------------------------------------
redirect_see_other() ->
[{doc, "The different URI SHOULD be given by the Location field in the response. "
"Unless the request method was HEAD, the entity of the response SHOULD contain a short "
- "hypertext note with a hyperlink to the new URI(s). "}].
+ "hypertext note with a hyperlink to the new URI(s)."}].
redirect_see_other(Config) when is_list(Config) ->
URL303 = url(group_name(Config), "/303.html", Config),
@@ -556,10 +561,11 @@ redirect_see_other(Config) when is_list(Config) ->
[], []).
%%-------------------------------------------------------------------------
redirect_temporary_redirect() ->
- [{doc," If the 307 status code is received in response to a request other "
- "than GET or HEAD, the user agent MUST NOT automatically redirect the request "
- "unless it can be confirmed by the user, since this might change "
- "the conditions under which the request was issued."}].
+ [{doc, "The server SHOULD generate a Location header field in the response "
+ "containing a URI reference for the different URI. The user agent MAY "
+ "use the Location field value for automatic redirection. The server's "
+ "response payload usually contains a short hypertext note with a "
+ "hyperlink to the different URI(s)."}].
redirect_temporary_redirect(Config) when is_list(Config) ->
URL307 = url(group_name(Config), "/307.html", Config),
@@ -570,7 +576,7 @@ redirect_temporary_redirect(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], []}}
= httpc:request(head, {URL307, []}, [], []),
- {ok, {{_,307,_}, [_ | _], [_|_]}}
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
= httpc:request(post, {URL307, [],"text/plain", "foobar"},
[], []).
@@ -997,10 +1003,25 @@ invalid_headers(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), [{"cookie", undefined}]},
{error, _} = httpc:request(get, Request, [], []).
+%%-------------------------------------------------------------------------
+
+invalid_body(Config) ->
+ URL = url(group_name(Config), "/dummy.html", Config),
+ try
+ httpc:request(post, {URL, [], <<"text/plain">>, "foobar"},
+ [], []),
+ ct:fail(accepted_invalid_input)
+ catch
+ error:function_clause ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------------
remote_socket_close(Config) when is_list(Config) ->
URL = url(group_name(Config), "/just_close.html", Config),
{error, socket_closed_remotely} = httpc:request(URL).
+
%%-------------------------------------------------------------------------
remote_socket_close_async(Config) when is_list(Config) ->
@@ -1099,8 +1120,21 @@ port_in_host_header(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/ensure_host_header_with_port.html", Config), []},
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
inets_test_lib:check_body(Body).
+%%-------------------------------------------------------------------------
+redirect_port_in_host_header(Config) when is_list(Config) ->
+
+ Request = {url(group_name(Config), "/redirect_ensure_host_header_with_port.html", Config), []},
+ {ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
+ inets_test_lib:check_body(Body).
%%-------------------------------------------------------------------------
+multipart_chunks(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/multipart_chunks.html", Config), []},
+ {ok, Ref} = httpc:request(get, Request, [], [{sync, false}, {stream, self}]),
+ ok = receive_stream_n(Ref, 10),
+ httpc:cancel_request(Ref).
+
+%%-------------------------------------------------------------------------
timeout_memory_leak() ->
[{doc, "Check OTP-8739"}].
timeout_memory_leak(Config) when is_list(Config) ->
@@ -1395,7 +1429,7 @@ dummy_server(Caller, SocketType, Inet, Extra) ->
end.
dummy_server_init(Caller, ip_comm, Inet, _) ->
- BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {active, false}],
+ BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {keepalive, true}, {active, false}],
{ok, ListenSocket} = gen_tcp:listen(0, [Inet | BaseOpts]),
{ok, Port} = inet:port(ListenSocket),
Caller ! {port, Port},
@@ -1677,6 +1711,12 @@ handle_uri(_,"/ensure_host_header_with_port.html",_,Headers,_,_) ->
"HTTP/1.1 500 Internal Server Error\r\n" ++
"Content-Length:" ++ Len ++ "\r\n\r\n" ++ B
end;
+handle_uri(_,"/redirect_ensure_host_header_with_port.html",Port,_,Socket,_) ->
+ NewUri = url_start(Socket) ++
+ integer_to_list(Port) ++ "/ensure_host_header_with_port.html",
+ "HTTP/1.1 302 Found \r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:0\r\n\r\n";
handle_uri(_,"/300.html",Port,_,Socket,_) ->
NewUri = url_start(Socket) ++
@@ -1965,6 +2005,16 @@ handle_uri(_,"/missing_CR.html",_,_,_,_) ->
"Content-Length:32\r\n\n" ++
"<HTML><BODY>foobar</BODY></HTML>";
+handle_uri(_,"/multipart_chunks.html",_,_,Socket,_) ->
+ Head = "HTTP/1.1 200 ok\r\n" ++
+ "Transfer-Encoding:chunked\r\n" ++
+ "Date: " ++ httpd_util:rfc1123_date() ++ "\r\n"
+ "Connection: Keep-Alive\r\n" ++
+ "Content-Type: multipart/x-mixed-replace; boundary=chunk_boundary\r\n" ++
+ "\r\n",
+ send(Socket, Head),
+ send_multipart_chunks(Socket),
+ http_chunk:encode_last();
handle_uri("HEAD",_,_,_,_,_) ->
"HTTP/1.1 200 ok\r\n" ++
"Content-Length:0\r\n\r\n";
@@ -2261,3 +2311,21 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) ->
Error ->
exit(Error)
end.
+
+send_multipart_chunks(Socket) ->
+ send(Socket, http_chunk:encode("--chunk_boundary\r\n")),
+ send(Socket, http_chunk:encode("Content-Type: text/plain\r\nContent-Length: 4\r\n\r\n")),
+ send(Socket, http_chunk:encode("test\r\n")),
+ ct:sleep(500),
+ send_multipart_chunks(Socket).
+
+receive_stream_n(_, 0) ->
+ ok;
+receive_stream_n(Ref, N) ->
+ receive
+ {http, {Ref, stream_start, _}} ->
+ receive_stream_n(Ref, N);
+ {http, {Ref,stream, Data}} ->
+ ct:pal("Data: ~p", [Data]),
+ receive_stream_n(Ref, N-1)
+ end.
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 3194b5ad3d..aae4ce5256 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -119,8 +119,10 @@ groups() ->
]},
{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, mod_esi_chunk_timeout] ++ http_head() ++ http_get() ++ load()},
+ {http_1_1, [],
+ [host, chunked, expect, cgi, cgi_chunked_encoding_test,
+ trace, range, if_modified_since, mod_esi_chunk_timeout,
+ esi_put] ++ http_head() ++ http_get() ++ load()},
{http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()},
{http_0_9, [], http_head() ++ http_get() ++ load()}
].
@@ -283,20 +285,50 @@ init_per_testcase(Case, Config) when Case == host; Case == trace ->
http_1_1 ->
httpd_1_1
end,
- [{version_cb, Cb} | proplists:delete(version_cb, Config)];
+ dbg(
+ Case,
+ [{version_cb, Cb} | proplists:delete(version_cb, Config)],
+ init);
init_per_testcase(range, Config) ->
ct:timetrap({seconds, 20}),
DocRoot = proplists:get_value(doc_root, Config),
create_range_data(DocRoot),
- Config;
+ dbg(range, Config, init);
-init_per_testcase(_, Config) ->
+init_per_testcase(Case, Config) ->
ct:timetrap({seconds, 20}),
- Config.
-
-end_per_testcase(_Case, _Config) ->
- ok.
+ dbg(Case, Config, init).
+
+end_per_testcase(Case, Config) ->
+ dbg(Case, Config, 'end').
+
+
+dbg(Case, Config, Status) ->
+ Cases = [esi_put],
+ case lists:member(Case, Cases) of
+ true ->
+ case Status of
+ init ->
+ dbg:tracer(),
+ dbg:p(all, c),
+ dbg:tpl(httpd_example, cx),
+ dbg:tpl(mod_esi, generate_webpage, cx),
+ io:format("dbg: started~n"),
+ Config;
+ 'end' ->
+ io:format("dbg: stopped~n"),
+ dbg:stop_clear(),
+ ok
+ end;
+ false ->
+ case Status of
+ init ->
+ Config;
+ 'end' ->
+ ok
+ end
+ end.
%%-------------------------------------------------------------------------
%% Test cases starts here.
@@ -489,6 +521,9 @@ do_auth_api(AuthPrefix, Config) ->
"two", "group1"),
add_group_member(Node, ServerRoot, Port, AuthPrefix,
"secret", "Aladdin", "group2"),
+ {ok, Members} = list_group_members(Node, ServerRoot, Port, AuthPrefix, "secret", "group1"),
+ true = lists:member("one", Members),
+ true = lists:member("two", Members),
ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
"one", "onePassword", Version, Host),
Config, [{statuscode, 200}]),
@@ -765,6 +800,14 @@ esi(Config) when is_list(Config) ->
ok = http_status("GET /cgi-bin/erl/httpd_example:peer ",
Config, [{statuscode, 200},
{header, "peer-cert-exist", peer(Config)}]).
+
+%%-------------------------------------------------------------------------
+esi_put() ->
+ [{doc, "Test mod_esi PUT"}].
+
+esi_put(Config) when is_list(Config) ->
+ ok = http_status("PUT /cgi-bin/erl/httpd_example/put/123342234123 ",
+ Config, [{statuscode, 200}]).
%%-------------------------------------------------------------------------
mod_esi_chunk_timeout(Config) when is_list(Config) ->
@@ -2115,6 +2158,10 @@ add_group_member(Node, Root, Port, AuthPrefix, Dir, User, Group) ->
Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
rpc:call(Node, mod_auth, add_group_member, [Group, User, Addr, Port,
Directory]).
+list_group_members(Node, Root, Port, AuthPrefix, Dir, Group) ->
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, list_group_members, [Group, [{port, Port}, {dir, Directory}]]).
+
getaddr() ->
{ok,HostName} = inet:gethostname(),
{ok,{A1,A2,A3,A4}} = inet:getaddr(HostName,inet),
diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl
index 5eaf3a28a0..38b8229389 100644
--- a/lib/inets/test/inets_SUITE.erl
+++ b/lib/inets/test/inets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -212,11 +212,19 @@ start_httpd(Config) when is_list(Config) ->
Pids0 = [ServicePid || {_, ServicePid} <- inets:services()],
true = lists:member(Pid0, Pids0),
[_|_] = inets:services_info(),
-
inets:stop(httpd, Pid0),
ct:sleep(500),
+ Pids1 = [ServicePid || {_, ServicePid} <- inets:services()],
+ false = lists:member(Pid0, Pids1),
+ {ok, Pid0b} =
+ inets:start(httpd, [{port, 0}, {ipfamily, inet6fb4} | HttpdConf]),
+ Pids0b = [ServicePid || {_, ServicePid} <- inets:services()],
+ true = lists:member(Pid0b, Pids0b),
+ [_|_] = inets:services_info(),
+ inets:stop(httpd, Pid0b),
+ ct:sleep(500),
Pids1 = [ServicePid || {_, ServicePid} <- inets:services()],
- false = lists:member(Pid0, Pids1),
+ false = lists:member(Pid0b, Pids1),
{ok, Pid1} =
inets:start(httpd, [{port, 0}, {ipfamily, inet} | HttpdConf],
stand_alone),
diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl
index 18df995215..7ea7e08ed1 100644
--- a/lib/inets/test/inets_socketwrap_SUITE.erl
+++ b/lib/inets/test/inets_socketwrap_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 5b8b1463c8..1e664337e6 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -33,7 +33,7 @@ suite() ->
all() ->
[default_tree, ftpc_worker, tftpd_worker,
- httpd_subtree, httpd_subtree_profile,
+ httpd_config, httpd_subtree, httpd_subtree_profile,
httpc_subtree].
groups() ->
@@ -52,9 +52,32 @@ end_per_suite(_) ->
inets:stop(),
ok.
-init_per_testcase(httpd_subtree, Config) ->
+init_per_testcase(httpd_config = TC, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Dir = filename:join(PrivDir, TC),
+ ok = file:make_dir(Dir),
+
+ FallbackConfig = [{port, 0},
+ {server_name,"www.test"},
+ {modules, [mod_get]},
+ {server_root, Dir},
+ {document_root, Dir},
+ {bind_address, any},
+ {ipfamily, inet6fb4}],
+ try
+ inets:stop(),
+ inets:start(),
+ inets:start(httpd, FallbackConfig),
+ Config
+ catch
+ _:Reason ->
+ inets:stop(),
+ exit({failed_starting_inets, Reason})
+ end;
+
+init_per_testcase(httpd_subtree = TC, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
- Dir = filename:join(PrivDir, "root"),
+ Dir = filename:join(PrivDir, TC),
ok = file:make_dir(Dir),
SimpleConfig = [{port, 0},
@@ -75,9 +98,9 @@ init_per_testcase(httpd_subtree, Config) ->
exit({failed_starting_inets, Reason})
end;
-init_per_testcase(httpd_subtree_profile, Config) ->
+init_per_testcase(httpd_subtree_profile = TC, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
- Dir = filename:join(PrivDir, "root"),
+ Dir = filename:join(PrivDir, TC),
ok = file:make_dir(Dir),
SimpleConfig = [{port, 0},
@@ -193,6 +216,11 @@ tftpd_worker(Config) when is_list(Config) ->
[] = supervisor:which_children(tftp_sup),
ok.
+httpd_config() ->
+ [{doc, "Makes sure the httpd config works for inet6fb4."}].
+httpd_config(Config) when is_list(Config) ->
+ do_httpd_subtree(Config, default).
+
httpd_subtree() ->
[{doc, "Makes sure the httpd sub tree is correct."}].
httpd_subtree(Config) when is_list(Config) ->
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 543e0d44fd..758cef7ac4 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
+# Copyright Ericsson AB 2001-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.3
+INETS_VSN = 6.3.9
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/doc/src/Makefile b/lib/jinterface/doc/src/Makefile
index cd1e61a795..508c8e01b5 100644
--- a/lib/jinterface/doc/src/Makefile
+++ b/lib/jinterface/doc/src/Makefile
@@ -166,7 +166,7 @@ release_docs_spec: docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DIR) "$(RELSYSDIR)/doc/html/java/$(JAVA_PKG_PATH)"
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- (/bin/cp -rf ../html "$(RELSYSDIR)/doc")
+ ($(CP) -rf ../html "$(RELSYSDIR)/doc")
# $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
# "$(RELSYSDIR)/doc/html"
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index 3151fc4b5e..30f607c357 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
+<section><title>Jinterface 1.7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Update build scripts to not make assumtions about where
+ env, cp and perl are located.</p>
+ <p>
+ Own Id: OTP-13800</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Jinterface 1.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index 752b34e78c..c29d9df3d7 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.7
+JINTERFACE_VSN = 1.7.1
diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml
index 5e0da409a3..d2e9390d7e 100644
--- a/lib/kernel/doc/src/app.xml
+++ b/lib/kernel/doc/src/app.xml
@@ -151,7 +151,7 @@ ApplicationVersion = string()</code>
application is allowed to be started. <c>systools</c> uses
this list to generate correct start scripts. Defaults to
the empty list, but notice that all applications have
- dependencies to (at least) <c>Kernel</c> and <c>STDLIB</c>.</p>
+ dependencies to (at least) Kernel and STDLIB.</p>
</item>
<tag><c>env</c></tag>
<item>
@@ -171,7 +171,7 @@ ApplicationVersion = string()</code>
implemented as a supervision tree, otherwise the application
controller does not know how to start it. <c>mod</c>
can be omitted for applications without processes, typically
- code libraries, for example, <c>STDLIB</c>.</p>
+ code libraries, for example, STDLIB.</p>
</item>
<tag><c>start_phases</c></tag>
<item>
@@ -236,7 +236,7 @@ ApplicationVersion = string()</code>
<section>
<title>See Also</title>
<p><seealso marker="application"><c>application(3)</c></seealso>,
- <seealso marker="sasl:systools"><c>sasl:systools(3)</c></seealso></p>
+ <seealso marker="sasl:systools"><c>systools(3)</c></seealso></p>
</section>
</fileref>
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 8d33aa86e7..886286b76d 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -200,7 +200,7 @@
<seealso marker="app"><c>app(4)</c></seealso>.</p>
<p>If <c><anno>Distributed</anno> == {<anno>Application</anno>,[<anno>Time</anno>,]<anno>Nodes</anno>}</c>,
the application becomes distributed. The argument overrides
- the value for the application in the <c>Kernel</c> configuration
+ the value for the application in the Kernel configuration
parameter <c>distributed</c>. <c><anno>Application</anno></c> must be
the application name (same as in the first argument).
If a node crashes and <c><anno>Time</anno></c> is specified,
@@ -221,7 +221,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
the application is to be started at <c>cp2@cave</c>
or <c>cp3@cave</c>.</p>
<p>If <c>Distributed == default</c>, the value for
- the application in the <c>Kernel</c> configuration parameter
+ the application in the Kernel configuration parameter
<c>distributed</c> is used.</p>
</desc>
</func>
@@ -267,7 +267,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
started, <c>Application</c> is started as well.</p>
<p>By default, all applications are loaded with permission
<c>true</c> on all nodes. The permission can be configured
- using the <c>Kernel</c> configuration parameter <c>permissions</c>.</p>
+ using the Kernel configuration parameter <c>permissions</c>.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml
index 03f983b96d..5901446960 100644
--- a/lib/kernel/doc/src/auth.xml
+++ b/lib/kernel/doc/src/auth.xml
@@ -47,7 +47,7 @@
<desc>
<p>Use
<seealso marker="erts:erlang#erlang:get_cookie/0"><c>erlang:get_cookie()</c></seealso>
- in <c>ERTS</c> instead.</p>
+ in ERTS instead.</p>
</desc>
</func>
<func>
@@ -59,7 +59,7 @@
<desc>
<p>Use
<seealso marker="erts:erlang#erlang:set_cookie/2"><c>erlang:set_cookie(node(), <anno>Cookie</anno>)</c>
- in <c>ERTS</c></seealso> instead.</p>
+ in ERTS</seealso> instead.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index d3611d6a03..3143cdc825 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -86,11 +86,11 @@
an <c>ebin</c> directory are ignored.</p>
<p>All application directories found in the additional directories
appears before the standard OTP applications, except for the
- <c>Kernel</c> and <c>STDLIB</c> applications, which are placed before
+ Kernel and STDLIB applications, which are placed before
any additional applications. In other words, modules found in any
of the additional library directories override modules with
- the same name in OTP, except for modules in <c>Kernel</c> and
- <c>STDLIB</c>.</p>
+ the same name in OTP, except for modules in Kernel and
+ STDLIB.</p>
<p>Environment variable <c>ERL_LIBS</c> (if defined) is to contain
a colon-separated (for Unix-like systems) or semicolon-separated
(for Windows) list of additional libraries.</p>
@@ -151,7 +151,7 @@ zip:create("mnesia-4.4.7.ez",
<c>$OTPROOT/lib/mnesia.ez/mnesia/ebin</c> or
<c>$OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin</c>.</p>
- <p>The code server uses module <c>erl_prim_loader</c> in <c>ERTS</c>
+ <p>The code server uses module <c>erl_prim_loader</c> in ERTS
(possibly through <c>erl_boot_server</c>) to read code files from
archives. However, the functions in <c>erl_prim_loader</c> can also be
used by other applications to read files from archives. For
@@ -382,9 +382,14 @@ zip:create("mnesia-4.4.7.ez",
<name name="add_pathsa" arity="1"/>
<fsummary>Add directories to the beginning of the code path.</fsummary>
<desc>
- <p>Adds the directories in <c><anno>Dirs</anno></c> to the beginning of
- the code path. If a <c><anno>Dir</anno></c> exists, it is removed
- from the old position in the code path.</p>
+ <p>Traverses <c><anno>Dirs</anno></c> and adds
+ each <c><anno>Dir</anno></c> to the beginning of the code
+ path. This means that the order of <c><anno>Dirs</anno></c>
+ is reversed in the resulting code path. For example, if you
+ add <c>[Dir1,Dir2]</c>, the resulting path will
+ be <c>[Dir2,Dir1|OldCodePath]</c>.</p>
+ <p>If a <c><anno>Dir</anno></c> already exists in the code
+ path, it is removed from the old position.</p>
<p>Always returns <c>ok</c>, regardless of the validity of each
individual <c><anno>Dir</anno></c>.</p>
</desc>
@@ -651,6 +656,11 @@ ok = code:finish_loading(Prepared),
<p>Purges the code for <c><anno>Module</anno></c>, that is, removes code
marked as old. If some processes still linger in the old code,
these processes are killed before the code is removed.</p>
+ <note><p>As of ERTS version 9.0, a process is only considered
+ to be lingering in the code if it has direct references to the code.
+ For more information see documentation of
+ <seealso marker="erts:erlang#check_process_code/3"><c>erlang:check_process_code/3</c></seealso>,
+ which is used in order to determine this.</p></note>
<p>Returns <c>true</c> if successful and any process is needed to
be killed, otherwise <c>false</c>.</p>
</desc>
@@ -661,6 +671,11 @@ ok = code:finish_loading(Prepared),
<desc>
<p>Purges the code for <c><anno>Module</anno></c>, that is, removes code
marked as old, but only if no processes linger in it.</p>
+ <note><p>As of ERTS version 9.0, a process is only considered
+ to be lingering in the code if it has direct references to the code.
+ For more information see documentation of
+ <seealso marker="erts:erlang#check_process_code/3"><c>erlang:check_process_code/3</c></seealso>,
+ which is used in order to determine this.</p></note>
<p>Returns <c>false</c> if the module cannot be purged because
of processes lingering in old code, otherwise <c>true</c>.</p>
</desc>
@@ -678,9 +693,9 @@ ok = code:finish_loading(Prepared),
<p>Normally, <c><anno>Loaded</anno></c> is the absolute filename
<c>Filename</c> from which the code is obtained. If the module
is preloaded (see
- <seealso marker="sasl:script"><c>sasl:script(4)</c></seealso>),
+ <seealso marker="sasl:script"><c>script(4)</c></seealso>),
<c>Loaded==preloaded</c>. If the module is Cover-compiled (see
- <seealso marker="tools:cover"><c>tools:cover(3)</c></seealso>),
+ <seealso marker="tools:cover"><c>cover(3)</c></seealso>),
<c>Loaded==cover_compiled</c>.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml
index 897365f9b9..4109251387 100644
--- a/lib/kernel/doc/src/erl_boot_server.xml
+++ b/lib/kernel/doc/src/erl_boot_server.xml
@@ -38,13 +38,13 @@
command-line flag <c>-loader inet</c>. All hosts specified
with command-line flag <c>-hosts Host</c> must have one
instance of this server running.</p>
- <p>This server can be started with the <c>Kernel</c> configuration
+ <p>This server can be started with the Kernel configuration
parameter <c>start_boot_server</c>.</p>
<p>The <c>erl_boot_server</c> can read regular files and
files in archives. See <seealso marker="code"><c>code(3)</c></seealso>
and
<seealso marker="erts:erl_prim_loader"><c>erl_prim_loader(3)</c></seealso>
- in <c>ERTS</c>.</p>
+ in ERTS.</p>
<warning><p>The support for loading code from archive files is
experimental. It is released before it is ready
to obtain early feedback. The file format, semantics,
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index a5ce58ef3e..75114e015c 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -201,7 +201,7 @@
<desc>
<p>Removes a driver monitor in much the same way as
<seealso marker="erts:erlang#erlang:demonitor/1"><c>erlang:demonitor/1</c></seealso>
- in <c>ERTS</c>
+ in ERTS
does with process monitors. For details about how to create
driver monitors, see
<seealso marker="#monitor/2"><c>monitor/2</c></seealso>,
@@ -431,7 +431,7 @@
<p>Creates a driver monitor and works in many
ways as
<seealso marker="erts:erlang#erlang:monitor/2"><c>erlang:monitor/2</c></seealso>
- in <c>ERTS</c>,
+ in ERTS,
does for processes. When a driver changes state, the monitor
results in a monitor message that is sent to the calling
process. <c><anno>MonitorRef</anno></c> returned by this function is
@@ -745,7 +745,7 @@
<p>This parameter is the name of the driver
to be used in subsequent calls to function
<seealso marker="erts:erlang#open_port/2"><c>erlang:open_port</c></seealso>
- in <c>ERTS</c>.
+ in ERTS.
The name can be specified as an <c>iolist()</c> or
an <c>atom()</c>. The name specified when loading is used
to find the object file (with the help of <c><anno>Path</anno></c>
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml
index a8273e59e2..814e8eac46 100644
--- a/lib/kernel/doc/src/error_logger.xml
+++ b/lib/kernel/doc/src/error_logger.xml
@@ -33,7 +33,7 @@
<description>
<p>The Erlang <em>error logger</em> is an event manager (see
<seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso> and
- <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>),
+ <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>),
registered as <c>error_logger</c>. Errors, warnings, and info events
are sent to the error logger from the Erlang runtime system and
the different Erlang/OTP applications. The events are, by default,
@@ -44,12 +44,12 @@
executing.</p>
<p>Initially, <c>error_logger</c> has only a primitive event
handler, which buffers and prints the raw event messages. During
- system startup, the <c>Kernel</c> application replaces this with a
+ system startup, the Kernel application replaces this with a
<em>standard event handler</em>, by default one that writes
- nicely formatted output to the terminal. <c>Kernel</c> can also be
+ nicely formatted output to the terminal. Kernel can also be
configured so that events are logged to a file instead, or not logged at all,
see <seealso marker="kernel_app"><c>kernel(6)</c></seealso>.</p>
- <p>Also the <c>SASL</c> application, if started, adds its own event
+ <p>Also the SASL application, if started, adds its own event
handler, which by default writes supervisor, crash, and progress
reports to the terminal. See
<seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso>.</p>
@@ -58,9 +58,9 @@
User-defined event handlers can be added to handle application-specific
events, see
<seealso marker="#add_report_handler/1"><c>add_report_handler/1,2</c></seealso>.
- Also, a useful event handler is provided in <c>STDLIB</c> for multi-file
+ Also, a useful event handler is provided in STDLIB for multi-file
logging of events, see
- <seealso marker="stdlib:log_mf_h"><c>stdlib:log_mf_h(3)</c></seealso>.</p>
+ <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>.</p>
<p>Warning events were introduced in Erlang/OTP R9C and are enabled
by default as from Erlang/OTP 18.0. To retain backwards compatibility
with existing user-defined event handlers, the warning events can be
@@ -82,7 +82,7 @@
<p>Adds a new event handler to the error logger. The event
handler must be implemented as a <c>gen_event</c> callback
module, see
- <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>.</p>
+ <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>.</p>
<p><c><anno>Handler</anno></c> is typically the name of the callback module
and <c><anno>Args</anno></c> is an optional term (defaults to []) passed
to the initialization callback function <c><anno>Handler</anno>:init/1</c>.
@@ -97,7 +97,7 @@
<desc>
<p>Deletes an event handler from the error logger by calling
<c>gen_event:delete_handler(error_logger, <anno>Handler</anno>, [])</c>,
- see <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>.</p>
+ see <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -110,7 +110,7 @@
The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
are the same as the arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in <c>STDLIB</c>.
+ in STDLIB.
The event is handled by the standard event handler.</p>
<p><em>Example:</em></p>
<pre>
@@ -171,7 +171,7 @@ ok</pre>
The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
are the same as the arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in <c>STDLIB</c>. The event is handled by the standard event handler.</p>
+ in STDLIB. The event is handled by the standard event handler.</p>
<p><em>Example:</em></p>
<pre>
1> <input>error_logger:info_msg("Something happened in ~p~n", [a_module]).</input>
@@ -235,7 +235,7 @@ ok</pre>
<p>Enables or disables printout of standard events to a file.</p>
<p>This is done by adding or deleting the standard event handler
for output to file. Thus, calling this function overrides
- the value of the <c>Kernel</c> <c>error_logger</c> configuration
+ the value of the Kernel <c>error_logger</c> configuration
parameter.</p>
<p>Enabling file logging can be used together with calling
<c>tty(false)</c>, to have a silent system where
@@ -274,7 +274,7 @@ ok</pre>
to the terminal.</p>
<p>This is done by adding or deleting the standard event handler
for output to the terminal. Thus, calling this function overrides
- the value of the <c>Kernel</c> <c>error_logger</c> configuration parameter.</p>
+ the value of the Kernel <c>error_logger</c> configuration parameter.</p>
</desc>
</func>
<func>
@@ -323,7 +323,7 @@ ok</pre>
The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
are the same as the arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in <c>STDLIB</c>.
+ in STDLIB.
The event is handled by the standard event handler. It is tagged
as an error, warning, or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
@@ -416,8 +416,8 @@ ok</pre>
</section>
<section>
<title>See Also</title>
- <p><seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>,
- <seealso marker="stdlib:log_mf_h"><c>stdlib:log_mf_h(3)</c></seealso>
+ <p><seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>,
+ <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>
<seealso marker="kernel_app"><c>kernel(6)</c></seealso>
<seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso></p>
</section>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 7d86c3ebcb..b674b3ca93 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -79,7 +79,7 @@
<seealso marker="#list_dir_all"><c>list_dir_all/1</c></seealso> and
<seealso marker="#read_link_all"><c>read_link_all/1</c></seealso>.</p>
- <p>See also section <seealso marker="stdlib:unicode_usage#notes-about-raw-filenames">Notes About Raw Filenames</seealso> in the <c>STDLIB</c> User´s Giude.</p>
+ <p>See also section <seealso marker="stdlib:unicode_usage#notes-about-raw-filenames">Notes About Raw Filenames</seealso> in the STDLIB User's Guide.</p>
</description>
@@ -277,7 +277,7 @@ f.txt: {person, "kalle", 25}.
{ok,[{person,"kalle",25},{person,"pelle",30}]}</pre>
<p>The encoding of <c><anno>Filename</anno></c> can be set
by a comment, as described in
- <seealso marker="stdlib:epp#encoding"><c>stdlib:epp(3)</c></seealso>.</p>
+ <seealso marker="stdlib:epp#encoding"><c>epp(3)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -445,7 +445,7 @@ f.txt: {person, "kalle", 25}.
</taglist>
<p>The encoding of <c><anno>Filename</anno></c> can be set
by a comment, as described in
- <seealso marker="stdlib:epp#encoding"><c>stdlib:epp(3)</c></seealso>.</p>
+ <seealso marker="stdlib:epp#encoding"><c>epp(3)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -455,7 +455,7 @@ f.txt: {person, "kalle", 25}.
<p>The same as <c>eval/1</c>, but the variable bindings
<c><anno>Bindings</anno></c> are used in the evaluation. For information
about the variable bindings, see
- <seealso marker="stdlib:erl_eval"><c>stdlib:erl_eval(3)</c></seealso>.</p>
+ <seealso marker="stdlib:erl_eval"><c>erl_eval(3)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -830,7 +830,7 @@ f.txt: {person, "kalle", 25}.
this module (<c>file</c>) for reading and writing data as the interfaces
provided here work with byte-oriented data. Using other (Unicode)
encodings makes the
- <seealso marker="stdlib:io"><c>stdlib:io(3)</c></seealso> functions
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso> functions
<c>get_chars</c>, <c>get_line</c>, and <c>put_chars</c> more suitable,
as they can work with the full Unicode range.</p>
<p>If data is sent to an <c>io_device()</c> in a format that cannot be
@@ -847,7 +847,7 @@ f.txt: {person, "kalle", 25}.
that is,
<seealso marker="#read/2"><c>read/2</c></seealso> are
returned "as is". If module
- <seealso marker="stdlib:io"><c>stdlib:io(3)</c></seealso> is used for
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso> is used for
writing, the file can only cope with Unicode characters up to code point
255 (the ISO Latin-1 range).</p>
</item>
@@ -861,7 +861,7 @@ f.txt: {person, "kalle", 25}.
the file lies beyond the ISO Latin-1 range (0..255), but failure occurs
if the data contains Unicode code points beyond that range. The file is
best read with the functions in the Unicode aware module
- <seealso marker="stdlib:io"><c>stdlib:io(3)</c></seealso>.</p>
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso>.</p>
<p>Bytes written to the file by any means are translated to UTF-8 encoding
before being stored on the disk file.</p>
</item>
@@ -891,7 +891,7 @@ f.txt: {person, "kalle", 25}.
So a file can be analyzed in latin1 encoding for, for example, a BOM,
positioned beyond the BOM and then be set for the right encoding before
further reading. For functions identifying BOMs, see module
- <seealso marker="stdlib:unicode"><c>stdlib:unicode(3)</c></seealso>. </p>
+ <seealso marker="stdlib:unicode"><c>unicode(3)</c></seealso>. </p>
<p>This option is not allowed on <c>raw</c> files.</p>
</item>
<tag><c>ram</c></tag>
@@ -932,7 +932,7 @@ f.txt: {person, "kalle", 25}.
closed and the process itself is terminated.
An <c><anno>IoDevice</anno></c> returned from this call can be used
as an argument to the I/O functions (see
- <seealso marker="stdlib:io"><c>stdlib:io(3)</c></seealso>).</p>
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso>).</p>
<note>
<p>In previous versions of <c>file</c>, modes were specified
as one of the atoms <c>read</c>, <c>write</c>, or
@@ -1055,7 +1055,7 @@ f.txt: {person, "kalle", 25}.
</taglist>
<p>The encoding of <c><anno>Filename</anno></c> can be set
by a comment as described in
- <seealso marker="stdlib:epp#encoding"><c>stdlib:epp(3)</c></seealso>.</p>
+ <seealso marker="stdlib:epp#encoding"><c>epp(3)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -1128,7 +1128,7 @@ f.txt: {person, "kalle", 25}.
</taglist>
<p>The encoding of <c><anno>Filename</anno></c> can be set
by a comment as described in
- <seealso marker="stdlib:epp#encoding"><c>stdlib:epp(3)</c></seealso>.</p>
+ <seealso marker="stdlib:epp#encoding"><c>epp(3)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -1389,7 +1389,7 @@ f.txt: {person, "kalle", 25}.
<c>{ok, <anno>FileInfo</anno>}</c> if successful, otherwise
<c>{error, <anno>Reason</anno>}</c>. <c><anno>FileInfo</anno></c>
is a record
- <c>file_info</c>, defined in the <c>Kernel</c> include file
+ <c>file_info</c>, defined in the Kernel include file
<c>file.hrl</c>. Include the following directive in the module
from which the function is called:</p>
<code type="none">
@@ -1477,8 +1477,8 @@ f.txt: {person, "kalle", 25}.
<tag><c>16#400</c></tag>
<item><p>set group id on execution</p></item>
</taglist>
- <p>On Unix platforms, the following bits
- can also be set:</p>
+ <p>On Unix platforms, other bits than those listed above
+ may be set.</p>
</item>
<tag><c>links = integer() >= 0</c></tag>
<item>
@@ -1552,7 +1552,7 @@ f.txt: {person, "kalle", 25}.
raw line-oriented reading.</p>
<p>If <c>encoding</c> is set to something else than <c>latin1</c>, the
<c>read_line/1</c> call fails if the data contains characters larger than 255,
- why module <seealso marker="stdlib:io"><c>stdlib:io(3)</c></seealso> is to be
+ why module <seealso marker="stdlib:io"><c>io(3)</c></seealso> is to be
preferred when reading such a file.</p>
<p>The function returns:</p>
<taglist>
@@ -1970,7 +1970,7 @@ f.txt: {person, "kalle", 25}.
<p>Changes file information. Returns <c>ok</c> if successful,
otherwise <c>{error, <anno>Reason</anno>}</c>.
<c><anno>FileInfo</anno></c> is a record
- <c>file_info</c>, defined in the <c>Kernel</c> include file
+ <c>file_info</c>, defined in the Kernel include file
<c>file.hrl</c>. Include the following directive in the module
from which the function is called:</p>
<code type="none">
@@ -2042,8 +2042,8 @@ f.txt: {person, "kalle", 25}.
<tag><c>16#400</c></tag>
<item><p>Set group id on execution</p></item>
</taglist>
- <p>On Unix platforms, the following bits
- can also be set.</p>
+ <p>On Unix platforms, other bits than those listed above
+ may be set.</p>
</item>
<tag><c>uid = integer() >= 0</c></tag>
<item>
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index 83242c2df8..e97db20062 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -216,7 +216,7 @@ do_recv(Sock, Bs) ->
time-out in milliseconds. Defaults to <c>infinity</c>.</p>
<note>
<p>The default values for options specified to <c>connect</c> can
- be affected by the <c>Kernel</c> configuration parameter
+ be affected by the Kernel configuration parameter
<c>inet_default_connect_options</c>. For details, see
<seealso marker="inet"><c>inet(3)</c></seealso>.</p>
</note>
@@ -231,7 +231,11 @@ do_recv(Sock, Bs) ->
<c><anno>Socket</anno></c>. The controlling process is the process
that receives messages from the socket. If called by any other
process than the current controlling process,
- <c>{error, not_owner}</c> is returned.</p>
+ <c>{error, not_owner}</c> is returned. If the process identified
+ by <c><anno>Pid</anno></c> is not an existing local pid,
+ <c>{error, badarg}</c> is returned. <c>{error, badarg}</c> may also
+ be returned in some cases when <c><anno>Socket</anno></c> is closed
+ during the execution of this function.</p>
<p>If the socket is set in active mode, this function
will transfer any messages in the mailbox of the caller
to the new controlling process.
@@ -293,7 +297,7 @@ do_recv(Sock, Bs) ->
<seealso marker="#accept/1"><c>accept/1,2</c></seealso>.</p>
<note>
<p>The default values for options specified to <c>listen</c> can
- be affected by the <c>Kernel</c> configuration parameter
+ be affected by the Kernel configuration parameter
<c>inet_default_listen_options</c>. For details, see
<seealso marker="inet"><c>inet(3)</c></seealso>.</p>
</note>
@@ -307,7 +311,7 @@ do_recv(Sock, Bs) ->
<type_desc variable="HttpPacket">See the description of
<c>HttpPacket</c> in
<seealso marker="erts:erlang#decode_packet/3"><c>erlang:decode_packet/3</c></seealso>
- in <c>ERTS</c>.
+ in ERTS.
</type_desc>
<desc>
<p>Receives a packet from a socket in passive
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index 3f88a0272d..f79566ef71 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -68,7 +68,11 @@
<c><anno>Socket</anno></c>. The controlling process is the process
that receives messages from the socket. If called by any other
process than the current controlling process,
- <c>{error, not_owner}</c> is returned.</p>
+ <c>{error, not_owner}</c> is returned. If the process identified
+ by <c><anno>Pid</anno></c> is not an existing local pid,
+ <c>{error, badarg}</c> is returned. <c>{error, badarg}</c> may also
+ be returned in some cases when <c><anno>Socket</anno></c> is closed
+ during the execution of this function.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 864f8facac..5b5b71e521 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -37,10 +37,7 @@
the <c>heart</c> port program is to check that the Erlang runtime system
it is supervising is still running. If the port program has not
received any heartbeats within <c>HEART_BEAT_TIMEOUT</c> seconds
- (defaults to 60 seconds), the system can be rebooted. Also, if
- the system is equipped with a hardware watchdog timer and is
- running Solaris, the watchdog can be used to supervise the entire
- system.</p>
+ (defaults to 60 seconds), the system can be rebooted.</p>
<p>An Erlang runtime system to be monitored by a heart program
is to be started with command-line flag <c>-heart</c> (see
also <seealso marker="erts:erl"><c>erl(1)</c></seealso>).
@@ -51,17 +48,13 @@
or a terminated Erlang runtime system, environment variable
<c>HEART_COMMAND</c> must be set before the system is started.
If this variable is not set, a warning text is printed but
- the system does not reboot. However, if the hardware watchdog is
- used, it still triggers a reboot <c>HEART_BEAT_BOOT_DELAY</c>
- seconds later (defaults to 60 seconds).</p>
+ the system does not reboot.</p>
<p>To reboot on Windows, <c>HEART_COMMAND</c> can be
set to <c>heart -shutdown</c> (included in the Erlang delivery)
or to any other suitable program that can activate a reboot.</p>
- <p>The hardware watchdog is not started under Solaris if
- environment variable <c>HW_WD_DISABLE</c> is set.</p>
- <p>The environment variables <c>HEART_BEAT_TIMEOUT</c> and
- <c>HEART_BEAT_BOOT_DELAY</c> can be used to configure the heart
- time-outs; they can be set in the operating system shell before Erlang
+ <p>The environment variable <c>HEART_BEAT_TIMEOUT</c>
+ can be used to configure the heart
+ time-outs; it can be set in the operating system shell before Erlang
is started or be specified at the command line:</p>
<pre>
% <input>erl -heart -env HEART_BEAT_TIMEOUT 30 ...</input></pre>
@@ -83,7 +76,7 @@
<c><![CDATA[SIGKILL]]></c>:</p>
<pre>
% <input>erl -heart -env HEART_KILL_SIGNAL SIGABRT ...</input></pre>
- <p> If heart should <b>not</b> kill the Erlang runtime system, this can be indicated
+ <p> If heart should <em>not</em> kill the Erlang runtime system, this can be indicated
using the environment variable <c><![CDATA[HEART_NO_KILL=TRUE]]></c>.
This can be useful if the command executed by heart takes care of this,
for example as part of a specific cleanup sequence.
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index c0dce2f50c..4c4a5c39cb 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -36,7 +36,7 @@
<seealso marker="erts:inet_cfg">ERTS User's Guide:
Inet Configuration</seealso> for more information about how to
configure an Erlang runtime system for IP communication.</p>
- <p>The following two <c>Kernel</c> configuration parameters affect the
+ <p>The following two Kernel configuration parameters affect the
behavior of all sockets opened on an Erlang node:</p>
<list type="bulleted">
<item><p><c>inet_default_connect_options</c> can contain a list of
@@ -48,7 +48,7 @@
<p>When <c>accept</c> is issued, the values of the listening socket options
are inherited. No such application variable is therefore needed for
<c>accept</c>.</p>
- <p>Using the <c>Kernel</c> configuration parameters above, one
+ <p>Using the Kernel configuration parameters above, one
can set default options for all TCP sockets on a node, but use this
with care. Options such as <c>{delay_send,true}</c> can be
specified in this way. The following is an example of starting an Erlang
@@ -95,7 +95,7 @@ fe80::204:acff:fe17:bf38
<datatype>
<name name="hostent"/>
<desc>
- <p>The record is defined in the <c>Kernel</c> include file
+ <p>The record is defined in the Kernel include file
<c>"inet.hrl"</c>.</p>
<p>Add the following directive to the module:</p>
<code>
@@ -151,6 +151,12 @@ fe80::204:acff:fe17:bf38
<name name="socket_address"/>
</datatype>
<datatype>
+ <name name="socket_getopt"/>
+ </datatype>
+ <datatype>
+ <name name="socket_setopt"/>
+ </datatype>
+ <datatype>
<name name="returned_non_ip_address"/>
<desc>
<p>
@@ -327,8 +333,6 @@ fe80::204:acff:fe17:bf38
<func>
<name name="getopts" arity="2"/>
<fsummary>Get one or more options for a socket.</fsummary>
- <type name="socket_getopt"/>
- <type name="socket_setopt"/>
<desc>
<p>Gets one or more options for a socket. For a list of available
options, see
@@ -387,7 +391,7 @@ get_tcpi_sacked(Sock) ->
<<_:28/binary,TcpiSacked:32/native,_/binary>> = Info,
TcpiSacked.]]></code>
<p>Preferably, you would check the machine type, the operating system,
- and the <c>Kernel</c> version before executing anything similar to
+ and the Kernel version before executing anything similar to
this code.</p>
</desc>
</func>
@@ -580,7 +584,6 @@ get_tcpi_sacked(Sock) ->
<func>
<name name="setopts" arity="2"/>
<fsummary>Set one or more options for a socket.</fsummary>
- <type name="socket_setopt"/>
<desc>
<p>Sets one or more options for a socket.</p>
<p>The following options are available:</p>
@@ -658,7 +661,7 @@ get_tcpi_sacked(Sock) ->
<p>The size of the user-level software buffer used by
the driver. Not to be confused with options <c>sndbuf</c>
and <c>recbuf</c>, which correspond to the
- <c>Kernel</c> socket buffers. It is recommended
+ Kernel socket buffers. It is recommended
to have <c>val(buffer) &gt;= max(val(sndbuf),val(recbuf))</c> to
avoid performance issues because of unnecessary copying.
<c>val(buffer)</c> is automatically set to the above
@@ -717,7 +720,7 @@ get_tcpi_sacked(Sock) ->
<p>The socket message queue is set to a busy
state when the amount of data on the message
queue reaches this limit. Notice that this limit only
- concerns data that has not yet reached the <c>ERTS</c> internal
+ concerns data that has not yet reached the ERTS internal
socket implementation. Defaults to 8 kB.</p>
<p>Senders of data to the socket are suspended if
either the socket message queue is busy or the socket
@@ -733,7 +736,7 @@ get_tcpi_sacked(Sock) ->
<tag><c>{high_watermark, Size}</c> (TCP/IP sockets)</tag>
<item>
<p>The socket is set to a busy state when the amount
- of data queued internally by the <c>ERTS</c> socket implementation
+ of data queued internally by the ERTS socket implementation
reaches this limit. Defaults to 8 kB.</p>
<p>Senders of data to the socket are suspended if
either the socket message queue is busy or the socket
@@ -813,7 +816,7 @@ get_tcpi_sacked(Sock) ->
socket message queue is set in a not busy state when
the amount of data queued in the message queue falls
below this limit. Notice that this limit only concerns data
- that has not yet reached the <c>ERTS</c> internal socket
+ that has not yet reached the ERTS internal socket
implementation. Defaults to 4 kB.</p>
<p>Senders that are suspended because of either a
busy message queue or a busy socket are resumed
@@ -831,7 +834,7 @@ get_tcpi_sacked(Sock) ->
<item>
<p>If the socket is in a busy state, the socket is
set in a not busy state when the amount of data
- queued internally by the <c>ERTS</c> socket implementation
+ queued internally by the ERTS socket implementation
falls below this limit. Defaults to 4 kB.</p>
<p>Senders that are suspended because of a
busy message queue or a busy socket are resumed
@@ -951,7 +954,7 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
are returned with the format according to <c>HttpPacket</c>
described in
<seealso marker="erts:erlang#decode_packet/3">
- <c>erlang:decode_packet/3</c></seealso> in <c>ERTS</c>.
+ <c>erlang:decode_packet/3</c></seealso> in ERTS.
A socket in passive
mode returns <c>{ok, HttpPacket}</c> from <c>gen_tcp:recv</c>
while an active socket sends messages like
@@ -984,11 +987,6 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
<p>Sets the line delimiting character for line-oriented protocols
(<c>line</c>). Defaults to <c>$\n</c>.</p>
</item>
- <tag><c>{priority, Priority}</c></tag>
- <item>
- <p>Sets the protocol-defined priority for all packets to be sent
- on this socket.</p>
- </item>
<tag><c>{raw, Protocol, OptionNum, ValueBin}</c></tag>
<item>
<p>See below.</p>
@@ -1089,6 +1087,15 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
The option is ignored on platforms where it is not
implemented. Use with caution.</p>
</item>
+ <tag><c>{tclass, Integer}</c></tag>
+ <item>
+ <p>
+ Sets <c>IPV6_TCLASS IP</c> level options on platforms
+ where this is implemented. The behavior and allowed range
+ varies between different systems.
+ The option is ignored on platforms where it is not
+ implemented. Use with caution.</p>
+ </item>
</taglist>
<p>In addition to these options, <em>raw</em>
option specifications can be used. The raw options are
@@ -1127,7 +1134,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
can respond differently to this kind of option
manipulation. Use with care.</p>
<p>Notice that the default options for TCP/IP sockets can be
- changed with the <c>Kernel</c> configuration parameters mentioned in
+ changed with the Kernel configuration parameters mentioned in
the beginning of this manual page.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/init_stub.xml b/lib/kernel/doc/src/init_stub.xml
index df89b174ca..1297c8264d 100644
--- a/lib/kernel/doc/src/init_stub.xml
+++ b/lib/kernel/doc/src/init_stub.xml
@@ -34,6 +34,6 @@
<modulesummary>Coordination of system startup.</modulesummary>
<description>
<p>This module is moved to the
- <seealso marker="erts:init"><c>ERTS</c></seealso> application.</p>
+ <seealso marker="erts:init">ERTS</seealso> application.</p>
</description>
</erlref>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 9e6fb60bb7..df681a505f 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -31,12 +31,12 @@
<app>kernel</app>
<appsummary>The Kernel application.</appsummary>
<description>
- <p>The <c>Kernel</c> application has all the code necessary to run
+ <p>The Kernel application has all the code necessary to run
the Erlang runtime system: file servers, code servers,
and so on.</p>
- <p>The <c>Kernel</c> application is the first application started. It is
+ <p>The Kernel application is the first application started. It is
mandatory in the sense that the minimal system based on
- Erlang/OTP consists of <c>Kernel</c> and <c>STDLIB</c>. <c>Kernel</c>
+ Erlang/OTP consists of Kernel and STDLIB. Kernel
contains the following functional areas:</p>
<list type="bulleted">
<item>Start, stop, supervision, configuration, and distribution of applications</item>
@@ -53,13 +53,13 @@
<section>
<title>Error Logger Event Handlers</title>
<p>Two standard error logger event handlers are defined in
- the <c>Kernel</c> application. These are described in
+ the Kernel application. These are described in
<seealso marker="error_logger"><c>error_logger(3)</c></seealso>.</p>
</section>
<section>
<title>Configuration</title>
- <p>The following configuration parameters are defined for the <c>Kernel</c>
+ <p>The following configuration parameters are defined for the Kernel
application. For more information about configuration parameters,
see file <seealso marker="app"><c>app(4)</c></seealso>.</p>
<taglist>
@@ -162,8 +162,8 @@
depth to which terms are printed by the error logger event
handlers included in OTP. This
configuration parameter is used by the two event handlers
- defined by the <c>Kernel</c> application and the two event
- handlers in the <c>SASL</c> application.
+ defined by the Kernel application and the two event
+ handlers in the SASL application.
(If you have implemented your own error handlers, this configuration
parameter has no effect on them.)</p>
@@ -173,7 +173,7 @@
<c>~P</c> and <c>~W</c>, respectively, and <c>Depth</c> is
used as the depth parameter. For details, see
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in <c>STDLIB</c>.</p>
+ in STDLIB.</p>
<note><p>A reasonable starting value for <c>Depth</c> is
<c>30</c>. We recommend to test crashing various processes in your
@@ -217,12 +217,14 @@
</item>
<tag><c>{inet_dist_listen_options, Opts}</c></tag>
<item>
+ <marker id="inet_dist_listen_options"></marker>
<p>Defines a list of extra socket options to be used when opening the
listening socket for a distributed Erlang node.
See <seealso marker="gen_tcp#listen/2"><c>gen_tcp:listen/2</c></seealso>.</p>
</item>
<tag><c>{inet_dist_connect_options, Opts}</c></tag>
<item>
+ <marker id="inet_dist_connect_options"></marker>
<p>Defines a list of extra socket options to be used when connecting to
other distributed Erlang nodes.
See <seealso marker="gen_tcp#connect/4"><c>gen_tcp:connect/4</c></seealso>.</p>
@@ -239,7 +241,7 @@
<p>The name (string) of an Inet user configuration file. For details,
see section
<seealso marker="erts:inet_cfg"><c>Inet Configuration</c></seealso>
- in the <c>ERTS</c> User's Guide.</p>
+ in the ERTS User's Guide.</p>
</item>
<tag><c>net_setuptime = SetupTime</c></tag>
<item>
@@ -358,7 +360,7 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_timer = true | false</c></tag>
<item>
<p>Starts the <c>timer_server</c> if the parameter is
- <c>true</c> (see <seealso marker="stdlib:timer"><c>stdlib:timer(3)</c></seealso>).
+ <c>true</c> (see <seealso marker="stdlib:timer"><c>timer(3)</c></seealso>).
This parameter is to be set to <c>true</c> in an embedded system
using this service.</p>
<p>Defaults to <c>false</c>.</p>
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index f48a534d4f..4e2b0c69db 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -55,7 +55,7 @@ $ <input>erl -sname foobar</input></pre>
<seealso marker="erts:erl"><c>erl</c></seealso>.</p>
<p>Normally, connections are established automatically when
another node is referenced. This functionality can be disabled
- by setting <c>Kernel</c> configuration parameter
+ by setting Kernel configuration parameter
<c>dist_auto_connect</c> to <c>false</c>, see
<seealso marker="kernel_app"><c>kernel(6)</c></seealso>. In this case,
connections must be established explicitly by calling
@@ -116,6 +116,21 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
+ <name name="getopts" arity="2"/>
+ <fsummary>Get distribution socket options.</fsummary>
+ <desc>
+ <p>Get one or more options for the distribution socket
+ connected to <c><anno>Node</anno></c>.</p>
+ <p>If <c><anno>Node</anno></c> is a connected node
+ the return value is the same as from
+ <seealso marker="inet#getopts/2"><c>inet:getopts(Sock, Options)</c></seealso>
+ where <c>Sock</c> is the distribution socket for <c><anno>Node</anno></c>.</p>
+ <p>Returns <c>ignored</c> if the local node is not alive or
+ <c>{error, noconnection}</c> if <c><anno>Node</anno></c> is not connected.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="monitor_nodes" arity="1"/>
<name name="monitor_nodes" arity="2"/>
<fsummary>Subscribe to node status change messages.</fsummary>
@@ -131,7 +146,7 @@ $ <input>erl -sname foobar</input></pre>
are stopped. Two
option lists are considered the same if they contain the same
set of options.</p>
- <p>As from <c>Kernel</c> version 2.11.4, and <c>ERTS</c> version
+ <p>As from Kernel version 2.11.4, and ERTS version
5.5.4, the following is guaranteed:</p>
<list type="bulleted">
<item><p><c>nodeup</c> messages are delivered before delivery
@@ -141,13 +156,13 @@ $ <input>erl -sname foobar</input></pre>
messages from the remote node that have been passed
through the connection have been delivered.</p></item>
</list>
- <p>Notice that this is <em>not</em> guaranteed for <c>Kernel</c>
+ <p>Notice that this is <em>not</em> guaranteed for Kernel
versions before 2.11.4.</p>
- <p>As from <c>Kernel</c> version 2.11.4, subscriptions can also be
+ <p>As from Kernel version 2.11.4, subscriptions can also be
made before the <c>net_kernel</c> server is started, that is,
<c>net_kernel:monitor_nodes/[1,2]</c> does not return
<c>ignored</c>.</p>
- <p>As from <c>Kernel</c> version 2.13, and <c>ERTS</c> version
+ <p>As from Kernel version 2.13, and ERTS version
5.7, the following is guaranteed:</p>
<list type="bulleted">
<item><p><c>nodeup</c> messages are delivered after the
@@ -157,7 +172,7 @@ $ <input>erl -sname foobar</input></pre>
corresponding node has disappeared in results from
<c>erlang:nodes/X</c>.</p></item>
</list>
- <p>Notice that this is <em>not</em> guaranteed for <c>Kernel</c>
+ <p>Notice that this is <em>not</em> guaranteed for Kernel
versions before 2.13.</p>
<p>The format of the node status change messages depends on
<c><anno>Options</anno></c>. If <c><anno>Options</anno></c> is
@@ -289,6 +304,27 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
+ <name name="setopts" arity="2"/>
+ <fsummary>Set distribution socket options.</fsummary>
+ <desc>
+ <p>Set one or more options for distribution sockets.
+ Argument <c><anno>Node</anno></c> can be either one node name
+ or the atom <c>new</c> to affect the distribution sockets of all
+ future connected nodes.</p>
+ <p>The return value is the same as from
+ <seealso marker="inet#setopts/2"><c>inet:setopts/2</c></seealso>
+ or <c>{error, noconnection}</c> if <c><anno>Node</anno></c> is not
+ a connected node or <c>new</c>.</p>
+ <p>If <c><anno>Node</anno></c> is <c>new</c> the <c><anno>Options</anno></c>
+ will then also be added to kernel configration parameters
+ <seealso marker="kernel:kernel_app#inet_dist_listen_options">inet_dist_listen_options</seealso>
+ and
+ <seealso marker="kernel:kernel_app#inet_dist_connect_options">inet_dist_connect_options</seealso>.</p>
+ <p>Returns <c>ignored</c> if the local node is not alive.</p>
+ </desc>
+ </func>
+
+ <func>
<name>start([Name]) -> {ok, pid()} | {error, Reason}</name>
<name>start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name>
<name>start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index f37433110c..c6d7b00e24 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,201 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 5.2.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add <c>os:cmd/2</c> that takes an options map as the
+ second argument.</p>
+ <p>
+ Add <c>max_size</c> as an option to <c>os:cmd/2</c> that
+ control the maximum size of the result that
+ <c>os:cmd/2</c> will return.</p>
+ <p>
+ Own Id: OTP-14823</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a race during cleanup of os:cmd that would cause
+ os:cmd to hang indefinitely.</p>
+ <p>
+ Own Id: OTP-14232 Aux Id: seq13275 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>The functions in the '<c>file</c>' module that take a
+ list of paths (e.g. <c>file:path_consult/2</c>) will now
+ continue to search in the path if the path contains
+ something that is not a directory.</p>
+ <p>
+ Own Id: OTP-14191</p>
+ </item>
+ <item>
+ <p>Two OTP processes that are known to receive many
+ messages are 'rex' (used by 'rpc') and 'error_logger'.
+ Those processes will now store unprocessed messages
+ outside the process heap, which will potentially decrease
+ the cost of garbage collections.</p>
+ <p>
+ Own Id: OTP-14192</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>code:add_pathsa/1</c> and command line option
+ <c>-pa</c> both revert the given list of directories when
+ adding it at the beginning of the code path. This is now
+ documented.</p>
+ <p>
+ Own Id: OTP-13920 Aux Id: ERL-267 </p>
+ </item>
+ <item>
+ <p>
+ Add lost runtime dependency to erts-8.1. This should have
+ been done in kernel-5.1 (OTP-19.1) as it cannot run
+ without at least erts-8.1 (OTP-19.1).</p>
+ <p>
+ Own Id: OTP-14003</p>
+ </item>
+ <item>
+ <p>
+ Type and doc for gen_{tcp,udp,sctp}:controlling_process/2
+ has been improved.</p>
+ <p>
+ Own Id: OTP-14022 Aux Id: PR-1208 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a memory leak when calling
+ seq_trace:get_system_tracer().</p>
+ <p>
+ Own Id: OTP-13742</p>
+ </item>
+ <item>
+ <p>
+ Fix for the problem that when adding the ebin directory
+ of an application to the code path, the
+ <c>code:priv_dir/1</c> function returns an incorrect path
+ to the priv directory of the same application.</p>
+ <p>
+ Own Id: OTP-13758 Aux Id: ERL-195 </p>
+ </item>
+ <item>
+ <p>
+ Fix code_server crash when adding code paths of two
+ levels.</p>
+ <p>
+ Own Id: OTP-13765 Aux Id: ERL-194 </p>
+ </item>
+ <item>
+ <p>
+ Respect -proto_dist switch while connection to EPMD</p>
+ <p>
+ Own Id: OTP-13770 Aux Id: PR-1129 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug where init:stop could deadlock if a process
+ with infinite shutdown timeout (e.g. a supervisor)
+ attempted to load code while terminating.</p>
+ <p>
+ Own Id: OTP-13802</p>
+ </item>
+ <item>
+ <p>
+ Close stdin of commands run in os:cmd. This is a
+ backwards compatiblity fix that restores the behaviour of
+ pre 19.0 os:cmd.</p>
+ <p>
+ Own Id: OTP-13867 Aux Id: seq13178 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add <c>net_kernel:setopts/2</c> and
+ <c>net_kernel:getopts/2</c> to control options for
+ distribution sockets in runtime.</p>
+ <p>
+ Own Id: OTP-13564</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When calling os:cmd from a process that has set trap_exit
+ to true an 'EXIT' message would be left in the message
+ queue. This bug was introduced in kernel vsn 5.0.1.</p>
+ <p>
+ Own Id: OTP-13813</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a os:cmd bug where creating a background job using
+ &amp; would cause os:cmd to hang until the background job
+ terminated or closed its stdout and stderr file
+ descriptors. This bug has existed from kernel 5.0.</p>
+ <p>
+ Own Id: OTP-13741</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 5.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -3447,7 +3642,7 @@
types (for instance, <c>ensure_loaded/1</c> now only
accepts an atom as documented; it used to accept a string
too).</p>
- <p><c>Dialyzer</c> will generally emit warnings for any
+ <p>Dialyzer will generally emit warnings for any
calls that use undocumented argument types. Even if the
call happens to still work in R12B, you should correct
your code. A future release will adhere to the
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index 739ac35d2a..a6a63448b7 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -38,17 +38,35 @@
most platforms.</p>
</description>
+ <datatypes>
+ <datatype>
+ <name name="os_command"/>
+ </datatype>
+ <datatype>
+ <name name="os_command_opts"/>
+ <desc>
+ <p>Options for <seealso marker="#cmd/2"><c>os:cmd/2</c></seealso></p>
+ <taglist>
+ <tag><c>max_size</c></tag>
+ <item>
+ <p>The maximum size of the data returned by the <c>os:cmd</c> call.
+ See the <seealso marker="#cmd/2"><c>os:cmd/2</c></seealso>
+ documentation for more details.</p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ </datatypes>
+
<funcs>
<func>
<name name="cmd" arity="1"/>
+ <name name="cmd" arity="2"/>
<fsummary>Execute a command in a shell of the target OS.</fsummary>
<desc>
<p>Executes <c><anno>Command</anno></c> in a command shell of the
- target OS,
- captures the standard output of the command, and returns this
- result as a string. This function is a replacement of
- the previous function <c>unix:cmd/1</c>; they are equivalent on a
- Unix platform.</p>
+ target OS, captures the standard output of the command,
+ and returns this result as a string.</p>
<p><em>Examples:</em></p>
<code type="none">
LsOut = os:cmd("ls"), % on unix platform
@@ -57,6 +75,21 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
called from another program (for example, <c>os:cmd/1</c>)
can differ, compared with the standard output of the command
when called directly from an OS command shell.</p>
+ <p><c>os:cmd/2</c> was added in kernel-5.5 (OTP-20.2.1). It makes it
+ possible to pass an options map as the second argument in order to
+ control the behaviour of <c>os:cmd</c>. The possible options are:
+ </p>
+ <taglist>
+ <tag><c>max_size</c></tag>
+ <item>
+ <p>The maximum size of the data returned by the <c>os:cmd</c> call.
+ This option is a safety feature that should be used when the command
+ executed can return a very large, possibly infinite, result.</p>
+ <code type="none">
+> os:cmd("cat /dev/zero", #{ max_size => 20 }).
+[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]</code>
+ </item>
+ </taglist>
</desc>
</func>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index 8cad9fe4fc..adec2d9520 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -88,6 +88,12 @@
to retrieve the value of evaluating <c>apply(<anno>Module</anno>,
<anno>Function</anno>, <anno>Args</anno>)</c> on node
<c><anno>Node</anno></c>.</p>
+ <note>
+ <p><seealso marker="#yield/1"><c>yield/1</c></seealso> and
+ <seealso marker="#nb_yield/1"><c>nb_yield/1,2</c></seealso>
+ must be called by the same process from which this function
+ was made otherwise they will never yield correctly.</p>
+ </note>
</desc>
</func>
@@ -299,6 +305,11 @@
the tuple <c>{value, <anno>Val</anno>}</c> when the computation is
finished, or <c>timeout</c> when <c><anno>Timeout</anno></c>
milliseconds has elapsed.</p>
+ <note>
+ <p>This function must be called by the same process from which
+ <seealso marker="#async_call/4"><c>async_call/4</c></seealso>
+ was made otherwise it will only return <c>timeout</c>.</p>
+ </note>
</desc>
</func>
@@ -320,7 +331,7 @@
<fsummary>Information about a process.</fsummary>
<desc>
<p>Location transparent version of the BIF
- <seealso marker="erts:erlang#process_info/1"><c>erlang:process_info/1</c></seealso> in <c>ERTS</c>.</p>
+ <seealso marker="erts:erlang#process_info/1"><c>erlang:process_info/1</c></seealso> in ERTS.</p>
</desc>
</func>
@@ -330,7 +341,7 @@
<fsummary>Information about a process.</fsummary>
<desc>
<p>Location transparent version of the BIF
- <seealso marker="erts:erlang#process_info/2"><c>erlang:process_info/2</c></seealso> in <c>ERTS</c>.</p>
+ <seealso marker="erts:erlang#process_info/2"><c>erlang:process_info/2</c></seealso> in ERTS.</p>
</desc>
</func>
@@ -407,6 +418,11 @@
If the answer is available, it is
returned immediately. Otherwise, the calling process is
suspended until the answer arrives from <c>Node</c>.</p>
+ <note>
+ <p>This function must be called by the same process from which
+ <seealso marker="#async_call/4"><c>async_call/4</c></seealso>
+ was made otherwise it will never return.</p>
+ </note>
</desc>
</func>
</funcs>
diff --git a/lib/kernel/doc/src/zlib_stub.xml b/lib/kernel/doc/src/zlib_stub.xml
index b111581b10..9ab9c4eb62 100644
--- a/lib/kernel/doc/src/zlib_stub.xml
+++ b/lib/kernel/doc/src/zlib_stub.xml
@@ -34,6 +34,6 @@
<modulesummary>Zlib compression interface.</modulesummary>
<description>
<p>This module is moved to the
- <seealso marker="erts:zlib"><c>ERTS</c></seealso> application.</p>
+ <seealso marker="erts:zlib">ERTS</seealso> application.</p>
</description>
</erlref>
diff --git a/lib/kernel/include/dist_util.hrl b/lib/kernel/include/dist_util.hrl
index 43e50d4325..320e916c04 100644
--- a/lib/kernel/include/dist_util.hrl
+++ b/lib/kernel/include/dist_util.hrl
@@ -63,7 +63,7 @@
f_getll, %% Get low level port or pid.
f_address, %% The address of the "socket",
%% generated from Socket,Node
- %% These two are used in the tick loop,
+ %% These three are used in the tick loop,
%% so they are not fun's to avoid holding old code.
mf_tick, %% Takes the socket as parameters and
%% sends a tick, this is no fun, it
@@ -74,7 +74,11 @@
%% {ok, RecvCnt, SendCnt, SendPend} for
%% a given socket. This is a {M,F},
%% returning {error, Reason on failure}
- request_type = normal
+ request_type = normal,
+
+ %% New in kernel-5.1 (OTP 19.1):
+ mf_setopts, %% netkernel:setopts on active connection
+ mf_getopts %% netkernel:getopts on active connection
}).
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 6174136507..59b26176bf 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -135,10 +135,14 @@ split_paths([], _S, Path, Paths) ->
-spec call(term()) -> term().
call(Req) ->
+ Ref = erlang:monitor(process, ?MODULE),
?MODULE ! {code_call, self(), Req},
receive
{?MODULE, Reply} ->
- Reply
+ erlang:demonitor(Ref,[flush]),
+ Reply;
+ {'DOWN',Ref,process,_,_} ->
+ exit({'DOWN',code_server,Req})
end.
reply(Pid, Res) ->
@@ -807,7 +811,13 @@ clear_namedb([], _) ->
%% Dir must be a complete pathname (not only a name).
insert_dir(Dir, Db) ->
Splitted = filename:split(Dir),
- Name = get_name_from_splitted(Splitted),
+ case get_name_from_splitted(Splitted) of
+ Name when Name /= "ebin", Name /= "." ->
+ Name;
+ _ ->
+ SplittedAbsName = filename:split(absname(Dir)),
+ Name = get_name_from_splitted(SplittedAbsName)
+ end,
AppDir = filename:join(del_ebin_1(Splitted)),
do_insert_name(Name, AppDir, Db).
@@ -933,15 +943,25 @@ del_ebin(Dir) ->
filename:join(del_ebin_1(filename:split(Dir))).
del_ebin_1([Parent,App,"ebin"]) ->
- Ext = archive_extension(),
- case filename:basename(Parent, Ext) of
- Parent ->
- %% Plain directory.
+ case filename:basename(Parent) of
+ [] ->
+ %% Parent is the root directory
[Parent,App];
- Archive ->
- %% Archive.
- [Archive]
+ _ ->
+ Ext = archive_extension(),
+ case filename:basename(Parent, Ext) of
+ Parent ->
+ %% Plain directory.
+ [Parent,App];
+ Archive ->
+ %% Archive.
+ [Archive]
+ end
end;
+del_ebin_1(Path = [_App,"ebin"]) ->
+ del_ebin_1(filename:split(absname(filename:join(Path))));
+del_ebin_1(["ebin"]) ->
+ del_ebin_1(filename:split(absname("ebin")));
del_ebin_1([H|T]) ->
[H|del_ebin_1(T)];
del_ebin_1([]) ->
@@ -1372,11 +1392,10 @@ finish_on_load(PidRef, OnLoadRes, #state{on_load=OnLoad0}=St0) ->
finish_on_load_1(Mod, OnLoadRes, Waiting, St) ->
Keep = OnLoadRes =:= ok,
- erlang:finish_after_on_load(Mod, Keep),
+ erts_code_purger:finish_after_on_load(Mod, Keep),
Res = case Keep of
false ->
_ = finish_on_load_report(Mod, OnLoadRes),
- _ = erts_code_purger:purge(Mod),
{error,on_load_failure};
true ->
{module,Mod}
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index 47d0c1b861..8d2fc4d4b7 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -143,7 +143,11 @@ handshake_other_started(#hs_data{request_type=ReqType}=HSData0) ->
ChallengeB = recv_challenge_reply(HSData, ChallengeA, MyCookie),
send_challenge_ack(HSData, gen_digest(ChallengeB, HisCookie)),
?debug({dist_util, self(), accept_connection, Node}),
- connection(HSData).
+ connection(HSData);
+
+handshake_other_started(OldHsData) when element(1,OldHsData) =:= hs_data ->
+ handshake_other_started(convert_old_hsdata(OldHsData)).
+
%%
%% check if connecting node is allowed to connect
@@ -330,7 +334,20 @@ handshake_we_started(#hs_data{request_type=ReqType,
gen_digest(ChallengeA,HisCookie)),
reset_timer(NewHSData#hs_data.timer),
recv_challenge_ack(NewHSData, MyChallenge, MyCookie),
- connection(NewHSData).
+ connection(NewHSData);
+
+handshake_we_started(OldHsData) when element(1,OldHsData) =:= hs_data ->
+ handshake_we_started(convert_old_hsdata(OldHsData)).
+
+convert_old_hsdata({hs_data, KP, ON, TN, S, T, TF, A, OV, OF, OS, FS, FR,
+ FS_PRE, FS_POST, FG, FA, MFT, MFG, RT}) ->
+ #hs_data{
+ kernel_pid = KP, other_node = ON, this_node = TN, socket = S, timer = T,
+ this_flags = TF, allowed = A, other_version = OV, other_flags = OF,
+ other_started = OS, f_send = FS, f_recv = FR, f_setopts_pre_nodeup = FS_PRE,
+ f_setopts_post_nodeup = FS_POST, f_getll = FG, f_address = FA,
+ mf_tick = MFT, mf_getstat = MFG, request_type = RT}.
+
%% --------------------------------------------------------------
%% The connection has been established.
@@ -350,15 +367,15 @@ connection(#hs_data{other_node = Node,
mark_nodeup(HSData,Address),
case FPostNodeup(Socket) of
ok ->
- con_loop(HSData#hs_data.kernel_pid,
- Node,
- Socket,
- Address,
- HSData#hs_data.this_node,
- PType,
- #tick{},
- HSData#hs_data.mf_tick,
- HSData#hs_data.mf_getstat);
+ con_loop({HSData#hs_data.kernel_pid,
+ Node,
+ Socket,
+ PType,
+ HSData#hs_data.mf_tick,
+ HSData#hs_data.mf_getstat,
+ HSData#hs_data.mf_setopts,
+ HSData#hs_data.mf_getopts},
+ #tick{});
_ ->
?shutdown2(Node, connection_setup_failed)
end;
@@ -454,8 +471,8 @@ mark_nodeup(#hs_data{kernel_pid = Kernel,
?shutdown(Node)
end.
-con_loop(Kernel, Node, Socket, TcpAddress,
- MyNode, Type, Tick, MFTick, MFGetstat) ->
+con_loop({Kernel, Node, Socket, Type, MFTick, MFGetstat, MFSetOpts, MFGetOpts}=ConData,
+ Tick) ->
receive
{tcp_closed, Socket} ->
?shutdown2(Node, connection_closed);
@@ -468,15 +485,12 @@ con_loop(Kernel, Node, Socket, TcpAddress,
_ ->
ignore_it
end,
- con_loop(Kernel, Node, Socket, TcpAddress, MyNode, Type,
- Tick, MFTick, MFGetstat);
+ con_loop(ConData, Tick);
{Kernel, tick} ->
case send_tick(Socket, Tick, Type,
MFTick, MFGetstat) of
{ok, NewTick} ->
- con_loop(Kernel, Node, Socket, TcpAddress,
- MyNode, Type, NewTick, MFTick,
- MFGetstat);
+ con_loop(ConData, NewTick);
{error, not_responding} ->
error_msg("** Node ~p not responding **~n"
"** Removing (timedout) connection **~n",
@@ -489,13 +503,24 @@ con_loop(Kernel, Node, Socket, TcpAddress,
case MFGetstat(Socket) of
{ok, Read, Write, _} ->
From ! {self(), get_status, {ok, Read, Write}},
- con_loop(Kernel, Node, Socket, TcpAddress,
- MyNode,
- Type, Tick,
- MFTick, MFGetstat);
+ con_loop(ConData, Tick);
_ ->
?shutdown2(Node, get_status_failed)
- end
+ end;
+ {From, Ref, {setopts, Opts}} ->
+ Ret = case MFSetOpts of
+ undefined -> {error, enotsup};
+ _ -> MFSetOpts(Socket, Opts)
+ end,
+ From ! {Ref, Ret},
+ con_loop(ConData, Tick);
+ {From, Ref, {getopts, Opts}} ->
+ Ret = case MFGetOpts of
+ undefined -> {error, enotsup};
+ _ -> MFGetOpts(Socket, Opts)
+ end,
+ From ! {Ref, Ret},
+ con_loop(ConData, Tick)
end.
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index f8ef4a475d..7bc9e2ede3 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -103,6 +103,10 @@ names(EpmdAddr) ->
register_node(Name, PortNo) ->
register_node(Name, PortNo, inet).
+register_node(Name, PortNo, inet_tcp) ->
+ register_node(Name, PortNo, inet);
+register_node(Name, PortNo, inet6_tcp) ->
+ register_node(Name, PortNo, inet6);
register_node(Name, PortNo, Family) ->
gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
@@ -403,8 +407,6 @@ select_best_version(L1, _H1, _L2, H2) when L1 > H2 ->
0;
select_best_version(_L1, H1, L2, _H2) when L2 > H1 ->
0;
-select_best_version(_L1, H1, L2, _H2) when L2 > H1 ->
- 0;
select_best_version(_L1, H1, _L2, H2) ->
erlang:min(H1, H2).
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index 3523f680a3..81f1bf8d97 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -360,8 +360,12 @@ init(Max) when is_integer(Max) ->
%% go back.
init({go_back, _PostState}) ->
{ok, {?buffer_size, 0, []}};
-init(_) -> %% Start and just relay to other
- {ok, []}. %% node if node(GLeader) =/= node().
+init(_) ->
+ %% The error logger process may receive a huge amount of
+ %% messages. Make sure that they are stored off heap to
+ %% avoid exessive GCs.
+ process_flag(message_queue_data, off_heap),
+ {ok, []}.
-spec handle_event(term(), state()) -> {'ok', state()}.
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 58b601e456..6d94f7770f 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -1413,7 +1413,7 @@ path_open_first([Path|Rest], Name, Mode, LastError) ->
case open(FileName, Mode) of
{ok, Fd} ->
{ok, Fd, FileName};
- {error, enoent} ->
+ {error, Reason} when Reason =:= enoent; Reason =:= enotdir ->
path_open_first(Rest, Name, Mode, LastError);
Error ->
Error
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index b133e6fed4..a6aa0edd15 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -439,7 +439,7 @@ error_string(X) ->
-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: sctp_socket(),
Pid :: pid(),
- Reason :: closed | not_owner | inet:posix().
+ Reason :: closed | not_owner | badarg | inet:posix().
controlling_process(S, Pid) when is_port(S), is_pid(Pid) ->
inet:udp_controlling_process(S, Pid);
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 1a21541b7c..ac61dbc792 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -320,7 +320,7 @@ unrecv(S, Data) when is_port(S) ->
-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: socket(),
Pid :: pid(),
- Reason :: closed | not_owner | inet:posix().
+ Reason :: closed | not_owner | badarg | inet:posix().
controlling_process(S, NewOwner) ->
case inet_db:lookup_socket(S) of
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 98d2f0bcfb..3121544719 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -195,7 +195,7 @@ connect(S, Address, Port) when is_port(S) ->
-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: socket(),
Pid :: pid(),
- Reason :: closed | not_owner | inet:posix().
+ Reason :: closed | not_owner | badarg | inet:posix().
controlling_process(S, NewOwner) ->
inet:udp_controlling_process(S, NewOwner).
diff --git a/lib/kernel/src/global_group.erl b/lib/kernel/src/global_group.erl
index 8ac0bd9551..f5ead2a4c5 100644
--- a/lib/kernel/src/global_group.erl
+++ b/lib/kernel/src/global_group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index eea78aabdf..8fa48d56fb 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -198,16 +198,11 @@ start_portprogram() ->
end.
get_heart_timeouts() ->
- HeartOpts = case os:getenv("HEART_BEAT_TIMEOUT") of
- false -> "";
- H when is_list(H) ->
- "-ht " ++ H
- end,
- HeartOpts ++ case os:getenv("HEART_BEAT_BOOT_DELAY") of
- false -> "";
- W when is_list(W) ->
- " -wt " ++ W
- end.
+ case os:getenv("HEART_BEAT_TIMEOUT") of
+ false -> "";
+ H when is_list(H) ->
+ "-ht " ++ H
+ end.
check_start_heart() ->
case init:get_argument(heart) of
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index a91a6ed517..f5c13ecdd7 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -75,6 +75,7 @@
-export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
local_address/0, socket_address/0, returned_non_ip_address/0,
+ socket_setopt/0, socket_getopt/0,
posix/0, socket/0, stat_option/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -676,7 +677,7 @@ parse_strict_address(Addr) ->
%% Return a list of available options
options() ->
[
- tos, priority, reuseaddr, keepalive, dontroute, linger,
+ tos, tclass, priority, reuseaddr, keepalive, dontroute, linger,
broadcast, sndbuf, recbuf, nodelay, ipv6_v6only,
buffer, header, active, packet, deliver, mode,
multicast_if, multicast_ttl, multicast_loop,
@@ -697,7 +698,7 @@ stats() ->
%% Available options for tcp:connect
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
- [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
@@ -765,7 +766,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
%% Available options for tcp:listen
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_options() ->
- [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
@@ -845,7 +846,7 @@ tcp_module_1(Opts, Address) ->
%% Available options for udp:open
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
udp_options() ->
- [tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
+ [tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw,
@@ -916,7 +917,7 @@ udp_module(Opts) ->
% (*) passing of open FDs ("fdopen") is not supported.
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
- mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
+ mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf,
recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
% Other options are SCTP-specific (though they may be similar to their
diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
index 3aa61973af..9b6c2745d5 100644
--- a/lib/kernel/src/inet6_tcp_dist.erl
+++ b/lib/kernel/src/inet6_tcp_dist.erl
@@ -24,6 +24,7 @@
-export([listen/1, accept/1, accept_connection/5,
setup/5, close/1, select/1, is_node_name/1]).
+-export([setopts/2, getopts/2]).
%% ------------------------------------------------------------
%% Select this protocol based on node name
@@ -72,3 +73,9 @@ close(Socket) ->
is_node_name(Node) when is_atom(Node) ->
inet_tcp_dist:is_node_name(Node).
+
+setopts(S, Opts) ->
+ inet_tcp_dist:setopts(S, Opts).
+
+getopts(S, Opts) ->
+ inet_tcp_dist:getopts(S, Opts).
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index c8a8962e78..4e8f59a3b9 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -153,6 +153,7 @@
-define(INET_LOPT_NETNS, 38).
-define(INET_LOPT_TCP_SHOW_ECONNRESET, 39).
-define(INET_LOPT_LINE_DELIM, 40).
+-define(INET_OPT_TCLASS, 41).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index f91d7ef7c3..8c8fe86811 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,13 +24,16 @@
-export([listen/1, accept/1, accept_connection/5,
setup/5, close/1, select/1, is_node_name/1]).
+%% Optional
+-export([setopts/2, getopts/2]).
+
%% Generalized dist API
-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
gen_setup/6, gen_select/2]).
%% internal exports
--export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]).
+-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1,tick/2]).
-import(error_logger,[error_msg/2]).
@@ -74,7 +77,7 @@ gen_listen(Driver, Name) ->
TcpAddress = get_tcp_address(Driver, Socket),
{_,Port} = TcpAddress#net_address.address,
ErlEpmd = net_kernel:epmd_module(),
- case ErlEpmd:register_node(Name, Port) of
+ case ErlEpmd:register_node(Name, Port, Driver) of
{ok, Creation} ->
{ok, {Socket, TcpAddress, Creation}};
Error ->
@@ -215,8 +218,10 @@ do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
inet:getll(S)
end,
f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end,
- mf_tick = fun(S) -> tick(Driver, S) end,
- mf_getstat = fun ?MODULE:getstat/1
+ mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end,
+ mf_getstat = fun ?MODULE:getstat/1,
+ mf_setopts = fun ?MODULE:setopts/2,
+ mf_getopts = fun ?MODULE:getopts/2
},
dist_util:handshake_other_started(HSData);
{false,IP} ->
@@ -320,6 +325,7 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
{packet, 4},
nodelay()])
end,
+
f_getll = fun inet:getll/1,
f_address =
fun(_,_) ->
@@ -329,9 +335,11 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
protocol = tcp,
family = AddressFamily}
end,
- mf_tick = fun(S) -> tick(Driver, S) end,
+ mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end,
mf_getstat = fun ?MODULE:getstat/1,
- request_type = Type
+ request_type = Type,
+ mf_setopts = fun ?MODULE:setopts/2,
+ mf_getopts = fun ?MODULE:getopts/2
},
dist_util:handshake_we_started(HSData);
_ ->
@@ -492,3 +500,12 @@ split_stat([], R, W, P) ->
{ok, R, W, P}.
+setopts(S, Opts) ->
+ case [Opt || {K,_}=Opt <- Opts,
+ K =:= active orelse K =:= deliver orelse K =:= packet] of
+ [] -> inet:setopts(S,Opts);
+ Opts1 -> {error, {badopts,Opts1}}
+ end.
+
+getopts(S, Opts) ->
+ inet:getopts(S, Opts).
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 56d1699656..d184223524 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -118,6 +118,6 @@
{applications, []},
{env, [{error_logger, tty}]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-8.0", "stdlib-3.0", "sasl-3.0"]}
+ {runtime_dependencies, ["erts-8.1", "stdlib-3.0", "sasl-3.0"]}
]
}.
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index d16e200cb3..e1173cd2f4 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"5\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
+ [{<<"5\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-18.*
%% Down to - max one major revision back
- [{<<"5\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
+ [{<<"5\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-18.*
}.
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index ac19f4935b..0c679e7349 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -59,6 +59,8 @@
connect_node/1,
monitor_nodes/1,
monitor_nodes/2,
+ setopts/2,
+ getopts/2,
start/1,
stop/0]).
@@ -111,7 +113,7 @@
}).
-record(listen, {
- listen, %% listen pid
+ listen, %% listen socket
accept, %% accepting pid
address, %% #net_address
module %% proto module
@@ -384,7 +386,7 @@ init({Name, LongOrShortNames, TickT, CleanHalt}) ->
connections =
ets:new(sys_dist,[named_table,
protected,
- {keypos, 2}]),
+ {keypos, #connection.node}]),
listen = Listeners,
allowed = [],
verbose = 0
@@ -554,6 +556,38 @@ handle_call({new_ticktime,_T,_TP},
#state{tick = #tick_change{time = T}} = State) ->
async_reply({reply, {ongoing_change_to, T}, State}, From);
+handle_call({setopts, new, Opts}, From, State) ->
+ Ret = setopts_new(Opts, State),
+ async_reply({reply, Ret, State}, From);
+
+handle_call({setopts, Node, Opts}, From, State) ->
+ Return =
+ case ets:lookup(sys_dist, Node) of
+ [Conn] when Conn#connection.state =:= up ->
+ case call_owner(Conn#connection.owner, {setopts, Opts}) of
+ {ok, Ret} -> Ret;
+ _ -> {error, noconnection}
+ end;
+
+ _ ->
+ {error, noconnection}
+ end,
+ async_reply({reply, Return, State}, From);
+
+handle_call({getopts, Node, Opts}, From, State) ->
+ Return =
+ case ets:lookup(sys_dist, Node) of
+ [Conn] when Conn#connection.state =:= up ->
+ case call_owner(Conn#connection.owner, {getopts, Opts}) of
+ {ok, Ret} -> Ret;
+ _ -> {error, noconnection}
+ end;
+
+ _ ->
+ {error, noconnection}
+ end,
+ async_reply({reply, Return, State}, From);
+
handle_call(_Msg, _From, State) ->
{noreply, State}.
@@ -1608,3 +1642,93 @@ async_gen_server_reply(From, Msg) ->
{'EXIT', _} ->
ok
end.
+
+call_owner(Owner, Msg) ->
+ Mref = monitor(process, Owner),
+ Owner ! {self(), Mref, Msg},
+ receive
+ {Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ {ok, Reply};
+ {'DOWN', Mref, _, _, _} ->
+ error
+ end.
+
+
+-spec setopts(Node, Options) -> ok | {error, Reason} | ignored when
+ Node :: node() | new,
+ Options :: [inet:socket_setopt()],
+ Reason :: inet:posix() | noconnection.
+
+setopts(Node, Opts) when is_atom(Node), is_list(Opts) ->
+ request({setopts, Node, Opts}).
+
+setopts_new(Opts, State) ->
+ %% First try setopts on listening socket(s)
+ %% Bail out on failure.
+ %% If successful, we are pretty sure Opts are ok
+ %% and we continue with config params and pending connections.
+ case setopts_on_listen(Opts, State#state.listen) of
+ ok ->
+ setopts_new_1(Opts);
+ Fail -> Fail
+ end.
+
+setopts_on_listen(_, []) -> ok;
+setopts_on_listen(Opts, [#listen {listen = LSocket, module = Mod} | T]) ->
+ try Mod:setopts(LSocket, Opts) of
+ ok ->
+ setopts_on_listen(Opts, T);
+ Fail -> Fail
+ catch
+ error:undef -> {error, enotsup}
+ end.
+
+setopts_new_1(Opts) ->
+ ConnectOpts = case application:get_env(kernel, inet_dist_connect_options) of
+ {ok, CO} -> CO;
+ _ -> []
+ end,
+ application:set_env(kernel, inet_dist_connect_options,
+ merge_opts(Opts,ConnectOpts)),
+ ListenOpts = case application:get_env(kernel, inet_dist_listen_options) of
+ {ok, LO} -> LO;
+ _ -> []
+ end,
+ application:set_env(kernel, inet_dist_listen_options,
+ merge_opts(Opts, ListenOpts)),
+ case lists:keyfind(nodelay, 1, Opts) of
+ {nodelay, ND} when is_boolean(ND) ->
+ application:set_env(kernel, dist_nodelay, ND);
+ _ -> ignore
+ end,
+
+ %% Update any pending connections
+ PendingConns = ets:select(sys_dist, [{'_',
+ [{'=/=',{element,#connection.state,'$_'},up}],
+ ['$_']}]),
+ lists:foreach(fun(#connection{state = pending, owner = Owner}) ->
+ call_owner(Owner, {setopts, Opts});
+ (#connection{state = up_pending, pending_owner = Owner}) ->
+ call_owner(Owner, {setopts, Opts});
+ (_) -> ignore
+ end, PendingConns),
+ ok.
+
+merge_opts([], B) ->
+ B;
+merge_opts([H|T], B0) ->
+ {Key, _} = H,
+ B1 = lists:filter(fun({K,_}) -> K =/= Key end, B0),
+ merge_opts(T, [H | B1]).
+
+-spec getopts(Node, Options) ->
+ {'ok', OptionValues} | {'error', Reason} | ignored when
+ Node :: node(),
+ Options :: [inet:socket_getopt()],
+ OptionValues :: [inet:socket_setopt()],
+ Reason :: inet:posix() | noconnection.
+
+getopts(Node, Opts) when is_atom(Node), is_list(Opts) ->
+ request({getopts, Node, Opts}).
+
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index f0ad26b1f2..92ac401b72 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
%% Provides a common operating system interface.
--export([type/0, version/0, cmd/1, find_executable/1, find_executable/2]).
+-export([type/0, version/0, cmd/1, cmd/2, find_executable/1, find_executable/2]).
-include("file.hrl").
@@ -32,6 +32,11 @@
putenv/2, system_time/0, system_time/1,
timestamp/0, unsetenv/1]).
+-type os_command() :: atom() | io_lib:chars().
+-type os_command_opts() :: #{ max_size => non_neg_integer() | infinity }.
+
+-export_type([os_command/0, os_command_opts/0]).
+
-spec getenv() -> [string()].
getenv() -> erlang:nif_error(undef).
@@ -223,14 +228,22 @@ extensions() ->
%% Executes the given command in the default shell for the operating system.
-spec cmd(Command) -> string() when
- Command :: atom() | io_lib:chars().
+ Command :: os_command().
cmd(Cmd) ->
+ cmd(Cmd, #{ }).
+
+-spec cmd(Command, Options) -> string() when
+ Command :: os_command(),
+ Options :: os_command_opts().
+cmd(Cmd, Opts) ->
validate(Cmd),
- {SpawnCmd, SpawnOpts, SpawnInput} = mk_cmd(os:type(), Cmd),
+ {SpawnCmd, SpawnOpts, SpawnInput, Eot} = mk_cmd(os:type(), Cmd),
Port = open_port({spawn, SpawnCmd}, [binary, stderr_to_stdout,
- stream, in, eof, hide | SpawnOpts]),
+ stream, in, hide | SpawnOpts]),
+ MonRef = erlang:monitor(port, Port),
true = port_command(Port, SpawnInput),
- Bytes = get_data(Port, []),
+ Bytes = get_data(Port, MonRef, Eot, [], 0, maps:get(max_size, Opts, infinity)),
+ demonitor(MonRef, [flush]),
String = unicode:characters_to_list(Bytes),
if %% Convert to unicode list if possible otherwise return bytes
is_list(String) -> String;
@@ -243,7 +256,7 @@ mk_cmd({win32,Wtype}, Cmd) ->
{false,_} -> lists:concat(["cmd /c", Cmd]);
{Cspec,_} -> lists:concat([Cspec," /c",Cmd])
end,
- {Command, [], []};
+ {Command, [], [], <<>>};
mk_cmd(OsType,Cmd) when is_atom(Cmd) ->
mk_cmd(OsType, atom_to_list(Cmd));
mk_cmd(_,Cmd) ->
@@ -252,7 +265,20 @@ mk_cmd(_,Cmd) ->
{"/bin/sh -s unix:cmd", [out],
%% We insert a new line after the command, in case the command
%% contains a comment character.
- ["(", unicode:characters_to_binary(Cmd), "\n); exit\n"]}.
+ %%
+ %% The </dev/null closes stdin, which means that programs
+ %% that use a closed stdin as an termination indicator works.
+ %% An example of such a program is 'more'.
+ %%
+ %% The "echo ^D" is used to indicate that the program has executed
+ %% and we should return any output we have gotten. We cannot use
+ %% termination of the child or closing of stdin/stdout as then
+ %% starting background jobs from os:cmd will block os:cmd.
+ %%
+ %% I tried changing this to be "better", but got bombarded with
+ %% backwards incompatibility bug reports, so leave this as it is.
+ ["(", unicode:characters_to_binary(Cmd), "\n) </dev/null; echo \"\^D\"\n"],
+ <<$\^D>>}.
validate(Atom) when is_atom(Atom) ->
ok;
@@ -267,21 +293,54 @@ validate1([List|Rest]) when is_list(List) ->
validate1([]) ->
ok.
-get_data(Port, Sofar) ->
+get_data(Port, MonRef, Eot, Sofar, Size, Max) ->
receive
{Port, {data, Bytes}} ->
- get_data(Port, [Sofar,Bytes]);
- {Port, eof} ->
- Port ! {self(), close},
- receive
- {Port, closed} ->
- true
- end,
- receive
- {'EXIT', Port, _} ->
- ok
- after 1 -> % force context switch
- ok
- end,
+ case eot(Bytes, Eot, Size, Max) of
+ more ->
+ get_data(Port, MonRef, Eot, [Sofar, Bytes],
+ Size + byte_size(Bytes), Max);
+ Last ->
+ catch port_close(Port),
+ flush_until_down(Port, MonRef),
+ iolist_to_binary([Sofar, Last])
+ end;
+ {'DOWN', MonRef, _, _, _} ->
+ flush_exit(Port),
iolist_to_binary(Sofar)
end.
+
+eot(Bs, <<>>, Size, Max) when Size + byte_size(Bs) < Max ->
+ more;
+eot(Bs, <<>>, Size, Max) ->
+ binary:part(Bs, {0, Max - Size});
+eot(Bs, Eot, Size, Max) ->
+ case binary:match(Bs, Eot) of
+ {Pos, _} when Size + Pos < Max ->
+ binary:part(Bs,{0, Pos});
+ _ ->
+ eot(Bs, <<>>, Size, Max)
+ end.
+
+%% When port_close returns we know that all the
+%% messages sent have been sent and that the
+%% DOWN message is after them all.
+flush_until_down(Port, MonRef) ->
+ receive
+ {Port, {data, _Bytes}} ->
+ flush_until_down(Port, MonRef);
+ {'DOWN', MonRef, _, _, _} ->
+ flush_exit(Port)
+ end.
+
+%% The exit signal is always delivered before
+%% the down signal, so we can be sure that if there
+%% was an exit message sent, it will be in the
+%% mailbox now.
+flush_exit(Port) ->
+ receive
+ {'EXIT', Port, _} ->
+ ok
+ after 0 ->
+ ok
+ end.
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 21bff02214..0e0b7dffa3 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,17 +67,27 @@
%%------------------------------------------------------------------------
+
+%% The rex server may receive a huge amount of
+%% messages. Make sure that they are stored off heap to
+%% avoid exessive GCs.
+
+-define(SPAWN_OPTS, [{spawn_opt,[{message_queue_data,off_heap}]}]).
+
%% Remote execution and broadcasting facility
-spec start() -> {'ok', pid()} | 'ignore' | {'error', term()}.
start() ->
- gen_server:start({local,?NAME}, ?MODULE, [], []).
+ gen_server:start({local,?NAME}, ?MODULE, [], ?SPAWN_OPTS).
-spec start_link() -> {'ok', pid()} | 'ignore' | {'error', term()}.
start_link() ->
- gen_server:start_link({local,?NAME}, ?MODULE, [], []).
+ %% The rex server process may receive a huge amount of
+ %% messages. Make sure that they are stored off heap to
+ %% avoid exessive GCs.
+ gen_server:start_link({local,?NAME}, ?MODULE, [], ?SPAWN_OPTS).
-spec stop() -> term().
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 8da67c89f8..a5a5da4684 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,7 +35,9 @@
purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1,
code_archive/1, code_archive2/1, on_load/1, on_load_binary/1,
on_load_embedded/1, on_load_errors/1, on_load_update/1,
+ on_load_trace_on_load/1,
on_load_purge/1, on_load_self_call/1, on_load_pending/1,
+ on_load_deleted/1,
big_boot_embedded/1,
native_early_modules/1, get_mode/1,
normalized_paths/1]).
@@ -64,12 +66,15 @@ all() ->
ext_mod_dep, clash, where_is_file,
purge_stacktrace, mult_lib_roots,
bad_erl_libs, code_archive, code_archive2, on_load,
- on_load_binary, on_load_embedded, on_load_errors, on_load_update,
+ on_load_binary, on_load_embedded, on_load_errors,
+ {group, sequence},
on_load_purge, on_load_self_call, on_load_pending,
+ on_load_deleted,
big_boot_embedded, native_early_modules, get_mode, normalized_paths].
-groups() ->
- [].
+%% These need to run in order
+groups() -> [{sequence, [sequence], [on_load_update,
+ on_load_trace_on_load]}].
init_per_group(_GroupName, Config) ->
Config.
@@ -586,20 +591,28 @@ sticky_compiler(Files, PrivDir) ->
[R || R <- Rets, R =/= ok].
do_sticky_compile(Mod, Dir) ->
- %% Make sure that the module is loaded. A module being sticky
- %% only prevents it from begin reloaded, not from being loaded
- %% from the wrong place to begin with.
- Mod = Mod:module_info(module),
- File = filename:append(Dir, atom_to_list(Mod)),
- Src = io_lib:format("-module(~s).\n"
- "-export([test/1]).\n"
- "test(me) -> fail.\n", [Mod]),
- ok = file:write_file(File++".erl", Src),
- case c:c(File, [{outdir,Dir}]) of
- {ok,Module} ->
- Module:test(me);
- {error,sticky_directory} ->
- ok
+ case code:is_sticky(Mod) of
+ true ->
+ %% Make sure that the module is loaded. A module being sticky
+ %% only prevents it from begin reloaded, not from being loaded
+ %% from the wrong place to begin with.
+ Mod = Mod:module_info(module),
+ File = filename:append(Dir, atom_to_list(Mod)),
+ Src = io_lib:format("-module(~s).\n"
+ "-export([test/1]).\n"
+ "test(me) -> fail.\n", [Mod]),
+ ok = file:write_file(File++".erl", Src),
+ case c:c(File, [{outdir,Dir}]) of
+ {ok,Module} ->
+ Module:test(me);
+ {error,sticky_directory} ->
+ ok
+ end;
+ false ->
+ %% For some reason the module is not sticky
+ %% could be that the .erlang file has
+ %% unstuck it?
+ {Mod, is_not_sticky}
end.
%% Test that the -pa and -pz options work as expected.
@@ -1446,7 +1459,7 @@ do_on_load_error(ReturnValue) ->
{undef,[{on_load_error,main,[],_}|_]} = Exit
end.
-on_load_update(_Config) ->
+on_load_update(Config) ->
{Mod,Code1} = on_load_update_code(1),
{module,Mod} = code:load_binary(Mod, "", Code1),
42 = Mod:a(),
@@ -1456,7 +1469,7 @@ on_load_update(_Config) ->
{Mod,Code2} = on_load_update_code(2),
{error,on_load_failure} = code:load_binary(Mod, "", Code2),
42 = Mod:a(),
- 100 = Mod:b(99),
+ 78 = Mod:b(77),
{'EXIT',{undef,_}} = (catch Mod:never()),
4 = erlang:trace_pattern({Mod,'_','_'}, false),
@@ -1467,6 +1480,9 @@ on_load_update(_Config) ->
{'EXIT',{undef,_}} = (catch Mod:b(10)),
{'EXIT',{undef,_}} = (catch Mod:never()),
+ code:purge(Mod),
+ code:delete(Mod),
+ code:purge(Mod),
ok.
on_load_update_code(Version) ->
@@ -1498,6 +1514,40 @@ on_load_update_code_1(3, Mod) ->
"f() -> ok.\n",
"c() -> 100.\n"]).
+%% Test -on_load while trace feature 'on_load' is enabled (OTP-14612)
+on_load_trace_on_load(Config) ->
+ Papa = self(),
+ Tracer = spawn_link(fun F() -> receive M -> Papa ! M end, F() end),
+ {tracer,[]} = erlang:trace_info(self(),tracer),
+ erlang:trace(self(), true, [call, {tracer, Tracer}]),
+ erlang:trace_pattern(on_load, true, []),
+ on_load_update(Config),
+ erlang:trace_pattern(on_load, false, []),
+ erlang:trace(self(), false, [call]),
+
+ %% WE GET TRACES FOR CALLS TO UNDEFINED FUNCTIONS ???
+ %% Remove filter when that is fixed.
+ Ms = lists:filter(fun({trace,Papa,call,
+ {error_handler,undefined_function,
+ [on_load_update_code,_,_]}})
+ -> false;
+ (_) -> true
+ end,
+ flush()),
+
+ [{trace, Papa, call, {on_load_update_code, a, []}},
+ {trace, Papa, call, {on_load_update_code, b, [99]}},
+ {trace, Papa, call, {on_load_update_code, c, []}}] = Ms,
+
+ exit(Tracer, normal),
+ ok.
+
+flush() ->
+ receive M -> [M | flush()]
+ after 100 -> []
+ end.
+
+
on_load_purge(_Config) ->
Mod = ?FUNCTION_NAME,
register(Mod, self()),
@@ -1602,6 +1652,98 @@ on_load_pending(_Config) ->
ok = Mod:t(),
ok.
+on_load_deleted(_Config) ->
+ Mod = ?FUNCTION_NAME,
+
+ R0 = fun() ->
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() -> ok.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ {module,Mod} = code:load_binary(Mod, "", Code)
+ end,
+ delete_before_reload(Mod, R0),
+ delete_before_reload(Mod, R0),
+
+ R1 = fun() ->
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() -> fail.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ {error,on_load_failure} = code:load_binary(Mod, "", Code)
+ end,
+ delete_before_reload(Mod, R1),
+ delete_before_reload(Mod, R1),
+
+ OtherMod = list_to_atom(lists:concat([Mod,"_42"])),
+ OtherTree = ?Q(["-module('@OtherMod@').\n"]),
+ merl:print(OtherTree),
+ {ok,OtherMod,OtherCode} = merl:compile(OtherTree),
+
+ R2 = fun() ->
+ RegName = 'on_load__registered_name',
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() ->\n",
+ " register('@RegName@', self()),\n",
+ " receive _ -> ok end.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ spawn(fun() ->
+ {module,Mod} = code:load_binary(Mod, "", Code)
+ end),
+ receive after 1 -> ok end,
+ {module,OtherMod} = code:load_binary(OtherMod, "",
+ OtherCode),
+ RegName ! stop
+ end,
+ delete_before_reload(Mod, R2),
+
+ ok.
+
+delete_before_reload(Mod, Reload) ->
+ false = check_old_code(Mod),
+
+ Tree1 = ?Q(["-module('@Mod@').\n",
+ "-export([f/1]).\n",
+ "f(Parent) ->\n",
+ " register('@Mod@', self()),\n",
+ " Parent ! started,\n",
+ " receive _ -> ok end.\n"]),
+ merl:print(Tree1),
+ {ok,Mod,Code1} = merl:compile(Tree1),
+
+ Self = self(),
+ spawn(fun() ->
+ {module,Mod} = code:load_binary(Mod, "", Code1),
+ Mod:f(Self)
+ end),
+ receive started -> ok end,
+
+ true = code:delete(Mod),
+ true = check_old_code(Mod),
+
+ Reload(),
+
+ %% When loading the the module with the -on_load() function,
+ %% the reference to the old code would be lost. Make sure that
+ %% the old code is remembered and is still preventing the
+ %% purge.
+ false = code:soft_purge(Mod),
+
+ %% Get rid of the old code.
+ Mod ! stop,
+ receive after 1 -> ok end,
+ true = code:soft_purge(Mod),
+
+ %% Unload the version of the module with the -on_load() function.
+ true = code:delete(Mod),
+ true = code:soft_purge(Mod),
+
+ ok.
+
%% Test that the native code of early loaded modules is loaded.
native_early_modules(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index eb58e92224..e43be77428 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -25,6 +25,7 @@
init_per_group/2,end_per_group/2]).
-export([tick/1, tick_change/1, illegal_nodenames/1, hidden_node/1,
+ setopts/1,
table_waste/1, net_setuptime/1,
inet_dist_options_options/1,
@@ -42,6 +43,8 @@
-export([get_socket_priorities/0,
tick_cli_test/1, tick_cli_test1/1,
tick_serv_test/2, tick_serv_test1/1,
+ run_remote_test/1,
+ setopts_do/2,
keep_conn/1, time_ping/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -66,6 +69,7 @@ suite() ->
all() ->
[tick, tick_change, illegal_nodenames, hidden_node,
+ setopts,
table_waste, net_setuptime, inet_dist_options_options,
{group, monitor_nodes}].
@@ -282,6 +286,165 @@ tick_cli_test1(Node) ->
end
end.
+setopts(Config) when is_list(Config) ->
+ register(setopts_regname, self()),
+ [N1,N2,N3,N4] = get_nodenames(4, setopts),
+
+ {_N1F,Port1} = start_node_unconnected(N1, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()), "1", "ping"]),
+ 0 = wait_for_port_exit(Port1),
+
+ {_N2F,Port2} = start_node_unconnected(N2, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()), "2", "ping"]),
+ 0 = wait_for_port_exit(Port2),
+
+ {ok, LSock} = gen_tcp:listen(0, [{packet,2}, {active,false}]),
+ {ok, LTcpPort} = inet:port(LSock),
+
+ {N3F,Port3} = start_node_unconnected(N3, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()),
+ "1", integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N3F, Port3),
+ 0 = wait_for_port_exit(Port3),
+
+ {N4F,Port4} = start_node_unconnected(N4, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()),
+ "2", integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N4F, Port4),
+ 0 = wait_for_port_exit(Port4),
+
+ ok.
+
+wait_and_connect(LSock, NodeName, NodePort) ->
+ {ok, Sock} = gen_tcp:accept(LSock),
+ {ok, "Connect please"} = gen_tcp:recv(Sock, 0),
+ flush_from_port(NodePort),
+ pong = net_adm:ping(NodeName),
+ gen_tcp:send(Sock, "Connect done"),
+ gen_tcp:close(Sock).
+
+
+flush_from_port(Port) ->
+ flush_from_port(Port, 10).
+
+flush_from_port(Port, Timeout) ->
+ receive
+ {Port,{data,String}} ->
+ io:format("~p: ~s\n", [Port, String]),
+ flush_from_port(Port, Timeout)
+ after Timeout ->
+ timeout
+ end.
+
+wait_for_port_exit(Port) ->
+ case (receive M -> M end) of
+ {Port,{exit_status,Status}} ->
+ Status;
+ {Port,{data,String}} ->
+ io:format("~p: ~s\n", [Port, String]),
+ wait_for_port_exit(Port)
+ end.
+
+run_remote_test([FuncStr, TestNodeStr | Args]) ->
+ Status = try
+ io:format("Node ~p started~n", [node()]),
+ TestNode = list_to_atom(TestNodeStr),
+ io:format("Node ~p spawning function ~p~n", [node(), FuncStr]),
+ {Pid,Ref} = spawn_monitor(?MODULE, list_to_atom(FuncStr), [TestNode, Args]),
+ io:format("Node ~p waiting for function ~p~n", [node(), FuncStr]),
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ 0;
+ Other ->
+ io:format("Node ~p got unexpected msg: ~p\n",[node(), Other]),
+ 1
+ end
+ catch
+ C:E ->
+ io:format("Node ~p got EXCEPTION ~p:~p\nat ~p\n",
+ [node(), C, E, erlang:get_stacktrace()]),
+ 2
+ end,
+ io:format("Node ~p doing halt(~p).\n",[node(), Status]),
+ erlang:halt(Status).
+
+% Do the actual test on the remote node
+setopts_do(TestNode, [OptNr, ConnectData]) ->
+ [] = nodes(),
+ {Opt, Val} = opt_from_nr(OptNr),
+ ok = net_kernel:setopts(new, [{Opt, Val}]),
+
+ [] = nodes(),
+ {error, noconnection} = net_kernel:getopts(TestNode, [Opt]),
+
+ case ConnectData of
+ "ping" -> % We connect
+ net_adm:ping(TestNode);
+ TcpPort -> % Other connect
+ {ok, Sock} = gen_tcp:connect("localhost", list_to_integer(TcpPort),
+ [{active,false},{packet,2}]),
+ ok = gen_tcp:send(Sock, "Connect please"),
+ {ok, "Connect done"} = gen_tcp:recv(Sock, 0),
+ gen_tcp:close(Sock)
+ end,
+ [TestNode] = nodes(),
+ {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]),
+ {error, noconnection} = net_kernel:getopts('pixie@fairyland', [Opt]),
+
+ NewVal = change_val(Val),
+ ok = net_kernel:setopts(TestNode, [{Opt, NewVal}]),
+ {ok, [{Opt,NewVal}]} = net_kernel:getopts(TestNode, [Opt]),
+
+ ok = net_kernel:setopts(TestNode, [{Opt, Val}]),
+ {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]),
+
+ ok.
+
+opt_from_nr("1") -> {nodelay, true};
+opt_from_nr("2") -> {nodelay, false}.
+
+change_val(true) -> false;
+change_val(false) -> true.
+
+start_node_unconnected(Name, Mod, Func, Args) ->
+ FullName = full_node_name(Name),
+ CmdLine = mk_node_cmdline(Name,Mod,Func,Args),
+ io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
+ case open_port({spawn, CmdLine}, [exit_status]) of
+ Port when is_port(Port) ->
+ {FullName, Port};
+ Error ->
+ exit({failed_to_start_node, FullName, Error})
+ end.
+
+full_node_name(PreName) ->
+ HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ atom_to_list(node())),
+ list_to_atom(atom_to_list(PreName) ++ HostSuffix).
+
+mk_node_cmdline(Name,Mod,Func,Args) ->
+ Static = "-noinput",
+ Pa = filename:dirname(code:which(?MODULE)),
+ Prog = case catch init:get_argument(progname) of
+ {ok,[[P]]} -> P;
+ _ -> exit(no_progname_argument_found)
+ end,
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname ";
+ true -> "-name ";
+ _ -> exit(not_distributed_node)
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ NameStr = atom_to_list(Name),
+ Prog ++ " "
+ ++ Static ++ " "
+ ++ NameSw ++ " " ++ NameStr
+ ++ " -pa " ++ Pa
+ ++ " -env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr
+ ++ " -setcookie " ++ atom_to_list(erlang:get_cookie())
+ ++ " -run " ++ atom_to_list(Mod) ++ " " ++ atom_to_list(Func)
+ ++ " " ++ string:join(Args, " ").
+
%% OTP-4255.
tick_change(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/error_logger_SUITE.erl b/lib/kernel/test/error_logger_SUITE.erl
index b6e7551741..2d26a7246c 100644
--- a/lib/kernel/test/error_logger_SUITE.erl
+++ b/lib/kernel/test/error_logger_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
+ off_heap/1,
error_report/1, info_report/1, error/1, info/1,
emulator/1, tty/1, logfile/1, add/1, delete/1]).
@@ -45,7 +46,7 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [error_report, info_report, error, info, emulator, tty,
+ [off_heap, error_report, info_report, error, info, emulator, tty,
logfile, add, delete].
groups() ->
@@ -66,6 +67,16 @@ end_per_group(_GroupName, Config) ->
%%-----------------------------------------------------------------
+off_heap(_Config) ->
+ %% The error_logger process may receive a huge amount of
+ %% messages. Make sure that they are stored off heap to
+ %% avoid exessive GCs.
+ MQD = message_queue_data,
+ {MQD,off_heap} = process_info(whereis(error_logger), MQD),
+ ok.
+
+%%-----------------------------------------------------------------
+
error_report(Config) when is_list(Config) ->
error_logger:add_report_handler(?MODULE, self()),
Rep1 = [{tag1,"data1"},{tag2,data2},{tag3,3}],
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 5f049c6f99..c37d114a58 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -493,22 +493,13 @@ read_write_file(Config) when is_list(Config) ->
%% Try writing and reading back some term
SomeTerm = {"This term",{will,be},[written,$t,$o],1,file,[]},
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(SomeTerm)),
- {ok,Bin1} = ?FILE_MODULE:read_file(Name),
- SomeTerm = binary_to_term(Bin1),
+ Bin1 = term_to_binary(SomeTerm),
+ ok = do_read_write_file(Name, Bin1),
%% Try a "null" term
NullTerm = [],
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(NullTerm)),
- {ok,Bin2} = ?FILE_MODULE:read_file(Name),
- NullTerm = binary_to_term(Bin2),
-
- %% Try some "complicated" types
- BigNum = 123456789012345678901234567890,
- ComplTerm = {self(),make_ref(),BigNum,3.14159},
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(ComplTerm)),
- {ok,Bin3} = ?FILE_MODULE:read_file(Name),
- ComplTerm = binary_to_term(Bin3),
+ Bin2 = term_to_binary(NullTerm),
+ ok = do_read_write_file(Name, Bin2),
%% Try reading a nonexistent file
Name2 = filename:join(RootDir,
@@ -519,25 +510,42 @@ read_write_file(Config) when is_list(Config) ->
{error, enoent} = ?FILE_MODULE:read_file(''),
%% Try writing to a bad filename
- {error, enoent} =
- ?FILE_MODULE:write_file("",term_to_binary(NullTerm)),
+ {error, enoent} = do_read_write_file("", Bin2),
%% Try writing something else than a binary
- {error, badarg} = ?FILE_MODULE:write_file(Name,{1,2,3}),
- {error, badarg} = ?FILE_MODULE:write_file(Name,self()),
+ {error, badarg} = do_read_write_file(Name, {1,2,3}),
+ {error, badarg} = do_read_write_file(Name, self()),
%% Some non-term binaries
- ok = ?FILE_MODULE:write_file(Name,[]),
- {ok,Bin4} = ?FILE_MODULE:read_file(Name),
- 0 = byte_size(Bin4),
+ ok = do_read_write_file(Name, []),
- ok = ?FILE_MODULE:write_file(Name,[Bin1,[],[[Bin2]]]),
- {ok,Bin5} = ?FILE_MODULE:read_file(Name),
- {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)),
+ %% Write some iolists
+ ok = do_read_write_file(Name, [Bin1,[],[[Bin2]]]),
+ ok = do_read_write_file(Name, ["string",<<"binary">>]),
+ ok = do_read_write_file(Name, "pure string"),
[] = flush(),
ok.
+do_read_write_file(Name, Data) ->
+ case ?FILE_MODULE:write_file(Name, Data) of
+ ok ->
+ BinData = iolist_to_binary(Data),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok = ?FILE_MODULE:write_file(Name, Data, []),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok = ?FILE_MODULE:write_file(Name, Data, [raw]),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok;
+ {error,_}=Res ->
+ Res = ?FILE_MODULE:write_file(Name, Data, []),
+ Res = ?FILE_MODULE:write_file(Name, Data, [raw]),
+ Res
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index f836b2aa94..620ab235a0 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -117,7 +117,11 @@ xfer_min(Config) when is_list(Config) ->
Stream = 0,
Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>,
Loopback = {127,0,0,1},
+ StatOpts =
+ [recv_avg,recv_cnt,recv_max,recv_oct,
+ send_avg,send_cnt,send_max,send_oct],
{ok,Sb} = gen_sctp:open([{type,seqpacket}]),
+ {ok,SbStat1} = inet:getstat(Sb, StatOpts),
{ok,Pb} = inet:port(Sb),
ok = gen_sctp:listen(Sb, true),
@@ -212,6 +216,8 @@ xfer_min(Config) when is_list(Config) ->
assoc_id=SbAssocId}} =
recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
ok = gen_sctp:close(Sa),
+ {ok,SbStat2} = inet:getstat(Sb, StatOpts),
+ [] = filter_stat_eq(SbStat1, SbStat2),
ok = gen_sctp:close(Sb),
receive
@@ -220,6 +226,18 @@ xfer_min(Config) when is_list(Config) ->
end,
ok.
+filter_stat_eq([], []) ->
+ [];
+filter_stat_eq([{Tag,Val1}=Stat|SbStat1], [{Tag,Val2}|SbStat2]) ->
+ if
+ Val1 == Val2 ->
+ [Stat|filter_stat_eq(SbStat1, SbStat2)];
+ true ->
+ filter_stat_eq(SbStat1, SbStat2)
+ end.
+
+
+
%% Minimal data transfer in active mode.
xfer_active(Config) when is_list(Config) ->
Timeout = 2000,
@@ -383,26 +401,28 @@ def_sndrcvinfo(Config) when is_list(Config) ->
assoc_id=S2AssocId} = S2AssocChange =
log_ok(gen_sctp:connect(S2, Loopback, P1, [])),
?LOGVAR(S2AssocChange),
- case recv_event(log_ok(gen_sctp:recv(S1))) of
- {Loopback,P2,
- #sctp_assoc_change{
- state=comm_up,
- error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId);
- {Loopback,P2,
- #sctp_paddr_change{
- state=addr_confirmed,
- error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId),
+ S1AssocId =
+ case recv_event(log_ok(gen_sctp:recv(S1))) of
{Loopback,P2,
#sctp_assoc_change{
state=comm_up,
error=0,
- assoc_id=S1AssocId}} =
- recv_event(log_ok(gen_sctp:recv(S1)))
- end,
+ assoc_id=AssocId}} ->
+ AssocId;
+ {Loopback,P2,
+ #sctp_paddr_change{
+ state=addr_confirmed,
+ error=0,
+ assoc_id=AssocId}} ->
+ {Loopback,P2,
+ #sctp_assoc_change{
+ state=comm_up,
+ error=0,
+ assoc_id=AssocId}} =
+ recv_event(log_ok(gen_sctp:recv(S1))),
+ AssocId
+ end,
+ ?LOGVAR(S1AssocId),
#sctp_sndrcvinfo{
ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} =
@@ -1055,6 +1075,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
Addr = {127,0,0,1},
Stream = 0,
Timeout = 333,
+ StartTime = timestamp(),
S1 = socket_open([{ifaddr,Addr}|SockOpts], Timeout),
?LOGVAR(S1),
P1 = socket_call(S1, get_port),
@@ -1077,7 +1098,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId2}}} -> AssocId2
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
?LOGVAR(S2Ai),
S1Ai =
@@ -1087,7 +1108,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId1}}} -> AssocId1
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
?LOGVAR(S1Ai),
%%
@@ -1095,13 +1116,13 @@ peeloff(Config, SockOpts) when is_list(Config) ->
receive
{S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}),
receive
{S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
S3 = socket_peeloff(Socket1, S1Ai, SockOpts, Timeout),
@@ -1120,31 +1141,31 @@ peeloff(Config, SockOpts) when is_list(Config) ->
receive
{S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2,S3])
+ socket_bailout([S1,S2,S3], StartTime)
end,
socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}),
receive
{S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2,S3])
+ socket_bailout([S1,S2,S3], StartTime)
end,
%%
inet:i(sctp),
- socket_close_verbose(S1),
- socket_close_verbose(S2),
+ socket_close_verbose(S1, StartTime),
+ socket_close_verbose(S2, StartTime),
receive
{S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} ->
match_unless_solaris(S3Ai, S3Ai_X)
after Timeout ->
- socket_bailout([S3])
+ socket_bailout([S3], StartTime)
end,
receive
{S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp,
assoc_id=S3Ai}}} -> ok
after Timeout ->
- socket_bailout([S3])
+ socket_bailout([S3], StartTime)
end,
- socket_close_verbose(S3),
+ socket_close_verbose(S3, StartTime),
[] = flush(),
ok.
@@ -1156,6 +1177,7 @@ buffers(Config) when is_list(Config) ->
Addr = {127,0,0,1},
Stream = 1,
Timeout = 3333,
+ StartTime = timestamp(),
S1 = socket_open([{ip,Addr}], Timeout),
?LOGVAR(S1),
P1 = socket_call(S1, get_port),
@@ -1174,7 +1196,7 @@ buffers(Config) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId2}}} -> AssocId2
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
S1Ai =
receive
@@ -1183,7 +1205,7 @@ buffers(Config) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId1}}} -> AssocId1
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
socket_call(S1, {setopts,[{recbuf,Limit}]}),
@@ -1197,22 +1219,22 @@ buffers(Config) when is_list(Config) ->
receive
{S1,{Addr,P2,S1Ai,Stream,Data}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
- socket_close_verbose(S1),
+ socket_close_verbose(S1, StartTime),
receive
{S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok
after Timeout ->
- socket_bailout([S2])
+ socket_bailout([S2], StartTime)
end,
receive
{S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp,
assoc_id=S2Ai}}} -> ok
after Timeout ->
- socket_bailout([S2])
+ socket_bailout([S2], StartTime)
end,
- socket_close_verbose(S2),
+ socket_close_verbose(S2, StartTime),
[] = flush(),
ok.
@@ -1521,8 +1543,8 @@ socket_peeloff(Socket, AssocId, SocketOpts, Timeout) ->
end,
s_start(Starter, Timeout).
-socket_close_verbose(S) ->
- History = socket_history(socket_close(S)),
+socket_close_verbose(S, StartTime) ->
+ History = socket_history(socket_close(S), StartTime),
io:format("socket_close ~p:~n ~p.~n", [S,History]),
History.
@@ -1535,19 +1557,19 @@ socket_call(S, Request) ->
%% socket_get(S, Key) ->
%% s_req(S, {get,Key}).
-socket_bailout([S|Ss]) ->
- History = socket_history(socket_close(S)),
+socket_bailout([S|Ss], StartTime) ->
+ History = socket_history(socket_close(S), StartTime),
io:format("bailout ~p:~n ~p.~n", [S,History]),
- socket_bailout(Ss);
-socket_bailout([]) ->
+ socket_bailout(Ss, StartTime);
+socket_bailout([], _) ->
io:format("flush: ~p.~n", [flush()]),
ct:fail(socket_bailout).
-socket_history({State,Flush}) ->
+socket_history({State,Flush}, StartTime) ->
{lists:keysort(
2,
lists:flatten(
- [[{Key,Val} || Val <- Vals]
+ [[{Key,{TS-StartTime,Val}} || {TS,Val} <- Vals]
|| {Key,Vals} <- gb_trees:to_list(State)])),
Flush}.
@@ -1610,14 +1632,12 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
{Parent,Ref,exit} ->
ok = gen_sctp:close(Socket),
Key = exit,
- Val = {now(),Socket},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, Socket, State),
Parent ! {self(),Ref,{NewState,flush()}};
{Parent,Ref,{Msg}} ->
Result = Handler(Msg),
Key = req,
- Val = {now(),{Msg,Result}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Msg,Result}, State),
Parent ! {self(),Ref,Result},
s_loop(Socket, Timeout, Parent, Handler, NewState);
%% {Parent,Ref,{get,Key}} ->
@@ -1627,16 +1647,15 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
{[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}}
when not is_tuple(Data) ->
case gb_get({assoc_change,AssocId}, State) of
- [{_,{Addr,Port,
- #sctp_assoc_change{
- state=comm_up,
- inbound_streams=Is}}}|_]
+ [{Addr,Port,
+ #sctp_assoc_change{
+ state=comm_up,
+ inbound_streams=Is}}|_]
when 0 =< Stream, Stream < Is-> ok;
[] -> ok
end,
Key = {msg,AssocId,Stream},
- Val = {now(),{Addr,Port,SRI,Data}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SRI,Data}, State),
Parent ! {self(),{Addr,Port,AssocId,Stream,Data}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1647,13 +1666,12 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
Key = {assoc_change,AssocId},
- Val = {now(),{Addr,Port,SAC}},
case {gb_get(Key, State),St} of
{[],_} -> ok;
- {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_}
+ {[{Addr,Port,#sctp_assoc_change{state=comm_up}}|_],_}
when St =:= comm_lost; St =:= shutdown_comp -> ok
end,
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SAC}, State),
Parent ! {self(),{Addr,Port,SAC}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1667,14 +1685,13 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
case {gb_get({assoc_change,AssocId}, State),St} of
- {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_}
+ {[{Addr,Port,#sctp_assoc_change{state=comm_up}}|_],_}
when St =:= addr_available;
St =:= addr_confirmed -> ok;
{[],addr_confirmed} -> ok
end,
Key = {paddr_change,AssocId},
- Val = {now(),{Addr,Port,SPC}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SPC}, State),
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
{sctp,Socket,Addr,Port,
@@ -1684,12 +1701,11 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
case gb_get({assoc_change,AssocId}, State) of
- [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok;
+ [{Addr,Port,#sctp_assoc_change{state=comm_up}}|_] -> ok;
[] -> ok
end,
Key = {shutdown_event,AssocId},
- Val = {now(),{Addr,Port}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port}, State),
Parent ! {self(), {Addr,Port,SSE}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1707,11 +1723,12 @@ again(Socket) ->
end.
gb_push(Key, Val, GBT) ->
+ TS = timestamp(),
case gb_trees:lookup(Key, GBT) of
none ->
- gb_trees:insert(Key, [Val], GBT);
+ gb_trees:insert(Key, [{TS,Val}], GBT);
{value,V} ->
- gb_trees:update(Key, [Val|V], GBT)
+ gb_trees:update(Key, [{TS,Val}|V], GBT)
end.
gb_get(Key, GBT) ->
@@ -1719,7 +1736,7 @@ gb_get(Key, GBT) ->
none ->
[];
{value,V} ->
- V
+ [Val || {_TS,Val} <- V]
end.
match_unless_solaris(A, B) ->
@@ -1727,3 +1744,6 @@ match_unless_solaris(A, B) ->
{unix,sunos} -> B;
_ -> A = B
end.
+
+timestamp() ->
+ erlang:monotonic_time().
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 77ec89b4f4..92a74465b7 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -38,7 +38,7 @@
t_local_basic/1, t_local_unbound/1, t_local_fdopen/1,
t_local_fdopen_listen/1, t_local_fdopen_listen_unbound/1,
t_local_fdopen_connect/1, t_local_fdopen_connect_unbound/1,
- t_local_abstract/1]).
+ t_local_abstract/1, t_accept_inet6_tclass/1]).
-export([getsockfd/0,closesockfd/1]).
@@ -50,6 +50,7 @@ all() ->
[{group, t_accept}, {group, t_connect}, {group, t_recv},
t_shutdown_write, t_shutdown_both, t_shutdown_error,
t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6,
+ t_accept_inet6_tclass,
{group, t_local}].
groups() ->
@@ -521,6 +522,24 @@ local_handshake(S, SAddr, C, CAddr) ->
SData = ok(gen_tcp:recv(C, length(SData))),
ok.
+t_accept_inet6_tclass(Config) when is_list(Config) ->
+ TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding
+ case gen_tcp:listen(0, [inet6,TClassOpt]) of
+ {ok,L} ->
+ LPort = ok(inet:port(L)),
+ Loopback = {0,0,0,0,0,0,0,1},
+ Sa = ok(gen_tcp:connect(Loopback, LPort, [])),
+ Sb = ok(gen_tcp:accept(L)),
+ [TClassOpt] = ok(inet:getopts(Sb, [tclass])),
+ ok = gen_tcp:close(Sb),
+ ok = gen_tcp:close(Sa),
+ ok = gen_tcp:close(L),
+ ok;
+ {error,_} ->
+ {skip,"IPv6 TCLASS not supported"}
+ end.
+
+
%%% Utilities
%% Calls M:F/length(A), which should return a timeout error, and complete
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 6b64c83fc2..5e08a5ea62 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -52,7 +52,7 @@
active_once_closed/1, send_timeout/1, send_timeout_active/1,
otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1,
wrapping_oct/0, wrapping_oct/1,
- otp_9389/1]).
+ otp_9389/1, otp_13939/1]).
%% Internal exports.
-export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1,
@@ -3014,3 +3014,42 @@ ok({ok,V}) -> V.
get_hostname(Name) ->
"@"++Host = lists:dropwhile(fun(C) -> C =/= $@ end, atom_to_list(Name)),
Host.
+
+otp_13939(doc) ->
+ ["Check that writing to a remotely closed socket doesn't block forever "
+ "when exit_on_close is false."];
+otp_13939(suite) ->
+ [];
+otp_13939(Config) when is_list(Config) ->
+ {Pid, Ref} = spawn_opt(
+ fun() ->
+ {ok, Listener} = gen_tcp:listen(0, [{exit_on_close, false}]),
+ {ok, Port} = inet:port(Listener),
+
+ spawn_link(
+ fun() ->
+ {ok, Client} = gen_tcp:connect("localhost", Port,
+ [{active, false}]),
+ ok = gen_tcp:close(Client)
+ end),
+
+ {ok, Accepted} = gen_tcp:accept(Listener),
+
+ ok = gen_tcp:send(Accepted, <<0:(10*1024*1024*8)>>),
+
+ %% The bug surfaces when there's a delay between the send
+ %% operations; inet:getstat is a red herring.
+ timer:sleep(100),
+
+ {error, Code} = gen_tcp:send(Accepted, <<0:(10*1024*1024*8)>>),
+ ct:pal("gen_tcp:send returned ~p~n", [Code])
+ end, [link, monitor]),
+
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ ok
+ after 1000 ->
+ demonitor(Ref, [flush]),
+ exit(Pid, normal),
+ ct:fail("Server process blocked on send.")
+ end.
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 1370e23195..2b59eb2bfe 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -27,7 +27,8 @@
-export([get_arguments/1, get_argument/1, boot_var/1, restart/1,
many_restarts/0, many_restarts/1,
get_plain_arguments/1,
- reboot/1, stop_status/1, stop/1, get_status/1, script_id/1]).
+ reboot/1, stop_status/1, stop/1, get_status/1, script_id/1,
+ find_system_processes/0]).
-export([boot1/1, boot2/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -355,12 +356,16 @@ wait_for(N,Node,EHPid) ->
restart(Config) when is_list(Config) ->
Args = args(),
+ Pa = " -pa " ++ filename:dirname(code:which(?MODULE)),
+
%% Currently test_server:start_node cannot be used. The restarted
%% node immediately halts due to the implementation of
%% test_server:start_node.
- {ok, Node} = loose_node:start(init_test, Args, ?DEFAULT_TIMEOUT_SEC),
+ {ok, Node} = loose_node:start(init_test, Args ++ Pa, ?DEFAULT_TIMEOUT_SEC),
%% Ok, the node is up, now the real test test begins.
erlang:monitor_node(Node, true),
+ SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []),
+ [InitPid, PurgerPid, LitCollectorPid, DirtyCodePid] = SysProcs0,
InitPid = rpc:call(Node, erlang, whereis, [init]),
PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]),
Procs = rpc:call(Node, erlang, processes, []),
@@ -375,6 +380,9 @@ restart(Config) when is_list(Config) ->
end,
ok = wait_restart(30, Node),
+ SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []),
+ [InitPid1, PurgerPid1, LitCollectorPid1, DirtyCodePid1] = SysProcs1,
+
%% Still the same init process!
InitPid1 = rpc:call(Node, erlang, whereis, [init]),
InitP = pid_to_list(InitPid),
@@ -385,8 +393,24 @@ restart(Config) when is_list(Config) ->
PurgerP = pid_to_list(PurgerPid),
PurgerP = pid_to_list(PurgerPid1),
+ %% and same literal area collector process!
+ case LitCollectorPid of
+ undefined -> undefined = LitCollectorPid1;
+ _ ->
+ LitCollectorP = pid_to_list(LitCollectorPid),
+ LitCollectorP = pid_to_list(LitCollectorPid1)
+ end,
+
+ %% and same dirty process code checker process!
+ case DirtyCodePid of
+ undefined -> undefined = DirtyCodePid1;
+ _ ->
+ DirtyCodeP = pid_to_list(DirtyCodePid),
+ DirtyCodeP = pid_to_list(DirtyCodePid1)
+ end,
+
NewProcs0 = rpc:call(Node, erlang, processes, []),
- NewProcs = NewProcs0 -- [InitPid1, PurgerPid1],
+ NewProcs = NewProcs0 -- SysProcs1,
case check_processes(NewProcs, MaxPid) of
true ->
ok;
@@ -406,6 +430,37 @@ restart(Config) when is_list(Config) ->
loose_node:stop(Node),
ok.
+-record(sys_procs, {init,
+ code_purger,
+ literal_collector,
+ dirty_proc_checker}).
+
+find_system_processes() ->
+ find_system_procs(processes(), #sys_procs{}).
+
+find_system_procs([], SysProcs) ->
+ [SysProcs#sys_procs.init,
+ SysProcs#sys_procs.code_purger,
+ SysProcs#sys_procs.literal_collector,
+ SysProcs#sys_procs.dirty_proc_checker];
+find_system_procs([P|Ps], SysProcs) ->
+ case process_info(P, initial_call) of
+ {initial_call,{otp_ring0,start,2}} ->
+ undefined = SysProcs#sys_procs.init,
+ find_system_procs(Ps, SysProcs#sys_procs{init = P});
+ {initial_call,{erts_code_purger,start,0}} ->
+ undefined = SysProcs#sys_procs.code_purger,
+ find_system_procs(Ps, SysProcs#sys_procs{code_purger = P});
+ {initial_call,{erts_literal_area_collector,start,0}} ->
+ undefined = SysProcs#sys_procs.literal_collector,
+ find_system_procs(Ps, SysProcs#sys_procs{literal_collector = P});
+ {initial_call,{erts_dirty_process_code_checker,start,0}} ->
+ undefined = SysProcs#sys_procs.dirty_proc_checker,
+ find_system_procs(Ps, SysProcs#sys_procs{dirty_proc_checker = P});
+ _ ->
+ find_system_procs(Ps, SysProcs)
+ end.
+
wait_restart(0, _Node) ->
ct:fail(not_restarted);
wait_restart(N, Node) ->
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 2a1e5016ec..d7f0463289 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -24,7 +24,9 @@
init_per_testcase/2,end_per_testcase/2]).
-export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1,
find_executable/1, unix_comment_in_command/1, deep_list_command/1,
- large_output_command/1, perf_counter_api/1]).
+ large_output_command/1, background_command/0, background_command/1,
+ message_leak/1, close_stdin/0, close_stdin/1, max_size_command/1,
+ perf_counter_api/1]).
-include_lib("common_test/include/ct.hrl").
@@ -35,7 +37,8 @@ suite() ->
all() ->
[space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command,
find_executable, unix_comment_in_command, deep_list_command,
- large_output_command, perf_counter_api].
+ large_output_command, background_command, message_leak,
+ close_stdin, max_size_command, perf_counter_api].
groups() ->
[].
@@ -52,6 +55,14 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(TC, Config)
+ when TC =:= background_command; TC =:= close_stdin ->
+ case os:type() of
+ {win32, _} ->
+ {skip,"Should not work on windows"};
+ _ ->
+ Config
+ end;
init_per_testcase(_TC,Config) ->
Config.
@@ -261,13 +272,69 @@ deep_list_command(Config) when is_list(Config) ->
%% FYI: [$e, $c, "ho"] =:= io_lib:format("ec~s", ["ho"])
ok.
-%% Test to take sure that the correct data is
+%% Test to make sure that the correct data is
%% received when doing large commands.
large_output_command(Config) when is_list(Config) ->
%% Maximum allowed on windows is 8192, so we test well below that
AAA = lists:duplicate(7000, $a),
comp(AAA,os:cmd("echo " ++ AAA)).
+%% Test that it is possible on unix to start a background task using os:cmd.
+background_command() ->
+ [{timetrap, {seconds, 5}}].
+background_command(_Config) ->
+ %% This testcase fails when the os:cmd takes
+ %% longer then the 5 second timeout
+ os:cmd("sleep 10&").
+
+%% Test that message does not leak to the calling process
+message_leak(_Config) ->
+ process_flag(trap_exit, true),
+
+ os:cmd("echo hello"),
+ [] = receive_all(),
+
+ case os:type() of
+ {unix, _} ->
+ os:cmd("for i in $(seq 1 100); do echo hello; done&"),
+ [] = receive_all();
+ _ ->
+ ok % Cannot background on non-unix
+ end,
+
+ process_flag(trap_exit, false).
+
+%% Test that os:cmd closes stdin of the program that is executed
+close_stdin() ->
+ [{timetrap, {seconds, 5}}].
+close_stdin(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Fds = filename:join(DataDir, "my_fds"),
+
+ "-1" = os:cmd(Fds).
+
+max_size_command(_Config) ->
+
+ Res20 = os:cmd("cat /dev/zero", #{ max_size => 20 }),
+ 20 = length(Res20),
+
+ Res0 = os:cmd("cat /dev/zero", #{ max_size => 0 }),
+ 0 = length(Res0),
+
+ Res32768 = os:cmd("cat /dev/zero", #{ max_size => 32768 }),
+ 32768 = length(Res32768),
+
+ ResHello = string_trim(os:cmd("echo hello", #{ max_size => 20 })),
+ 5 = length(ResHello).
+
+string_trim(S) ->
+ lists:reverse(string_trim_left(lists:reverse(string_trim_left(S)))).
+
+string_trim_left([C | T]) when C =:= $\s; C =:= $\n; C =:= $\t; C =:= $\r ->
+ string_trim_left(T);
+string_trim_left(S) ->
+ S.
+
%% Test that the os:perf_counter api works as expected
perf_counter_api(_Config) ->
diff --git a/lib/kernel/test/os_SUITE_data/Makefile.src b/lib/kernel/test/os_SUITE_data/Makefile.src
index 912d0cbcb1..f83f781411 100644
--- a/lib/kernel/test/os_SUITE_data/Makefile.src
+++ b/lib/kernel/test/os_SUITE_data/Makefile.src
@@ -3,7 +3,7 @@ LD = @LD@
CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
CROSSLDFLAGS = @CROSSLDFLAGS@
-PROGS = my_echo@exe@
+PROGS = my_echo@exe@ my_fds@exe@
all: $(PROGS)
@@ -12,3 +12,9 @@ my_echo@exe@: my_echo@obj@
my_echo@obj@: my_echo.c
$(CC) -c -o my_echo@obj@ $(CFLAGS) my_echo.c
+
+my_fds@exe@: my_fds@obj@
+ $(LD) $(CROSSLDFLAGS) -o my_fds my_fds@obj@ @LIBS@
+
+my_fds@obj@: my_fds.c
+ $(CC) -c -o my_fds@obj@ $(CFLAGS) my_fds.c
diff --git a/lib/kernel/test/os_SUITE_data/my_fds.c b/lib/kernel/test/os_SUITE_data/my_fds.c
new file mode 100644
index 0000000000..704a4d1e1d
--- /dev/null
+++ b/lib/kernel/test/os_SUITE_data/my_fds.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int
+main(int argc, char** argv)
+{
+ char buff[1];
+ int res = read(stdin, buff, 1);
+ printf("%d", res);
+}
diff --git a/lib/kernel/test/rpc_SUITE.erl b/lib/kernel/test/rpc_SUITE.erl
index 1c72ddc87f..a89a7600a2 100644
--- a/lib/kernel/test/rpc_SUITE.erl
+++ b/lib/kernel/test/rpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([call/1, block_call/1, multicall/1, multicall_timeout/1,
+-export([off_heap/1,
+ call/1, block_call/1, multicall/1, multicall_timeout/1,
multicall_dies/1, multicall_node_dies/1,
called_dies/1, called_node_dies/1,
called_throws/1, call_benchmark/1, async_call/1]).
@@ -35,7 +36,7 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- [call, block_call, multicall, multicall_timeout,
+ [off_heap, call, block_call, multicall, multicall_timeout,
multicall_dies, multicall_node_dies, called_dies,
called_node_dies, called_throws, call_benchmark,
async_call].
@@ -55,6 +56,13 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+off_heap(_Config) ->
+ %% The rex server process may receive a huge amount of
+ %% messages. Make sure that they are stored off heap to
+ %% avoid exessive GCs.
+ MQD = message_queue_data,
+ {MQD,off_heap} = process_info(whereis(rex), MQD),
+ ok.
%% Test different rpc calls.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index e7d422d03c..ff8fd8ab63 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 5.0
+KERNEL_VSN = 5.2.0.1
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index 46da79cfe3..9c73ab8072 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/megaco/test/megaco_app_test.erl b/lib/megaco/test/megaco_app_test.erl
index 346a123c66..981d93f5dd 100644
--- a/lib/megaco/test/megaco_app_test.erl
+++ b/lib/megaco/test/megaco_app_test.erl
@@ -17,8 +17,6 @@
%%
%% %CopyrightEnd%
%%
-
-%%
%%----------------------------------------------------------------------
%% Purpose: Verify the application specifics of the Megaco application
%%----------------------------------------------------------------------
@@ -26,296 +24,26 @@
-compile(export_all).
--include("megaco_test_lib.hrl").
-
-
-t() -> megaco_test_lib:t(?MODULE).
-t(Case) -> megaco_test_lib:t({?MODULE, Case}).
-
-
-%% Test server callbacks
-init_per_testcase(undef_funcs = Case, Config) ->
- NewConfig = [{tc_timeout, ?MINUTES(10)} | Config],
- megaco_test_lib:init_per_testcase(Case, NewConfig);
-init_per_testcase(Case, Config) ->
- megaco_test_lib:init_per_testcase(Case, Config).
-
-end_per_testcase(Case, Config) ->
- megaco_test_lib:end_per_testcase(Case, Config).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-include_lib("common_test/include/ct.hrl").
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
all() ->
[
- fields,
- modules,
- exportall,
- app_depend,
- undef_funcs
+ app,
+ appup
].
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init_per_suite(suite) -> [];
-init_per_suite(doc) -> [];
-init_per_suite(Config) when is_list(Config) ->
- case is_app(megaco) of
- {ok, AppFile} ->
- io:format("AppFile: ~n~p~n", [AppFile]),
- case megaco_flex_scanner:is_enabled() of
- true ->
- case megaco_flex_scanner:is_reentrant_enabled() of
- true ->
- io:format("~nMegaco reentrant flex scanner enabled~n~n", []);
- false ->
- io:format("~nMegaco non-reentrant flex scanner enabled~n~n", [])
- end;
- false ->
- io:format("~nMegaco flex scanner disabled~n~n", [])
- end,
- megaco:print_version_info(),
- [{app_file, AppFile}|Config];
- {error, Reason} ->
- fail(Reason)
- end.
-
-is_app(App) ->
- LibDir = code:lib_dir(App),
- File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
- case file:consult(File) of
- {ok, [{application, App, AppFile}]} ->
- {ok, AppFile};
- {error, {LineNo, Mod, Code}} ->
- IoList = lists:concat([File, ":", LineNo, ": ",
- Mod:format_error(Code)]),
- {error, list_to_atom(lists:flatten(IoList))};
- Error ->
- {error, {invalid_format, Error}}
- end.
-
-
-end_per_suite(suite) -> [];
-end_per_suite(doc) -> [];
-end_per_suite(Config) when is_list(Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fields(suite) ->
- [];
-fields(doc) ->
- [];
-fields(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Fields = [vsn, description, modules, registered, applications],
- case check_fields(Fields, AppFile, []) of
- [] ->
- ok;
- Missing ->
- fail({missing_fields, Missing})
- end.
-
-check_fields([], _AppFile, Missing) ->
- Missing;
-check_fields([Field|Fields], AppFile, Missing) ->
- check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
-
-check_field(Name, AppFile, Missing) ->
- io:format("checking field: ~p~n", [Name]),
- case lists:keymember(Name, 1, AppFile) of
- true ->
- Missing;
- false ->
- [Name|Missing]
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-modules(suite) ->
- [];
-modules(doc) ->
- [];
-modules(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- EbinList = get_ebin_mods(megaco),
- case missing_modules(Mods, EbinList, []) of
- [] ->
- ok;
- Missing ->
- throw({error, {missing_modules, Missing}})
- end,
- case extra_modules(Mods, EbinList, []) of
- [] ->
- ok;
- Extra ->
- throw({error, {extra_modules, Extra}})
- end,
- {ok, Mods}.
-
-get_ebin_mods(App) ->
- LibDir = code:lib_dir(App),
- EbinDir = filename:join([LibDir,"ebin"]),
- {ok, Files0} = file:list_dir(EbinDir),
- Files1 = [lists:reverse(File) || File <- Files0],
- [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
-
-
-missing_modules([], _Ebins, Missing) ->
- Missing;
-missing_modules([Mod|Mods], Ebins, Missing) ->
- case lists:member(Mod, Ebins) of
- true ->
- missing_modules(Mods, Ebins, Missing);
- false ->
- io:format("missing module: ~p~n", [Mod]),
- missing_modules(Mods, Ebins, [Mod|Missing])
- end.
-
-
-extra_modules(_Mods, [], Extra) ->
- Extra;
-extra_modules(Mods, [Mod|Ebins], Extra) ->
- case lists:member(Mod, Mods) of
- true ->
- extra_modules(Mods, Ebins, Extra);
- false ->
- io:format("supefluous module: ~p~n", [Mod]),
- extra_modules(Mods, Ebins, [Mod|Extra])
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-exportall(suite) ->
- [];
-exportall(doc) ->
- [];
-exportall(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- check_export_all(Mods).
-
-
-check_export_all([]) ->
- ok;
-check_export_all([Mod|Mods]) ->
- case (catch apply(Mod, module_info, [compile])) of
- {'EXIT', {undef, _}} ->
- check_export_all(Mods);
- O ->
- case lists:keysearch(options, 1, O) of
- false ->
- check_export_all(Mods);
- {value, {options, List}} ->
- case lists:member(export_all, List) of
- true ->
- throw({error, {export_all, Mod}});
- false ->
- check_export_all(Mods)
- end
- end
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-app_depend(suite) ->
- [];
-app_depend(doc) ->
- [];
-app_depend(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Apps = key1search(applications, AppFile),
- check_apps(Apps).
-
-
-check_apps([]) ->
- ok;
-check_apps([App|Apps]) ->
- case is_app(App) of
- {ok, _} ->
- check_apps(Apps);
- Error ->
- throw({error, {missing_app, {App, Error}}})
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-undef_funcs(suite) ->
- [];
-undef_funcs(doc) ->
- [];
-undef_funcs(Config) when is_list(Config) ->
- App = megaco,
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- Root = code:root_dir(),
- LibDir = code:lib_dir(App),
- EbinDir = filename:join([LibDir,"ebin"]),
- XRefTestName = undef_funcs_make_name(App, xref_test_name),
- {ok, XRef} = xref:start(XRefTestName),
- ok = xref:set_default(XRef,
- [{verbose,false},{warnings,false}]),
- XRefName = undef_funcs_make_name(App, xref_name),
- {ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
- {ok, App} = xref:replace_application(XRef, App, EbinDir),
- {ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
- xref:stop(XRef),
- analyze_undefined_function_calls(Undefs, Mods, []).
-
-analyze_undefined_function_calls([], _, []) ->
- ok;
-analyze_undefined_function_calls([], _, AppUndefs) ->
- exit({suite_failed, {undefined_function_calls, AppUndefs}});
-analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
- AppModules, AppUndefs) ->
- %% Check that this module is our's
- case lists:member(Mod,AppModules) of
- true ->
- {Calling,Called} = AppUndef,
- {Mod1,Func1,Ar1} = Calling,
- {Mod2,Func2,Ar2} = Called,
- io:format("undefined function call: "
- "~n ~w:~w/~w calls ~w:~w/~w~n",
- [Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
- analyze_undefined_function_calls(Undefs, AppModules,
- [AppUndef|AppUndefs]);
- false ->
- io:format("dropping ~p~n", [Mod]),
- analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
- end.
-
-%% This function is used simply to avoid cut-and-paste errors later...
-undef_funcs_make_name(App, PostFix) ->
- list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-fail(Reason) ->
- exit({suite_failed, Reason}).
-
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- undefined ->
- fail({not_found, Key, L});
- {value, {Key, Value}} ->
- Value
- end.
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the megaco app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = test_server:app_test(megaco).
+%%--------------------------------------------------------------------
+appup() ->
+ [{doc, "Test that the megaco appup file is ok"}].
+appup(Config) when is_list(Config) ->
+ ok = test_server:appup_test(megaco).
diff --git a/lib/megaco/test/megaco_appup_test.erl b/lib/megaco/test/megaco_appup_test.erl
index 325e7a6096..8dc3ad51a0 100644
--- a/lib/megaco/test/megaco_appup_test.erl
+++ b/lib/megaco/test/megaco_appup_test.erl
@@ -17,8 +17,6 @@
%%
%% %CopyrightEnd%
%%
-
-%%
%%----------------------------------------------------------------------
%% Purpose: Verify the application specifics of the Megaco application
%%----------------------------------------------------------------------
@@ -27,26 +25,18 @@
-compile(export_all).
-compile({no_auto_import,[error/1]}).
+-include_lib("common_test/include/ct.hrl").
-include("megaco_test_lib.hrl").
--define(APPLICATION, megaco).
-
-t() -> megaco_test_lib:t(?MODULE).
-t(Case) -> megaco_test_lib:t({?MODULE, Case}).
-
-
-%% Test server callbacks
-init_per_testcase(Case, Config) ->
- megaco_test_lib:init_per_testcase(Case, Config).
-
-end_per_testcase(Case, Config) ->
- megaco_test_lib:end_per_testcase(Case, Config).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
all() ->
- [appup].
+ Cases =
+ [
+ appup_file
+ ],
+ Cases.
groups() ->
[].
@@ -64,16 +54,9 @@ end_per_group(_GroupName, Config) ->
init_per_suite(suite) -> [];
init_per_suite(doc) -> [];
init_per_suite(Config) when is_list(Config) ->
- AppFile = file_name(?APPLICATION, ".app"),
- AppupFile = file_name(?APPLICATION, ".appup"),
- [{app_file, AppFile}, {appup_file, AppupFile}|Config].
+ Config.
-file_name(App, Ext) ->
- LibDir = code:lib_dir(App),
- filename:join([LibDir, "ebin", atom_to_list(App) ++ Ext]).
-
-
end_per_suite(suite) -> [];
end_per_suite(doc) -> [];
end_per_suite(Config) when is_list(Config) ->
@@ -82,468 +65,17 @@ end_per_suite(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-appup(suite) ->
- [];
-appup(doc) ->
- "perform a simple check of the appup file";
-appup(Config) when is_list(Config) ->
- AppupFile = key1search(appup_file, Config),
- AppFile = key1search(app_file, Config),
- Modules = modules(AppFile),
- check_appup(AppupFile, Modules).
-
-modules(File) ->
- case file:consult(File) of
- {ok, [{application,megaco,Info}]} ->
- case lists:keysearch(modules,1,Info) of
- {value, {modules, Modules}} ->
- Modules;
- false ->
- fail({bad_appinfo, Info})
- end;
- Error ->
- fail({bad_appfile, Error})
- end.
-
-
-check_appup(AppupFile, Modules) ->
- case file:consult(AppupFile) of
- {ok, [{V, UpFrom, DownTo}]} ->
- check_appup(V, UpFrom, DownTo, Modules);
- Else ->
- fail({bad_appupfile, Else})
- end.
-
-
-check_appup(V, UpFrom, DownTo, Modules) ->
- check_version(V),
- check_depends(up, UpFrom, Modules),
- check_depends(down, DownTo, Modules),
- check_module_subset(UpFrom),
- check_module_subset(DownTo),
- ok.
-
-
-check_depends(_, [], _) ->
- ok;
-check_depends(UpDown, [Dep|Deps], Modules) ->
- check_depend(UpDown, Dep, Modules),
- check_depends(UpDown, Deps, Modules).
-
-
-check_depend(up = UpDown, {add_application, ?APPLICATION} = Instr, Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n Instruction: ~p"
- "~n Modules: ~p", [UpDown, Instr, Modules]),
- ok;
-check_depend(down = UpDown, {remove_application, ?APPLICATION} = Instr,
- Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n Instruction: ~p"
- "~n Modules: ~p", [UpDown, Instr, Modules]),
- ok;
-check_depend(UpDown, {V, Instructions}, Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n V: ~p"
- "~n Modules: ~p", [UpDown, V, Modules]),
- check_version(V),
- case check_instructions(UpDown,
- Instructions, Instructions, [], [], Modules) of
- {_Good, []} ->
- ok;
- {_, Bad} ->
- fail({bad_instructions, Bad, UpDown})
- end.
-
-
-check_instructions(_, [], _, Good, Bad, _) ->
- {lists:reverse(Good), lists:reverse(Bad)};
-check_instructions(UpDown, [Instr|Instrs], AllInstr, Good, Bad, Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n Instr: ~p", [UpDown,Instr]),
- case (catch check_instruction(UpDown, Instr, AllInstr, Modules)) of
- ok ->
- check_instructions(UpDown, Instrs, AllInstr,
- [Instr|Good], Bad, Modules);
- {error, Reason} ->
- d("check_instructions(~w) -> bad instruction: "
- "~n Reason: ~p", [UpDown,Reason]),
- check_instructions(UpDown, Instrs, AllInstr, Good,
- [{Instr, Reason}|Bad], Modules)
- end.
-
-%% A new module is added
-check_instruction(up, {add_module, Module}, _, Modules)
- when is_atom(Module) ->
- d("check_instruction -> entry when up-add_module instruction with"
- "~n Module: ~p", [Module]),
- check_module(Module, Modules);
-
-%% An old module is re-added
-check_instruction(down, {add_module, Module}, _, Modules)
- when is_atom(Module) ->
- d("check_instruction -> entry when down-add_module instruction with"
- "~n Module: ~p", [Module]),
- case (catch check_module(Module, Modules)) of
- {error, {unknown_module, Module, Modules}} ->
- ok;
- ok ->
- error({existing_readded_module, Module})
- end;
-
-%% Removing a module on upgrade:
-%% - the module has been removed from the app-file.
-%% - check that no module depends on this (removed) module
-check_instruction(up, {remove, {Module, Pre, Post}}, _, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) ->
- d("check_instruction -> entry when up-remove instruction with"
- "~n Module: ~p"
- "~n Pre: ~p"
- "~n Post: ~p", [Module, Pre, Post]),
- case (catch check_module(Module, Modules)) of
- {error, {unknown_module, Module, Modules}} ->
- check_purge(Pre),
- check_purge(Post);
- ok ->
- error({existing_removed_module, Module})
- end;
-
-%% Removing a module on downgrade: the module exist
-%% in the app-file.
-check_instruction(down, {remove, {Module, Pre, Post}}, AllInstr, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) ->
- d("check_instruction -> entry when down-remove instruction with"
- "~n Module: ~p"
- "~n Pre: ~p"
- "~n Post: ~p", [Module, Pre, Post]),
- case (catch check_module(Module, Modules)) of
- ok ->
- check_purge(Pre),
- check_purge(Post),
- check_no_remove_depends(Module, AllInstr);
- {error, {unknown_module, Module, Modules}} ->
- error({nonexisting_removed_module, Module})
- end;
-
-check_instruction(_, {load_module, Module, Pre, Post, Depend},
- AllInstr, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) ->
- d("check_instruction -> entry when load_module instruction with"
- "~n Module: ~p"
- "~n Pre: ~p"
- "~n Post: ~p"
- "~n Depend: ~p", [Module, Pre, Post, Depend]),
- check_module(Module, Modules),
- check_module_depend(Module, Depend, Modules),
- check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
- check_purge(Pre),
- check_purge(Post);
-
-check_instruction(_, {update, Module, Change, Pre, Post, Depend},
- AllInstr, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) ->
- d("check_instruction -> entry when update instruction with"
- "~n Module: ~p"
- "~n Change: ~p"
- "~n Pre: ~p"
- "~n Post: ~p"
- "~n Depend: ~p", [Module, Change, Pre, Post, Depend]),
- check_module(Module, Modules),
- check_module_depend(Module, Depend, Modules),
- check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
- check_change(Change),
- check_purge(Pre),
- check_purge(Post);
-
-check_instruction(_, {update, Module, supervisor}, _, Modules)
- when is_atom(Module) ->
- check_module(Module, Modules);
-
-check_instruction(_, {apply, {Module, Function, Args}}, _, Modules)
- when is_atom(Module) andalso is_atom(Function) andalso is_list(Args) ->
- d("check_instruction -> entry when down-apply instruction with"
- "~n Module: ~p"
- "~n Function: ~p"
- "~n Args: ~p", [Module, Function, Args]),
- check_module(Module, Modules),
- check_apply(Module, Function, Args);
-
-check_instruction(_, {restart_application, ?APPLICATION}, _AllInstr, _Modules) ->
- ok;
-
-check_instruction(_, Instr, _AllInstr, _Modules) ->
- d("check_instruction -> entry when unknown instruction with"
- "~n Instr: ~p", [Instr]),
- error({error, {unknown_instruction, Instr}}).
-
-
-%% If Module X depends on Module Y, then module Y must have an update
-%% instruction of some sort (otherwise the depend is faulty).
-updated_modules([], Modules) ->
- d("update_modules -> entry when done with"
- "~n Modules: ~p", [Modules]),
- Modules;
-updated_modules([Instr|Instrs], Modules) ->
- d("update_modules -> entry with"
- "~n Instr: ~p"
- "~n Modules: ~p", [Instr,Modules]),
- Module = instruction_module(Instr),
- d("update_modules -> Module: ~p", [Module]),
- updated_modules(Instrs, [Module|Modules]).
-
-instruction_module({add_module, Module}) ->
- Module;
-instruction_module({remove, {Module, _, _}}) ->
- Module;
-instruction_module({load_module, Module, _, _, _}) ->
- Module;
-instruction_module({update, Module, _, _, _, _}) ->
- Module;
-instruction_module({apply, {Module, _, _}}) ->
- Module;
-instruction_module(Instr) ->
- d("instruction_module -> entry when unknown instruction with"
- "~n Instr: ~p", [Instr]),
- error({error, {unknown_instruction, Instr}}).
-
-
-%% Check that the modules handled in an instruction set for version X
-%% is a subset of the instruction set for version X-1.
-check_module_subset(Instructions) ->
- %% io:format("check_module_subset -> "
- %% "~n Instructions: ~p"
- %% "~n", [Instructions]),
- do_check_module_subset(modules_of(Instructions)).
-
-do_check_module_subset([]) ->
- ok;
-do_check_module_subset([_]) ->
- ok;
-do_check_module_subset([{_V1, Mods1}|T]) ->
- %% io:format("do_check_module_subset -> "
- %% "~n V1: ~p"
- %% "~n Mods1: ~p"
- %% "~n T: ~p"
- %% "~n", [_V1, Mods1, T]),
- {V2, Mods2} = hd(T),
- %% Check that the modules in V1 is a subset of V2
- case do_check_module_subset2(Mods1, Mods2) of
- ok ->
- do_check_module_subset(T);
- {error, Modules} ->
- fail({subset_missing_instructions, V2, Modules})
- end.
-
-do_check_module_subset2(Mods1, Mods2) ->
- do_check_module_subset2(Mods1, Mods2, []).
-
-do_check_module_subset2([], _, []) ->
- ok;
-do_check_module_subset2([], _, Acc) ->
- {error, lists:reverse(Acc)};
-do_check_module_subset2([Mod|Mods], Mods2, Acc) ->
- case lists:member(Mod, Mods2) of
- true ->
- do_check_module_subset2(Mods, Mods2, Acc);
- false ->
- do_check_module_subset2(Mods, Mods2, [Mod|Acc])
- end.
-
-
-modules_of(Instructions) ->
- modules_of(Instructions, []).
-
-modules_of([], Acc) ->
- lists:reverse(Acc);
-modules_of([{V,Instructions}|T], Acc) ->
- %% io:format("modules_of -> "
- %% "~n V: ~p"
- %% "~n Instructions: ~p"
- %% "~n", [V, Instructions]),
- case modules_of2(Instructions, []) of
- Mods when is_list(Mods) ->
- %% io:format("modules_of -> "
- %% "~n Mods: ~p"
- %% "~n", [Mods]),
- modules_of(T, [{V, Mods}|Acc]);
- skip ->
- %% io:format("modules_of -> skip"
- %% "~n", []),
- modules_of(T, Acc)
- end.
-
-modules_of2([], Acc) ->
- lists:reverse(Acc);
-modules_of2([Instr|Instructions], Acc) ->
- case module_of(Instr) of
- {value, Mod} ->
- modules_of2(Instructions, [Mod|Acc]);
- skip ->
- skip;
- false ->
- modules_of2(Instructions, Acc)
- end.
-
-module_of({add_module, Module}) ->
- {value, Module};
-module_of({remove, {Module, _Pre, _Post}}) ->
- {value, Module};
-module_of({load_module, Module, _Pre, _Post, _Depend}) ->
- {value, Module};
-module_of({update, Module, _Change, _Pre, _Post, _Depend}) ->
- {value, Module};
-module_of({restart_application, _App}) ->
- skip;
-module_of(_) ->
- false.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% The version is a string consting of numbers separated by dots: "."
-%% Example: "3.3.3"
-%%
-check_version(V) when is_list(V) ->
- case do_check_version(string:tokens(V, [$.])) of
- ok ->
- ok;
- {error, BadVersionPart} ->
- throw({error, {bad_version, V, BadVersionPart}})
- end;
-check_version(V) ->
- error({bad_version, V}).
-
-do_check_version([]) ->
- ok;
-do_check_version([H|T]) ->
- case (catch list_to_integer(H)) of
- I when is_integer(I) ->
- do_check_version(T);
- _ ->
- {error, H}
- end.
-
-check_module(M, Modules) when is_atom(M) ->
- case lists:member(M,Modules) of
- true ->
- ok;
- false ->
- error({unknown_module, M, Modules})
- end;
-check_module(M, _) ->
- error({bad_module, M}).
-
-
-check_module_depend(M, [], _) when is_atom(M) ->
- d("check_module_depend -> entry with"
- "~n M: ~p", [M]),
- ok;
-check_module_depend(M, Deps, Modules) when is_atom(M) andalso is_list(Deps) ->
- d("check_module_depend -> entry with"
- "~n M: ~p"
- "~n Deps: ~p"
- "~n Modules: ~p", [M, Deps, Modules]),
- case [Dep || Dep <- Deps, lists:member(Dep, Modules) == false] of
- [] ->
- ok;
- Unknown ->
- error({unknown_depend_modules, Unknown})
- end;
-check_module_depend(_M, D, _Modules) ->
- d("check_module_depend -> entry when bad depend with"
- "~n D: ~p", [D]),
- error({bad_depend, D}).
-
-
-check_no_remove_depends(_Module, []) ->
- ok;
-check_no_remove_depends(Module, [Instr|Instrs]) ->
- check_no_remove_depend(Module, Instr),
- check_no_remove_depends(Module, Instrs).
-
-check_no_remove_depend(Module, {load_module, Mod, _Pre, _Post, Depend}) ->
- case lists:member(Module, Depend) of
- true ->
- error({removed_module_in_depend, load_module, Mod, Module});
- false ->
- ok
- end;
-check_no_remove_depend(Module, {update, Mod, _Change, _Pre, _Post, Depend}) ->
- case lists:member(Module, Depend) of
- true ->
- error({removed_module_in_depend, update, Mod, Module});
- false ->
- ok
- end;
-check_no_remove_depend(_, _) ->
- ok.
-
-
-check_change(soft) ->
- ok;
-check_change({advanced, _Something}) ->
- ok;
-check_change(Change) ->
- error({bad_change, Change}).
-
-
-check_purge(soft_purge) ->
- ok;
-check_purge(brutal_purge) ->
- ok;
-check_purge(Purge) ->
- error({bad_purge, Purge}).
-
-
-check_apply(Module, Function, Args) ->
- case (catch Module:module_info()) of
- Info when is_list(Info) ->
- check_exported(Function, Args, Info);
- {'EXIT', {undef, _}} ->
- error({not_existing_module, Module})
- end.
-
-check_exported(Function, Args, Info) ->
- case lists:keysearch(exports, 1, Info) of
- {value, {exports, FuncList}} ->
- Arity = length(Args),
- Arities = [A || {F, A} <- FuncList, F == Function],
- case lists:member(Arity, Arities) of
- true ->
- ok;
- false ->
- error({not_exported_function, Function, Arity})
- end;
- _ ->
- error({bad_export, Info})
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-error(Reason) ->
- throw({error, Reason}).
-
-fail(Reason) ->
- exit({suite_failed, Reason}).
+%% Test server callbacks
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- undefined ->
- fail({not_found, Key, L});
- {value, {Key, Value}} ->
- Value
- end.
+end_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-d(F, A) ->
- d(false, F, A).
+%% Perform a simple check of the appup file
+appup_file(Config) when is_list(Config) ->
+ ok = ?t:appup_test(megaco).
-d(true, F, A) ->
- io:format(F ++ "~n", A);
-d(_, _, _) ->
- ok.
-
-
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index b95cd66a81..0d40f863b2 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2015. All Rights Reserved.
+# Copyright Ericsson AB 1997-2016. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/doc/src/Mnesia_chap1.xml b/lib/mnesia/doc/src/Mnesia_chap1.xml
index 9dfeb5efe4..035e934ed2 100644
--- a/lib/mnesia/doc/src/Mnesia_chap1.xml
+++ b/lib/mnesia/doc/src/Mnesia_chap1.xml
@@ -32,38 +32,38 @@
<rev>C</rev>
<file>Mnesia_chap1.xml</file>
</header>
- <p>The <c>Mnesia</c> application provides a heavy duty real-time
+ <p>The Mnesia application provides a heavy duty real-time
distributed database.</p>
<section>
<title>Scope</title>
<p>This User's Guide describes how to
- build <c>Mnesia</c> database applications, and how to integrate
- and use the <c>Mnesia</c> database management system with
+ build Mnesia database applications, and how to integrate
+ and use the Mnesia database management system with
OTP. Programming constructs are described, and numerous
programming examples are included to illustrate the use of
- <c>Mnesia</c>.</p>
+ Mnesia.</p>
<p>This User's Guide is organized as follows:</p>
<list type="bulleted">
<item><seealso marker="Mnesia_overview">Mnesia</seealso>
provides an introduction to
- <c>Mnesia</c>.
+ Mnesia.
</item>
<item><seealso marker="Mnesia_chap2">Getting Started</seealso>
- introduces <c>Mnesia</c> with an example database. Examples
+ introduces Mnesia with an example database. Examples
are included how to start an Erlang session, specify a
- <c>Mnesia</c> database directory, initialize a database
- schema, start <c>Mnesia</c>, and create tables. Initial
+ Mnesia database directory, initialize a database
+ schema, start Mnesia, and create tables. Initial
prototyping of record definitions is also discussed.
</item>
<item><seealso marker="Mnesia_chap3">Build a Mnesia
Database</seealso> more formally describes the steps
- introduced in the previous section, namely the <c>Mnesia</c>
- functions that define a database schema, start <c>Mnesia</c>,
+ introduced in the previous section, namely the Mnesia
+ functions that define a database schema, start Mnesia,
and create the required tables.
</item>
<item><seealso marker="Mnesia_chap4">Transactions and Other Access Contexts</seealso>
- describes the transactions properties that make <c>Mnesia</c> into
+ describes the transactions properties that make Mnesia into
a fault tolerant, real-time distributed database management
system. This section also describes the concept of locking
to ensure consistency in tables, and "dirty
@@ -76,16 +76,16 @@
features include indexing, checkpoints, distribution and fault
tolerance, disc-less nodes, replication manipulation, local
content tables, concurrency, and object-based programming in
- <c>Mnesia</c>.
+ Mnesia.
</item>
<item><seealso marker="Mnesia_chap7">Mnesia System
Information</seealso> describes the files contained in the
- <c>Mnesia</c> database directory, database configuration data,
+ Mnesia database directory, database configuration data,
core and table dumps, as well as the important subject of
backup, fall-back, and disaster recovery principles.
</item>
<item><seealso marker="Mnesia_chap8">Combine Mnesia with
- SNMP</seealso> is a short section that outlines <c>Mnesia</c>
+ SNMP</seealso> is a short section that outlines Mnesia
integrated with SNMP.
</item>
<item><seealso marker="Mnesia_App_A">Appendix A: Backup
diff --git a/lib/mnesia/doc/src/Mnesia_chap8.xml b/lib/mnesia/doc/src/Mnesia_chap8.xml
index f1a469e315..4a2eed84d7 100644
--- a/lib/mnesia/doc/src/Mnesia_chap8.xml
+++ b/lib/mnesia/doc/src/Mnesia_chap8.xml
@@ -51,11 +51,11 @@
</item>
</list>
<p>All these approaches have different advantages and
- disadvantages. <c>Mnesia</c> applications can easily be opened to
+ disadvantages. Mnesia applications can easily be opened to
the SNMP protocol. A direct 1-to-1 mapping can be established
- between <c>Mnesia</c> tables and SNMP tables. This means
- that a <c>Mnesia</c> table can be configured to be <em>both</em>
- a <c>Mnesia</c> table and an SNMP table. A number of functions to
+ between Mnesia tables and SNMP tables. This means
+ that a Mnesia table can be configured to be <em>both</em>
+ a Mnesia table and an SNMP table. A number of functions to
control this behavior are described in the Reference Manual.</p>
</section>
</chapter>
diff --git a/lib/mnesia/doc/src/Mnesia_overview.xml b/lib/mnesia/doc/src/Mnesia_overview.xml
index d2d597b85d..63f2309284 100644
--- a/lib/mnesia/doc/src/Mnesia_overview.xml
+++ b/lib/mnesia/doc/src/Mnesia_overview.xml
@@ -39,14 +39,14 @@
high level of fault tolerance that is required in many nonstop
systems, combined with requirements on the DBMS to run in the same
address space as the application, have led us to implement a new
- DBMS, called <c>Mnesia</c>.</p>
- <p><c>Mnesia</c> is implemented in, and tightly connected to Erlang.
+ DBMS, called Mnesia.</p>
+ <p>Mnesia is implemented in, and tightly connected to Erlang.
It provides the functionality that is necessary for the
implementation of fault tolerant telecommunications systems.</p>
- <p><c>Mnesia</c> is a multiuser distributed DBMS specially made for
+ <p>Mnesia is a multiuser distributed DBMS specially made for
industrial telecommunications applications written in Erlang,
which is also the intended target language.
- <c>Mnesia</c> tries to address all the data
+ Mnesia tries to address all the data
management issues required for typical telecommunications systems.
It has a number of features that are not normally found in traditional
databases.</p>
@@ -54,7 +54,7 @@
from the features provided by traditional DBMSs. The applications now
implemented in Erlang need a mixture of a broad range
of features, which generally are not satisfied by traditional DBMSs.
- <c>Mnesia</c> is designed with requirements like the following in
+ Mnesia is designed with requirements like the following in
mind:</p>
<list type="ordered">
<item>Fast real-time key/value lookup
@@ -71,9 +71,9 @@
<item>Complex objects
</item>
</list>
- <p><c>Mnesia</c> is designed with the typical data management problems
- of telecommunications applications in mind. This sets <c>Mnesia</c>
- apart from most other DBMS. Hence <c>Mnesia</c>
+ <p>Mnesia is designed with the typical data management problems
+ of telecommunications applications in mind. This sets Mnesia
+ apart from most other DBMS. Hence Mnesia
combines many concepts found in traditional databases such as
transactions and queries with concepts found in data management
systems for telecommunications applications, for example:</p>
@@ -86,7 +86,7 @@
suspending it.
</item>
</list>
- <p><c>Mnesia</c> is also interesting because of its tight coupling to
+ <p>Mnesia is also interesting because of its tight coupling to
Erlang, thus almost turning Erlang into a database programming
language. This has many benefits, the foremost is that
the impedance mismatch between the data format used by the DBMS
@@ -97,7 +97,7 @@
<title>Mnesia Database Management System (DBMS)</title>
<section>
<title>Features</title>
- <p><c>Mnesia</c> contains the following features that combine to
+ <p>Mnesia contains the following features that combine to
produce a fault-tolerant, distributed DBMS written in Erlang:
</p>
<list type="bulleted">
@@ -118,7 +118,7 @@
functions can be called within one transaction.
</item>
<item>Several transactions can run concurrently, and their execution
- is fully synchronized by the DBMS. <c>Mnesia</c> ensures that no
+ is fully synchronized by the DBMS. Mnesia ensures that no
two processes manipulate data simultaneously.
</item>
<item>Transactions can be assigned the property of being executed on
@@ -132,29 +132,29 @@
<section>
<title>Add-On Application</title>
- <p>Query List Comprehension (QLC) can be used with <c>Mnesia</c>
+ <p>Query List Comprehension (QLC) can be used with Mnesia
to produce specialized functions that enhance the operational
- ability of <c>Mnesia</c>. QLC has its own documentation as part
+ ability of Mnesia. QLC has its own documentation as part
of the OTP documentation set. The main features of QLC
- when used with <c>Mnesia</c> are as follows:</p>
+ when used with Mnesia are as follows:</p>
<list type="bulleted">
- <item>QLC can optimize the query compiler for the <c>Mnesia</c>
+ <item>QLC can optimize the query compiler for the Mnesia
DBMS, essentially making the DBMS more efficient.
</item>
<item>QLC can be used as a database programming
- language for <c>Mnesia</c>. It includes a notation called "list
+ language for Mnesia. It includes a notation called "list
comprehensions" and can be used to make complex database
queries over a set of tables.
</item>
</list>
<p>For information about QLC, see the
<seealso marker="stdlib:qlc">qlc</seealso> manual page
- in <c>STDLIB</c>.</p>
+ in STDLIB.</p>
</section>
<section>
<title>When to Use Mnesia</title>
- <p>Use <c>Mnesia</c> with the following types of applications:</p>
+ <p>Use Mnesia with the following types of applications:</p>
<list type="bulleted">
<item>Applications that need to replicate data.
</item>
@@ -166,7 +166,7 @@
<item>Applications that use soft real-time characteristics.
</item>
</list>
- <p><c>Mnesia</c> is not as appropriate with the
+ <p>Mnesia is not as appropriate with the
following types of applications:</p>
<list type="bulleted">
<item>Programs that process plain text or binary data files.
@@ -176,14 +176,14 @@
library module <c>dets</c>, which is a disc-based version
of the module <c>ets</c>. For information about <c>dets</c>,
see the <seealso marker="stdlib:dets">dets</seealso>
- manual page in <c>STDLIB</c>.
+ manual page in STDLIB.
</item>
<item>Applications that need disc logging facilities.
Those applications can
use the module <c>disk_log</c> by preference. For
information about <c>disk_log</c>, see the
<seealso marker="kernel:disk_log">disk_log</seealso>
- manual page in <c>Kernel</c>.
+ manual page in Kernel.
</item>
<item>Hard real-time systems.
</item>
diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml
index b35214cde9..621b6047ee 100644
--- a/lib/mnesia/doc/src/mnesia.xml
+++ b/lib/mnesia/doc/src/mnesia.xml
@@ -37,7 +37,7 @@
<description>
<p>The following are some of the most important and attractive
- capabilities provided by <c>Mnesia</c>:</p>
+ capabilities provided by Mnesia:</p>
<list type="bulleted">
<item>A relational/object hybrid data model that is suitable
for telecommunications applications.
@@ -62,15 +62,15 @@
reconfigured at runtime without stopping the system.
</item>
</list>
- <p>This Reference Manual describes the <c>Mnesia</c> API. This
- includes functions that define and manipulate <c>Mnesia</c>
+ <p>This Reference Manual describes the Mnesia API. This
+ includes functions that define and manipulate Mnesia
tables.</p>
<p>All functions in this Reference Manual can be used in any
combination with queries using the list comprehension notation.
For information about the query notation, see the
<seealso marker="stdlib:qlc">qlc</seealso>
- manual page in <c>STDLIB</c>.</p>
- <p>Data in <c>Mnesia</c> is organized as a set of tables. Each table
+ manual page in STDLIB.</p>
+ <p>Data in Mnesia is organized as a set of tables. Each table
has a name that must be an atom. Each table is made up of
Erlang records. The user is responsible for the record
definitions. Each table also has a set of properties. The
@@ -121,14 +121,14 @@
<item>
<p><c>index</c>. This is a list of attribute names, or
integers, which specify the tuple positions on which
- <c>Mnesia</c> is to build and maintain an extra index
+ Mnesia is to build and maintain an extra index
table.</p>
</item>
<item>
<p><c>local_content</c>. When an application requires
tables whose contents are local to each node,
<c>local_content</c> tables can be used. The table name
- is known to all <c>Mnesia</c> nodes, but its content is
+ is known to all Mnesia nodes, but its content is
unique on each node. This means that access to such a table
must be done locally. Set field <c>local_content</c> to
<c>true</c> to enable the <c>local_content</c>
@@ -143,7 +143,7 @@
avoid inconsistencies because of network splits.</p>
</item>
<item>
- <p><c>snmp</c>. Each (set-based) <c>Mnesia</c> table can be
+ <p><c>snmp</c>. Each (set-based) Mnesia table can be
automatically turned into a Simple Network Management
Protocol (SNMP) ordered table as well.
This property specifies the types of the SNMP keys.</p>
@@ -174,7 +174,7 @@
copy of each modified record during the transaction. During
iteration, that is, <c>mnesia:fold[lr]/4</c>,
<c>mnesia:next/2</c>, <c>mnesia:prev/2</c>, and
- <c>mnesia:snmp_get_next_index/2</c>, <c>Mnesia</c>
+ <c>mnesia:snmp_get_next_index/2</c>, Mnesia
compensates for every written or deleted record, which can
reduce the performance.</p>
<p>If possible, avoid writing or deleting records in the same
@@ -188,7 +188,7 @@
<desc>
<p>Makes the transaction silently
return the tuple <c>{aborted, Reason}</c>.
- Termination of a <c>Mnesia</c> transaction means that
+ Termination of a Mnesia transaction means that
an exception is thrown to an enclosing <c>catch</c>.
Thus, the expression <c>catch mnesia:abort(x)</c> does
not terminate the transaction.</p>
@@ -324,7 +324,7 @@
<c>mnesia:ets</c>. Argument <c>AccessMod</c>
is the name of a callback module, which implements the
<c>mnesia_access</c> behavior.</p>
- <p><c>Mnesia</c> forwards calls to the following functions:</p>
+ <p>Mnesia forwards calls to the following functions:</p>
<list type="bulleted">
<item>mnesia:lock/2 (read_lock_table/1, write_lock_table/1)
</item>
@@ -391,15 +391,15 @@
</item>
</list>
<p><c>ActivityId</c> is a record that represents the identity
- of the enclosing <c>Mnesia</c> activity. The first field
+ of the enclosing Mnesia activity. The first field
(obtained with <c>element(1, ActivityId)</c>) contains an
atom, which can be interpreted as the activity type:
<c>ets</c>, <c>async_dirty</c>, <c>sync_dirty</c>, or
<c>tid</c>. <c>tid</c> means that the activity is a
transaction. The structure of the rest of the identity
- record is internal to <c>Mnesia</c>.</p>
+ record is internal to Mnesia.</p>
<p><c>Opaque</c> is an opaque data structure that is internal
- to <c>Mnesia</c>.</p>
+ to Mnesia.</p>
</desc>
</func>
<func>
@@ -458,7 +458,7 @@ mnesia:add_table_index(person, age)</code>
<desc>
<marker id="async_dirty"></marker>
<p>Calls the <c>Fun</c> in a context that is not protected by
- a transaction. The <c>Mnesia</c> function calls performed in
+ a transaction. The Mnesia function calls performed in
the <c>Fun</c> are mapped to the corresponding dirty
functions. This still involves logging, replication, and
subscriptions, but there is no locking, local transaction
@@ -467,7 +467,7 @@ mnesia:add_table_index(person, age)</code>
for normal <c>mnesia:dirty_*</c> operations, the operations
are performed semi-asynchronously. For details, see
<c>mnesia:activity/4</c> and the User's Guide.</p>
- <p>The <c>Mnesia</c> tables can be manipulated without
+ <p>The Mnesia tables can be manipulated without
using transactions. This has some serious disadvantages, but
is considerably faster, as the transaction manager is not
involved and no locks are set. A dirty operation does,
@@ -480,7 +480,7 @@ mnesia:add_table_index(person, age)</code>
read records dirty than within a transaction.</p>
<p>Depending on the application, it can be a good idea to use
the dirty functions for certain operations. Almost all
- <c>Mnesia</c> functions that can be called within
+ Mnesia functions that can be called within
transactions have a dirty equivalent, which is much more
efficient.</p>
<p>However, notice that there is a risk that the database can
@@ -497,7 +497,7 @@ mnesia:add_table_index(person, age)</code>
<fsummary>Backs up all tables in the database.</fsummary>
<desc>
<marker id="backup"></marker>
- <p>Activates a new checkpoint covering all <c>Mnesia</c> tables,
+ <p>Activates a new checkpoint covering all Mnesia tables,
including the schema, with maximum degree of redundancy, and
performs a backup using <c>backup_checkpoint/2/3</c>. The
default value of the backup callback module <c>BackupMod</c>
@@ -529,16 +529,16 @@ mnesia:add_table_index(person, age)</code>
<taglist>
<tag><c>extra_db_nodes</c></tag>
<item>
- <p><c>Value</c> is a list of nodes that <c>Mnesia</c>
+ <p><c>Value</c> is a list of nodes that Mnesia
is to try to connect to. <c>ReturnValue</c> is those
- nodes in <c>Value</c> that <c>Mnesia</c> is connected
+ nodes in <c>Value</c> that Mnesia is connected
to.</p>
<p>Notice that this function must only be used to connect
to newly started RAM nodes (N.D.R.S.N.) with an empty
schema. If, for example, this function is used after
the network has been partitioned, it can lead to
inconsistent tables.</p>
- <p>Notice that <c>Mnesia</c> can be connected to other
+ <p>Notice that Mnesia can be connected to other
nodes than those returned in <c>ReturnValue</c>.</p>
</item>
<tag><c>dc_dump_limit</c></tag>
@@ -548,7 +548,7 @@ mnesia:add_table_index(person, age)</code>
Configuration Parameters</seealso>. <c>ReturnValue</c>
is the new value. Notice that this configuration
parameter is not persistent. It is lost when
- <c>Mnesia</c> has stopped.</p>
+ Mnesia has stopped.</p>
</item>
</taglist>
</desc>
@@ -562,9 +562,9 @@ mnesia:add_table_index(person, age)</code>
<c>read_write</c> but it can also be set to the atom
<c>read_only</c>. If <c>AccessMode</c> is set to
<c>read_only</c>, updates to the table cannot be
- performed. At startup, <c>Mnesia</c> always loads
+ performed. At startup, Mnesia always loads
<c>read_only</c> tables locally regardless of when and if
- <c>Mnesia</c> is terminated on other nodes.</p>
+ Mnesia is terminated on other nodes.</p>
</desc>
</func>
<func>
@@ -620,13 +620,13 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
<desc>
<marker id="create_schema"></marker>
<p>Creates a new database on disc. Various files are
- created in the local <c>Mnesia</c> directory of each node.
+ created in the local Mnesia directory of each node.
Notice that the directory must be unique for each node.
Two nodes must never share the same directory. If possible,
use a local disc device to improve performance.</p>
<p><c>mnesia:create_schema/1</c> fails if any of the
Erlang nodes given as <c>DiscNodes</c> are not alive, if
- <c>Mnesia</c> is running on any of the nodes, or if any
+ Mnesia is running on any of the nodes, or if any
of the nodes already have a schema. Use
<c>mnesia:delete_schema/1</c> to get rid of old faulty
schemas.</p>
@@ -638,10 +638,10 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
</func>
<func>
<name>create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name>
- <fsummary>Creates a <c>Mnesia</c> table called <c>Name</c>with properties as described by argument <c>TabDef</c>.</fsummary>
+ <fsummary>Creates a Mnesia table called <c>Name</c>with properties as described by argument <c>TabDef</c>.</fsummary>
<desc>
<marker id="create_table"></marker>
- <p>Creates a <c>Mnesia</c> table called
+ <p>Creates a Mnesia table called
<c>Name</c> according to argument <c>TabDef</c>. This
list must be a list of <c>{Item, Value}</c> tuples,
where the following values are allowed:</p>
@@ -652,8 +652,8 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
set to the atom <c>read_only</c>. If <c>AccessMode</c>
is set to <c>read_only</c>, updates to the table
cannot be performed.</p>
- <p>At startup, <c>Mnesia</c> always loads <c>read_only</c>
- table locally regardless of when and if <c>Mnesia</c> is
+ <p>At startup, Mnesia always loads <c>read_only</c>
+ table locally regardless of when and if Mnesia is
terminated on other nodes. This argument returns the
access mode of the table. The access mode can be
<c>read_only</c> or <c>read_write</c>.</p>
@@ -693,7 +693,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
<item>
<p><c>{index, Intlist}</c>, where
<c>Intlist</c> is a list of attribute names (atoms) or
- record fields for which <c>Mnesia</c> is to build and
+ record fields for which Mnesia is to build and
maintain an extra index table. The <c>qlc</c> query
compiler <em>may</em> be able to optimize queries
if there are indexes available.</p>
@@ -735,10 +735,10 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
<c>mnesia:create_table/2</c>, the table is immediately
accessible by SNMP. Therefore applications that use
SNMP to manipulate and control the system can be
- designed easily, since <c>Mnesia</c> provides a
+ designed easily, since Mnesia provides a
direct mapping between the logical tables that make up
an SNMP control application and the physical data that
- makes up a <c>Mnesia</c> table.</p>
+ makes up a Mnesia table.</p>
</item>
<item>
<p><c>{storage_properties, [{Backend, Properties}]</c>
@@ -746,7 +746,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
<c>Backend</c> can currently be <c>ets</c> or <c>dets</c>.
<c>Properties</c> is a list of options sent to the
back end storage during table creation. <c>Properties</c>
- cannot contain properties already used by <c>Mnesia</c>,
+ cannot contain properties already used by Mnesia,
such as <c>type</c> or <c>named_table</c>.</p>
<p>For example:</p>
<code type="none">
@@ -776,7 +776,7 @@ mnesia:create_table(table, [{ram_copies, [node()]}, {disc_only_copies, nodes()},
mnesia:create_table(person,
[{ram_copies, [N1, N2]},
{attributes, record_info(fields, person)}]).</code>
- <p>If it is required that <c>Mnesia</c> must build and
+ <p>If it is required that Mnesia must build and
maintain an extra index table on attribute <c>address</c>
of all the <c>person</c> records that are inserted in the
table, the following code would be issued:</p>
@@ -819,8 +819,8 @@ mnesia:create_table(person,
When the last replica is deleted with this
function, the table disappears entirely.</p>
<p>This function can also be used to delete a replica of
- the table named <c>schema</c>. The <c>Mnesia</c> node is
- then removed. Notice that <c>Mnesia</c> must be
+ the table named <c>schema</c>. The Mnesia node is
+ then removed. Notice that Mnesia must be
stopped on the node first.</p>
</desc>
</func>
@@ -891,9 +891,9 @@ mnesia:create_table(person,
<c>mnesia:create_schema/1</c>.
<c>mnesia:delete_schema/1</c> fails if any of the Erlang
nodes given as <c>DiscNodes</c> are not alive, or if
- <c>Mnesia</c> is running on any of the nodes.</p>
+ Mnesia is running on any of the nodes.</p>
<p>After the database is deleted, it can still be possible
- to start <c>Mnesia</c> as a disc-less node. This depends
+ to start Mnesia as a disc-less node. This depends
on how configuration parameter <c>schema_location</c> is
set.</p>
<warning>
@@ -1100,7 +1100,7 @@ mnesia:create_table(person,
<name>dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name>
<fsummary>Dirty update of a counter record.</fsummary>
<desc>
- <p><c>Mnesia</c> has no special counter records. However,
+ <p>Mnesia has no special counter records. However,
records of the form <c>{Tab, Key, Integer}</c> can be used
as (possibly disc-resident) counters when <c>Tab</c> is a
<c>set</c>. This function updates a counter with a positive
@@ -1147,7 +1147,7 @@ mnesia:create_table(person,
<desc>
<marker id="dump_log"></marker>
<p>Performs a user-initiated dump of the local log file.
- This is usually not necessary, as <c>Mnesia</c> by default
+ This is usually not necessary, as Mnesia by default
manages this automatically. See configuration parameters
<seealso marker="#dump_log_time_threshold">dump_log_time_threshold</seealso>
and
@@ -1172,7 +1172,7 @@ mnesia:create_table(person,
<fsummary>Dumps local tables into a text file.</fsummary>
<desc>
<marker id="dump_to_textfile"></marker>
- <p>Dumps all local tables of a <c>Mnesia</c> system into a
+ <p>Dumps all local tables of a Mnesia system into a
text file, which can be edited (by a normal text editor)
and then be reloaded with
<c>mnesia:load_textfile/1</c>. Only use this function for
@@ -1182,10 +1182,10 @@ mnesia:create_table(person,
</func>
<func>
<name>error_description(Error) -> String</name>
- <fsummary>Returns a string describing a particular <c>Mnesia</c> error.</fsummary>
+ <fsummary>Returns a string describing a particular Mnesia error.</fsummary>
<desc>
<marker id="error_description"></marker>
- <p>All <c>Mnesia</c> transactions, including all the schema
+ <p>All Mnesia transactions, including all the schema
update functions, either return value <c>{atomic, Val}</c>
or the tuple <c>{aborted, Reason}</c>. <c>Reason</c> can
be either of the atoms in the following list. The
@@ -1264,8 +1264,8 @@ mnesia:create_table(person,
<desc>
<marker id="ets"></marker>
<p>Calls the <c>Fun</c> in a raw context that is not protected by
- a transaction. The <c>Mnesia</c> function call is performed in
- the <c>Fun</c> and performed directly on the local <c>ets</c>
+ a transaction. The Mnesia function call is performed in
+ the <c>Fun</c> and performed directly on the local ETS
tables on the assumption that the local storage type is
<c>ram_copies</c> and the tables are not replicated to other
nodes. Subscriptions are not triggered and checkpoints are
@@ -1321,13 +1321,13 @@ mnesia:create_table(person,
<fsummary>Forces a table to be loaded into the system.</fsummary>
<desc>
<marker id="force_load_table"></marker>
- <p>The <c>Mnesia</c> algorithm for table load can lead to a
+ <p>The Mnesia algorithm for table load can lead to a
situation where a table cannot be loaded. This situation
- occurs when a node is started and <c>Mnesia</c> concludes, or
+ occurs when a node is started and Mnesia concludes, or
suspects, that another copy of the table was active after
this local copy became inactive because of a system crash.</p>
<p>If this situation is not acceptable, this function can be
- used to override the strategy of the <c>Mnesia</c> table
+ used to override the strategy of the Mnesia table
load algorithm. This can lead to a situation where some
transaction effects are lost with an inconsistent database as
result, but for some applications high availability is more
@@ -1402,9 +1402,9 @@ mnesia:create_table(person,
<desc>
<marker id="info"></marker>
<p>Prints system information on the terminal.
- This function can be used even if <c>Mnesia</c> is not
+ This function can be used even if Mnesia is not
started. However, more information is displayed if
- <c>Mnesia</c> is started.</p>
+ Mnesia is started.</p>
</desc>
</func>
<func>
@@ -1431,7 +1431,7 @@ mnesia:create_table(person,
<p>Installs a backup as fallback. The fallback is used to
restore the database at the next startup. Installation of
fallbacks requires Erlang to be operational on all the
- involved nodes, but it does not matter if <c>Mnesia</c>
+ involved nodes, but it does not matter if Mnesia
is running or not. The installation of the fallback fails
if the local node is not one of the disc-resident nodes
in the backup.</p>
@@ -1465,14 +1465,14 @@ mnesia:create_table(person,
<p><c>{mnesia_dir, AlternateDir}</c>.
This argument is only valid if the scope of the
installation is <c>local</c>. Normally the installation
- of a fallback is targeted to the <c>Mnesia</c> directory,
+ of a fallback is targeted to the Mnesia directory,
as configured with configuration parameter
<c>-mnesia dir</c>. But by explicitly supplying an
<c>AlternateDir</c>, the fallback is installed there
- regardless of the <c>Mnesia</c> directory configuration
+ regardless of the Mnesia directory configuration
parameter setting. After installation of a fallback on
- an alternative <c>Mnesia</c> directory, that directory
- is fully prepared for use as an active <c>Mnesia</c>
+ an alternative Mnesia directory, that directory
+ is fully prepared for use as an active Mnesia
directory.</p>
<p>This is a dangerous feature that must be
used with care. By unintentional mixing of directories,
@@ -1509,7 +1509,7 @@ mnesia:create_table(person,
<marker id="load_textfile"></marker>
<p>Loads a series of definitions and data found in the
text file (generated with <c>mnesia:dump_to_textfile/1</c>)
- into <c>Mnesia</c>. This function also starts <c>Mnesia</c>
+ into Mnesia. This function also starts Mnesia
and possibly creates a new schema. This function is
intended for educational purposes only. It is recommended
to use other functions to deal with real backups.</p>
@@ -1558,7 +1558,7 @@ mnesia:create_table(person,
</taglist>
<p>Conflicting lock requests are automatically queued if there
is no risk of a deadlock. Otherwise the transaction must be
- terminated and executed again. <c>Mnesia</c> does this
+ terminated and executed again. Mnesia does this
automatically as long as the upper limit of the maximum
<c>retries</c> is not reached. For details, see
<c>mnesia:transaction/3</c>.</p>
@@ -1726,19 +1726,19 @@ mnesia:create_table(person,
</func>
<func>
<name>report_event(Event) -> ok</name>
- <fsummary>Reports a user event to the <c>Mnesia</c> event handler.</fsummary>
+ <fsummary>Reports a user event to the Mnesia event handler.</fsummary>
<desc>
<marker id="report_event"></marker>
- <p>When tracing a system of <c>Mnesia</c> applications it is
- useful to be able to interleave <c>Mnesia</c> own events with
+ <p>When tracing a system of Mnesia applications it is
+ useful to be able to interleave Mnesia own events with
application-related events that give information about the
application context.</p>
<p>Whenever the application begins a
- new and demanding <c>Mnesia</c> task, or if it enters a new
+ new and demanding Mnesia task, or if it enters a new
interesting phase in its execution, it can be a good idea to
use <c>mnesia:report_event/1</c>. <c>Event</c> can be
any term and generates a <c>{mnesia_user, Event}</c> event
- for any processes that subscribe to <c>Mnesia</c> system
+ for any processes that subscribe to Mnesia system
events.</p>
</desc>
</func>
@@ -1748,7 +1748,7 @@ mnesia:create_table(person,
<desc>
<marker id="restore"></marker>
<p>With this function, tables can be restored online from a
- backup without restarting <c>Mnesia</c>.
+ backup without restarting Mnesia.
<c>Opaque</c> is forwarded to the backup module.
<c>Args</c> is a list of the following tuples:</p>
<list type="bulleted">
@@ -1873,7 +1873,7 @@ mnesia:create_table(person,
<p>For a complete description of <c>select</c>, see the
<seealso marker="erts:index">ERTS</seealso> User's Guide and the
<seealso marker="stdlib:ets">ets</seealso> manual page in
- <c>STDLIB</c>.</p>
+ STDLIB.</p>
<p>For example, to find the names of all male persons older
than 30 in table <c>Tab</c>:</p>
<code type="none">
@@ -1920,10 +1920,10 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</func>
<func>
<name>set_debug_level(Level) -> OldLevel</name>
- <fsummary>Changes the internal debug level of <c>Mnesia</c>.</fsummary>
+ <fsummary>Changes the internal debug level of Mnesia.</fsummary>
<desc>
<marker id="set_debug_level"></marker>
- <p>Changes the internal debug level of <c>Mnesia</c>.
+ <p>Changes the internal debug level of Mnesia.
For details, see
<seealso marker="#configuration_parameters">Section
Configuration Parameters</seealso>.</p>
@@ -1934,7 +1934,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
<fsummary>Sets the master nodes for all tables.</fsummary>
<desc>
<marker id="set_master_nodes_1"></marker>
- <p>For each table <c>Mnesia</c> determines its replica nodes
+ <p>For each table Mnesia determines its replica nodes
(<c>TabNodes</c>) and starts
<c>mnesia:set_master_nodes(Tab, TabMasterNodes)</c>. where
<c>TabMasterNodes</c> is the intersection of
@@ -1952,16 +1952,16 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
that can have caused an inconsistent database, it can use the
function <c>mnesia:set_master_nodes(Tab, MasterNodes)</c> to
define from which nodes each table is to be loaded.
- At startup, the <c>Mnesia</c> normal table load algorithm is
+ At startup, the Mnesia normal table load algorithm is
bypassed and the table is loaded from one of the master nodes
- defined for the table, regardless of when and if <c>Mnesia</c>
+ defined for the table, regardless of when and if Mnesia
terminated on other nodes. <c>MasterNodes</c> can only
contain nodes where the table has a replica. If the
<c>MasterNodes</c> list is empty, the master node recovery
mechanism for the particular table is reset, and the
normal load mechanism is used at the next restart.</p>
<p>The master node setting is always local. It can be
- changed regardless if <c>Mnesia</c> is started or not.</p>
+ changed regardless if Mnesia is started or not.</p>
<p>The database can also become inconsistent if
configuration parameter <c>max_wait_for_decision</c> is used
or if <c>mnesia:force_load_table/1</c> is used.</p>
@@ -1976,7 +1976,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</func>
<func>
<name>snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name>
- <fsummary>Gets the corresponding <c>Mnesia</c> key from an SNMP index.</fsummary>
+ <fsummary>Gets the corresponding Mnesia key from an SNMP index.</fsummary>
<type>
<v>Tab ::= atom()</v>
<v>RowIndex ::= [integer()]</v>
@@ -1984,7 +1984,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
<v>key() ::= integer() | string() | [integer()]</v>
</type>
<desc>
- <p>Transforms an SNMP index to the corresponding <c>Mnesia</c>
+ <p>Transforms an SNMP index to the corresponding Mnesia
key. If the SNMP table has multiple keys, the key is a tuple
of the key columns.</p>
</desc>
@@ -2020,7 +2020,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</func>
<func>
<name>snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name>
- <fsummary>Organizes a <c>Mnesia</c> table as an SNMP table.</fsummary>
+ <fsummary>Organizes a Mnesia table as an SNMP table.</fsummary>
<type>
<v>Tab ::= atom()</v>
<v>SnmpStruct ::= [{key, type()}]</v>
@@ -2029,14 +2029,14 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</type>
<desc>
<p>A direct one-to-one mapping can be established between
- <c>Mnesia</c> tables and SNMP tables. Many telecommunication
+ Mnesia tables and SNMP tables. Many telecommunication
applications are controlled and monitored by the SNMP
- protocol. This connection between <c>Mnesia</c> and SNMP
+ protocol. This connection between Mnesia and SNMP
makes it simple and convenient to achieve this mapping.</p>
<p>Argument <c>SnmpStruct</c> is a list of SNMP
information. Currently, the only information needed is
information about the key types in the table. Multiple
- keys cannot be handled in <c>Mnesia</c>, but many SNMP
+ keys cannot be handled in Mnesia, but many SNMP
tables have multiple keys. Therefore, the following
convention is used: if a table has multiple keys, these must
always be stored as a tuple of the keys. Information about
@@ -2069,39 +2069,39 @@ mnesia:create_table(employee,
<p>When a table is SNMP ordered, modifications are more
expensive than usual, O(logN). Also, more memory is used.</p>
<p>Notice that only the lexicographical SNMP ordering is
- implemented in <c>Mnesia</c>, not the actual SNMP monitoring.</p>
+ implemented in Mnesia, not the actual SNMP monitoring.</p>
</desc>
</func>
<func>
<name>start() -> ok | {error, Reason}</name>
- <fsummary>Starts a local <c>Mnesia</c> system.</fsummary>
+ <fsummary>Starts a local Mnesia system.</fsummary>
<desc>
<marker id="start"></marker>
- <p>The startup procedure for a set of <c>Mnesia</c> nodes is a
- fairly complicated operation. A <c>Mnesia</c> system consists
- of a set of nodes, with <c>Mnesia</c> started locally on all
+ <p>The startup procedure for a set of Mnesia nodes is a
+ fairly complicated operation. A Mnesia system consists
+ of a set of nodes, with Mnesia started locally on all
participating nodes. Normally, each node has a directory where
- all the <c>Mnesia</c> files are written. This directory is
- referred to as the <c>Mnesia</c> directory. <c>Mnesia</c> can
+ all the Mnesia files are written. This directory is
+ referred to as the Mnesia directory. Mnesia can
also be started on disc-less nodes. For more information
about disc-less nodes, see <c>mnesia:create_schema/1</c>
and the User's Guide.</p>
- <p>The set of nodes that makes up a <c>Mnesia</c> system is kept
- in a schema. <c>Mnesia</c> nodes can be added to or removed
+ <p>The set of nodes that makes up a Mnesia system is kept
+ in a schema. Mnesia nodes can be added to or removed
from the schema. The initial schema is normally created on
disc with the function <c>mnesia:create_schema/1</c>. On
disc-less nodes, a tiny default schema is generated each time
- <c>Mnesia</c> is started. During the startup procedure,
- <c>Mnesia</c> exchanges schema information between the nodes
+ Mnesia is started. During the startup procedure,
+ Mnesia exchanges schema information between the nodes
to verify that the table definitions are compatible.</p>
<p>Each schema has a unique cookie, which can be regarded as a
unique schema identifier. The cookie must be the same on all
- nodes where <c>Mnesia</c> is supposed to run. For details,
+ nodes where Mnesia is supposed to run. For details,
see the User's Guide.</p>
- <p>The schema file and all other files that <c>Mnesia</c>
- needs are kept in the <c>Mnesia</c> directory. The
+ <p>The schema file and all other files that Mnesia
+ needs are kept in the Mnesia directory. The
command-line option <c>-mnesia dir Dir</c> can be used to
- specify the location of this directory to the <c>Mnesia</c>
+ specify the location of this directory to the Mnesia
system. If no such command-line option is found, the name
of the directory defaults to <c>Mnesia.Node</c>.</p>
<p><c>application:start(mnesia)</c> can also be used.</p>
@@ -2109,10 +2109,10 @@ mnesia:create_table(employee,
</func>
<func>
<name>stop() -> stopped</name>
- <fsummary>Stops <c>Mnesia</c> locally.</fsummary>
+ <fsummary>Stops Mnesia locally.</fsummary>
<desc>
<marker id="stop"></marker>
- <p>Stops <c>Mnesia</c> locally on the current node.</p>
+ <p>Stops Mnesia locally on the current node.</p>
<p><c>application:stop(mnesia)</c> can also be used.</p>
</desc>
</func>
@@ -2132,7 +2132,7 @@ mnesia:create_table(employee,
<desc>
<marker id="sync_dirty"></marker>
<p>Calls the <c>Fun</c> in a context that is not protected by
- a transaction. The <c>Mnesia</c> function calls performed in
+ a transaction. The Mnesia function calls performed in
the <c>Fun</c> are mapped to the corresponding dirty functions.
It is performed in almost the same context as
<c>mnesia:async_dirty/1,2</c>. The difference is that the
@@ -2167,10 +2167,10 @@ mnesia:create_table(employee,
</func>
<func>
<name>system_info(InfoKey) -> Info | exit({aborted, Reason})</name>
- <fsummary>Returns information about the <c>Mnesia</c> system.</fsummary>
+ <fsummary>Returns information about the Mnesia system.</fsummary>
<desc>
<marker id="system_info"></marker>
- <p>Returns information about the <c>Mnesia</c> system, such as
+ <p>Returns information about the Mnesia system, such as
transaction statistics, <c>db_nodes</c>, and configuration
parameters. The valid keys are as follows:</p>
<list type="bulleted">
@@ -2188,7 +2188,7 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>auto_repair</c>. Returns <c>true</c> or <c>false</c>
- to indicate if <c>Mnesia</c> is configured to start the
+ to indicate if Mnesia is configured to start the
auto-repair facility on corrupted disc files.</p>
</item>
<item>
@@ -2209,20 +2209,20 @@ mnesia:create_table(employee,
in the list of nodes if they explicitly have been added
to the schema, for example, with
<c>mnesia:add_table_copy/3</c>. The function can be
- started even if <c>Mnesia</c> is not yet running.</p>
+ started even if Mnesia is not yet running.</p>
</item>
<item>
<p><c>debug</c>. Returns the current debug level of
- <c>Mnesia</c>.</p>
+ Mnesia.</p>
</item>
<item>
- <p><c>directory</c>. Returns the name of the <c>Mnesia</c>
- directory. It can be called even if <c>Mnesia</c> is
+ <p><c>directory</c>. Returns the name of the Mnesia
+ directory. It can be called even if Mnesia is
not yet running.</p>
</item>
<item>
<p><c>dump_log_load_regulation</c>. Returns a boolean that
- tells if <c>Mnesia</c> is configured to regulate the
+ tells if Mnesia is configured to regulate the
dumper process load.</p>
<p>This feature is temporary and will be removed in future
releases.</p>
@@ -2233,9 +2233,9 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>dump_log_update_in_place</c>. Returns a boolean that
- tells if <c>Mnesia</c> is configured to perform the
- updates in the <c>dets</c> files directly, or if the
- updates are to be performed in a copy of the <c>dets</c>
+ tells if Mnesia is configured to perform the
+ updates in the Dets files directly, or if the
+ updates are to be performed in a copy of the Dets
files.</p>
</item>
<item>
@@ -2253,13 +2253,13 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>held_locks</c>. Returns a list of all
- locks held by the local <c>Mnesia</c> lock manager.</p>
+ locks held by the local Mnesia lock manager.</p>
</item>
<item>
<p><c>is_running</c>. Returns <c>yes</c> or <c>no</c> to
- indicate if <c>Mnesia</c> is running. It can
+ indicate if Mnesia is running. It can
also return <c>starting</c> or <c>stopping</c>. Can be
- called even if <c>Mnesia</c> is not yet running.</p>
+ called even if Mnesia is not yet running.</p>
</item>
<item>
<p><c>local_tables</c>. Returns a list
@@ -2272,7 +2272,7 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>log_version</c>. Returns the version
- number of the <c>Mnesia</c> transaction log format.</p>
+ number of the Mnesia transaction log format.</p>
</item>
<item>
<p><c>master_node_tables</c>. Returns a
@@ -2280,25 +2280,25 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>protocol_version</c>. Returns the version number of
- the <c>Mnesia</c> inter-process communication protocol.</p>
+ the Mnesia inter-process communication protocol.</p>
</item>
<item>
<p><c>running_db_nodes</c>. Returns a list of nodes where
- <c>Mnesia</c> currently is running. This function can be
- called even if <c>Mnesia</c> is not yet running, but it
+ Mnesia currently is running. This function can be
+ called even if Mnesia is not yet running, but it
then has slightly different semantics.</p>
- <p>If <c>Mnesia</c> is down on the local node, the function
+ <p>If Mnesia is down on the local node, the function
returns those other <c>db_nodes</c> and
<c>extra_db_nodes</c> that for the moment are
operational.</p>
- <p>If <c>Mnesia</c> is started, the function returns
- those nodes that <c>Mnesia</c> on the local node is fully
- connected to. Only those nodes that <c>Mnesia</c> has
+ <p>If Mnesia is started, the function returns
+ those nodes that Mnesia on the local node is fully
+ connected to. Only those nodes that Mnesia has
exchanged schema information with are included as
<c>running_db_nodes</c>. After the merge of schemas, the
- local <c>Mnesia</c> system is fully operable and
+ local Mnesia system is fully operable and
applications can perform access of remote replicas.
- Before the schema merge, <c>Mnesia</c> only operates
+ Before the schema merge, Mnesia only operates
locally. Sometimes there are more nodes included in the
<c>running_db_nodes</c> list than all <c>db_nodes</c>
and <c>extra_db_nodes</c> together.</p>
@@ -2322,17 +2322,17 @@ mnesia:create_table(employee,
<item>
<p><c>transaction_failures</c>. Returns a
number that indicates how many transactions have
- failed since <c>Mnesia</c> was started.</p>
+ failed since Mnesia was started.</p>
</item>
<item>
<p><c>transaction_commits</c>. Returns a
number that indicates how many transactions have
- terminated successfully since <c>Mnesia</c> was started.</p>
+ terminated successfully since Mnesia was started.</p>
</item>
<item>
<p><c>transaction_restarts</c>. Returns a
number that indicates how many transactions have been
- restarted since <c>Mnesia</c> was started.</p>
+ restarted since Mnesia was started.</p>
</item>
<item>
<p><c>transaction_log_writes</c>.
@@ -2342,12 +2342,12 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>use_dir</c>. Returns a boolean that indicates if
- the <c>Mnesia</c> directory is used or not. Can be
- started even if <c>Mnesia</c> is not yet running.</p>
+ the Mnesia directory is used or not. Can be
+ started even if Mnesia is not yet running.</p>
</item>
<item>
<p><c>version</c>. Returns the current
- version number of <c>Mnesia</c>.</p>
+ version number of Mnesia.</p>
</item>
</list>
</desc>
@@ -2359,13 +2359,13 @@ mnesia:create_table(employee,
<marker id="table"></marker>
<p>Returns a Query List Comprehension (QLC) query handle,
see the <seealso marker="stdlib:qlc">qlc(3)</seealso>
- manual page in <c>STDLIB</c>. The module <c>qlc</c>
- implements a query language that can use <c>Mnesia</c>
+ manual page in STDLIB. The module <c>qlc</c>
+ implements a query language that can use Mnesia
tables as sources of data. Calling
<c>mnesia:table/1,2</c> is the means to make the
<c>mnesia</c> table <c>Tab</c> usable to QLC.</p>
- <p><c>Option</c> can contain <c>Mnesia</c>
- options or QLC options. <c>Mnesia</c> recognizes the
+ <p><c>Option</c> can contain Mnesia
+ options or QLC options. Mnesia recognizes the
following options (any other option is forwarded to
QLC).</p>
<list type="bulleted">
@@ -2374,7 +2374,7 @@ mnesia:create_table(employee,
</item>
<item><c>{n_objects,Number}</c>, where <c>n_objects</c>
specifies (roughly) the number of objects returned
- from <c>Mnesia</c> to QLC. Queries to remote tables
+ from Mnesia to QLC. Queries to remote tables
can need a larger chunk to reduce network overhead.
By default, <c>100</c> objects at a time are returned.
</item>
@@ -2413,7 +2413,7 @@ mnesia:create_table(employee,
<desc>
<marker id="table_info"></marker>
<p>The <c>table_info/2</c> function takes two arguments.
- The first is the name of a <c>Mnesia</c> table.
+ The first is the name of a Mnesia table.
The second is one of the following keys:</p>
<list type="bulleted">
<item>
@@ -2465,7 +2465,7 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>load_node</c>. Returns the name of
- the node that <c>Mnesia</c> loaded the table from. The
+ the node that Mnesia loaded the table from. The
structure of the returned value is unspecified, but
can be useful for debugging purposes.</p>
</item>
@@ -2476,7 +2476,7 @@ mnesia:create_table(employee,
</item>
<item>
<p><c>load_reason</c>. Returns the
- reason of why <c>Mnesia</c> decided to load the table.
+ reason of why Mnesia decided to load the table.
The structure of the returned value is unspecified, but
can be useful for debugging purposes.</p>
</item>
@@ -2620,7 +2620,7 @@ raise(Name, Amount) ->
several processes running on different nodes can concurrently
execute the function <c>raise/2</c> without interfering
with each other.</p>
- <p>Since <c>Mnesia</c> detects deadlocks, a transaction can be
+ <p>Since Mnesia detects deadlocks, a transaction can be
restarted any number of times. This function attempts a
restart as specified in <c>Retries</c>. <c>Retries</c> must
be an integer greater than 0 or the atom <c>infinity</c>.
@@ -2643,7 +2643,7 @@ raise(Name, Amount) ->
<p><c>NewAttributeList</c> and <c>NewRecordName</c>
specify the attributes and the new record type of the
converted table. Table name always remains unchanged. If
- <c>record_name</c> is changed, only the <c>Mnesia</c>
+ <c>record_name</c> is changed, only the Mnesia
functions that use table identifiers work, for example,
<c>mnesia:write/3</c> works, but not <c>mnesia:write/1</c>.</p>
</desc>
@@ -2706,7 +2706,7 @@ raise(Name, Amount) ->
distributed operation that is either performed on all
nodes with disc resident schema, or none. Uninstallation of
fallbacks requires Erlang to be operational on all
- involved nodes, but it does not matter if <c>Mnesia</c> is
+ involved nodes, but it does not matter if Mnesia is
running or not. Which nodes that are considered as
disc-resident nodes is determined from the schema
information in the local fallback.</p>
@@ -2792,28 +2792,28 @@ raise(Name, Amount) ->
<section>
<title>Configuration Parameters</title>
<marker id="configuration_parameters"></marker>
- <p><c>Mnesia</c> reads the following application configuration
+ <p>Mnesia reads the following application configuration
parameters:</p>
<list type="bulleted">
<item>
<p><c>-mnesia access_module Module</c>. The name of the
- <c>Mnesia</c> activity access callback module. Default is
+ Mnesia activity access callback module. Default is
<c>mnesia</c>.</p>
</item>
<item>
<p><c>-mnesia auto_repair true | false</c>. This flag
- controls if <c>Mnesia</c> automatically tries to repair
+ controls if Mnesia automatically tries to repair
files that have not been properly closed. Default is
<c>true</c>.</p>
</item>
<item>
<p><c>-mnesia backup_module Module</c>. The name of the
- <c>Mnesia</c> backup callback module. Default is
+ Mnesia backup callback module. Default is
<c>mnesia_backup</c>.</p>
</item>
<item>
<p><c>-mnesia debug Level</c>. Controls the debug level
- of <c>Mnesia</c>. The possible values are as follows:</p>
+ of Mnesia. The possible values are as follows:</p>
<taglist>
<tag><c>none</c></tag>
<item>
@@ -2825,7 +2825,7 @@ raise(Name, Amount) ->
events generate <c>{mnesia_info, Format, Args}</c>
system events. Processes can subscribe to these events with
<c>mnesia:subscribe/1</c>. The events are always sent to
- the <c>Mnesia</c> event handler.</p>
+ the Mnesia event handler.</p>
</item>
<tag><c>debug</c></tag>
<item>
@@ -2834,15 +2834,15 @@ raise(Name, Amount) ->
<c>{mnesia_info, Format, Args}</c> system events.
Processes can subscribe to these events with
<c>mnesia:subscribe/1</c>. The events are always sent to
- the <c>Mnesia</c> event handler. On this debug level,
- the <c>Mnesia</c> event handler starts subscribing to
+ the Mnesia event handler. On this debug level,
+ the Mnesia event handler starts subscribing to
updates in the schema table.</p>
</item>
<tag><c>trace</c></tag>
<item>
<p>Activates all events at the debug level. On this
- level, the <c>Mnesia</c> event handler starts subscribing
- to updates on all <c>Mnesia</c> tables. This level is
+ level, the Mnesia event handler starts subscribing
+ to updates on all Mnesia tables. This level is
intended only for debugging small toy systems, as many
large events can be generated.</p>
</item>
@@ -2856,7 +2856,7 @@ raise(Name, Amount) ->
</item>
<item>
<p><c>-mnesia core_dir Directory</c>. The name of the
- directory where <c>Mnesia</c> core files is stored, or
+ directory where Mnesia core files is stored, or
false. Setting it implies that also RAM-only nodes
generate a core file if a crash occurs.</p>
</item>
@@ -2870,9 +2870,9 @@ raise(Name, Amount) ->
</item>
<item>
<p><c>-mnesia dir Directory</c>. The name of the directory
- where all <c>Mnesia</c> data is stored. The directory name
+ where all Mnesia data is stored. The directory name
must be unique for the current node. Two nodes must never
- share the the same <c>Mnesia</c> directory. The results
+ share the the same Mnesia directory. The results
are unpredictable.</p>
</item>
<item>
@@ -2915,44 +2915,44 @@ raise(Name, Amount) ->
</item>
<item>
<p><c>-mnesia event_module Module</c>. The name of the
- <c>Mnesia</c> event handler callback module. Default is
+ Mnesia event handler callback module. Default is
<c>mnesia_event</c>.</p>
</item>
<item>
<p><c>-mnesia extra_db_nodes Nodes</c> specifies a list of
nodes, in addition to the ones found in the schema, with
- which <c>Mnesia</c> is also to establish contact. Default
+ which Mnesia is also to establish contact. Default
is <c>[]</c> (empty list).</p>
</item>
<item>
<p><c>-mnesia fallback_error_function {UserModule, UserFunc}</c>.
Specifies a user-supplied callback function, which is
- called if a fallback is installed and <c>Mnesia</c> goes
- down on another node. <c>Mnesia</c> calls the function
+ called if a fallback is installed and Mnesia goes
+ down on another node. Mnesia calls the function
with one argument, the name of the dying node, for example,
- <c>UserModule:UserFunc(DyingNode)</c>. <c>Mnesia</c> must
+ <c>UserModule:UserFunc(DyingNode)</c>. Mnesia must
be restarted, otherwise the database can be inconsistent.
- The default behavior is to terminate <c>Mnesia</c>.</p>
+ The default behavior is to terminate Mnesia.</p>
</item>
<item>
<p><c>-mnesia max_wait_for_decision Timeout</c>. Specifies
- how long <c>Mnesia</c> waits for other nodes to share their
+ how long Mnesia waits for other nodes to share their
knowledge about the outcome of an unclear transaction. By
default, <c>Timeout</c> is set to the atom <c>infinity</c>.
- This implies that if <c>Mnesia</c> upon startup detects
+ This implies that if Mnesia upon startup detects
a "heavyweight transaction" whose outcome is unclear, the
- local <c>Mnesia</c> waits until <c>Mnesia</c> is started
+ local Mnesia waits until Mnesia is started
on some (in the worst case all) of the other nodes that were
involved in the interrupted transaction. This is a rare
- situation, but if it occurs, <c>Mnesia</c> does not guess if
+ situation, but if it occurs, Mnesia does not guess if
the transaction on the other nodes was committed or
- terminated. <c>Mnesia</c> waits until it knows the outcome
+ terminated. Mnesia waits until it knows the outcome
and then acts accordingly.</p>
<p>If <c>Timeout</c> is set to an integer value in
- milliseconds, <c>Mnesia</c> forces "heavyweight transactions"
+ milliseconds, Mnesia forces "heavyweight transactions"
to be finished, even if the outcome of the transaction for
the moment is unclear. After <c>Timeout</c> milliseconds,
- <c>Mnesia</c> commits or terminates the transaction and
+ Mnesia commits or terminates the transaction and
continues with the startup. This can lead to a situation
where the transaction is committed on some nodes and
terminated on other nodes. If the transaction is a
@@ -2976,14 +2976,14 @@ raise(Name, Amount) ->
</item>
<item>
<p><c>-mnesia schema_location Loc</c>. Controls where
- <c>Mnesia</c> looks for its schema. Parameter
+ Mnesia looks for its schema. Parameter
<c>Loc</c> can be one of the following atoms:</p>
<taglist>
<tag><c>disc</c></tag>
<item>
<p>Mandatory disc. The schema is assumed to be located
- in the <c>Mnesia</c> directory. If the schema cannot
- be found, <c>Mnesia</c> refuses to start. This is the
+ in the Mnesia directory. If the schema cannot
+ be found, Mnesia refuses to start. This is the
old behavior.</p>
</item>
<tag><c>ram</c></tag>
@@ -3001,10 +3001,10 @@ raise(Name, Amount) ->
<tag><c>opt_disc</c></tag>
<item>
<p>Optional disc. The schema can reside on disc or in
- RAM. If the schema is found on disc, <c>Mnesia</c>
+ RAM. If the schema is found on disc, Mnesia
starts as a disc-based node and the storage type of
the schema table is <c>disc_copies</c>. If no schema is
- found on disc, <c>Mnesia</c> starts as a disc-less node
+ found on disc, Mnesia starts as a disc-less node
and the storage type of the schema table is
<c>ram_copies</c>. Default value for the application
parameter is <c>opt_disc</c>.</p>
@@ -3012,7 +3012,7 @@ raise(Name, Amount) ->
</taglist>
</item>
</list>
- <p>First, the <c>SASL</c> application parameters are checked,
+ <p>First, the SASL application parameters are checked,
then the command-line flags are checked, and finally, the
default value is chosen.</p>
</section>
diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml
index 95f5f8aa07..51b32129b6 100644
--- a/lib/mnesia/doc/src/mnesia_frag_hash.xml
+++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml
@@ -87,13 +87,13 @@
the new one.</p>
<p><c>NewState</c> is stored as <c>hash_state</c> among the
other <c>frag_properties</c>.</p>
- <p>As a part of the <c>add_frag</c> procedure, <c>Mnesia</c> iterates
+ <p>As a part of the <c>add_frag</c> procedure, Mnesia iterates
over all fragments corresponding to the <c>IterFrags</c> numbers
and starts <c>key_to_frag_number(NewState,RecordKey)</c> for
each record. If the new fragment differs from the old
fragment, the record is moved to the new fragment.</p>
<p>As the <c>add_frag</c> procedure is a part of a schema
- transaction, <c>Mnesia</c> acquires write locks on the
+ transaction, Mnesia acquires write locks on the
affected tables. That is, both the fragments corresponding
to <c>IterFrags</c> and those corresponding to
<c>AdditionalLockFrags</c>.</p>
@@ -112,7 +112,7 @@
<desc>
<p><c>NewState</c> is stored as <c>hash_state</c> among the
other <c>frag_properties</c>.</p>
- <p>As a part of the <c>del_frag</c> procedure, <c>Mnesia</c> iterates
+ <p>As a part of the <c>del_frag</c> procedure, Mnesia iterates
over all fragments corresponding to the <c>IterFrags</c> numbers
and starts <c>key_to_frag_number(NewState,RecordKey)</c> for
each record. If the new fragment differs from the old
@@ -120,7 +120,7 @@
<p>Notice that all records in the last fragment must be moved to
another fragment, as the entire fragment is deleted.</p>
<p>As the <c>del_frag</c> procedure is a part of a schema
- transaction, <c>Mnesia</c> acquires write locks on the
+ transaction, Mnesia acquires write locks on the
affected tables. That is, both the fragments corresponding
to <c>IterFrags</c> and those corresponding to
<c>AdditionalLockFrags</c>.</p>
@@ -134,7 +134,7 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>Starts whenever <c>Mnesia</c> needs to determine
+ <p>Starts whenever Mnesia needs to determine
which fragment a certain record belongs to. It is typically
started at <c>read</c>, <c>write</c>, and <c>delete</c>.</p>
</desc>
@@ -149,7 +149,7 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>This function is called whenever <c>Mnesia</c> needs to determine
+ <p>This function is called whenever Mnesia needs to determine
which fragments that need to be searched for a <c>MatchSpec</c>.
It is typically called by <c>select</c> and
<c>match_object</c>.</p>
diff --git a/lib/mnesia/doc/src/mnesia_registry.xml b/lib/mnesia/doc/src/mnesia_registry.xml
index cd778ae072..a76f716981 100644
--- a/lib/mnesia/doc/src/mnesia_registry.xml
+++ b/lib/mnesia/doc/src/mnesia_registry.xml
@@ -38,20 +38,20 @@
<modulesummary>Dump support for registries in erl_interface.</modulesummary>
<description>
<p>This module is usually part of the <c>erl_interface</c>
- application, but is currently part of the <c>Mnesia</c>
+ application, but is currently part of the Mnesia
application.</p>
<p>This module is mainly intended for internal use within OTP,
but it has two functions that are exported for public use.</p>
<p>On C-nodes, <c>erl_interface</c> has support for registry
tables. These tables reside in RAM on the C-node, but can also
- be dumped into <c>Mnesia</c> tables. By default, the dumping
+ be dumped into Mnesia tables. By default, the dumping
of registry tables through <c>erl_interface</c> causes a
- corresponding <c>Mnesia</c> table to be created with
+ corresponding Mnesia table to be created with
<c>mnesia_registry:create_table/1</c>, if necessary.</p>
<p>Tables that are created with these functions can be
- administered as all other <c>Mnesia</c> tables. They can be
+ administered as all other Mnesia tables. They can be
included in backups, replicas can be added, and so on.
- The tables are normal <c>Mnesia</c> tables owned by the user
+ The tables are normal Mnesia tables owned by the user
of the corresponding <c>erl_interface</c> registries.</p>
</description>
@@ -68,7 +68,7 @@
that is, <c>{ram_copies,[node()]}</c> or
<c>{disc_copies,[node()]}</c>.</p>
<p>This function is used by <c>erl_interface</c> to
- create the <c>Mnesia</c> table if it does not already
+ create the Mnesia table if it does not already
exist.</p>
</desc>
</func>
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index 7d8e8d0c44..a20640e1be 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -39,7 +39,94 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.14</title>
+ <section><title>Mnesia 4.14.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix backup error handling, the real failure reason was
+ not returned.</p>
+ <p>
+ Own Id: OTP-14776 Aux Id: ERIERL-103 </p>
+ </item>
+ <item>
+ <p>
+ Removed a quadratic behavior in startup. This change
+ implies that backend plugins (if used) must be set when
+ the schema is created or via configuration parameters
+ before mnesia is started.</p>
+ <p>
+ Own Id: OTP-14829 Aux Id: ERIERL-84 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.14.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed crash in checkpoint handling when table was deleted
+ during backup.</p>
+ <p>
+ Own Id: OTP-14167</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.14.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A continuation returned by mnesia:select/[14] should be
+ reusable in different, non-transactional activities.</p>
+ <p>
+ Own Id: OTP-13944 Aux Id: PR-1184 </p>
+ </item>
+ <item>
+ <p>
+ Fixed crash when calling block_table multiple times.
+ Could happen when having locks for a long time and
+ restarting mnesia.</p>
+ <p>
+ Own Id: OTP-13970 Aux Id: Seq-13198 </p>
+ </item>
+ <item>
+ <p>
+ Change mnesia_tm process to have off-heap messages since
+ mnesia_tm can be the receiver of many non-synchronized
+ message from other nodes.</p>
+ <p>
+ Own Id: OTP-14074</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.14.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Correct some minor documentation issues. </p>
+ <p>
+ Own Id: OTP-13891</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.14</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/mnesia/doc/src/part.xml b/lib/mnesia/doc/src/part.xml
index 101bdb29d4..d3ffe93937 100644
--- a/lib/mnesia/doc/src/part.xml
+++ b/lib/mnesia/doc/src/part.xml
@@ -30,7 +30,7 @@
<file>part.sgml</file>
</header>
<description>
- <p>The <c>Mnesia</c> application is a distributed Database Management
+ <p>The Mnesia application is a distributed Database Management
System (DBMS), appropriate for telecommunications applications and other
Erlang applications, which require continuous operation and exhibit soft
real-time properties.</p>
diff --git a/lib/mnesia/doc/src/ref_man.xml b/lib/mnesia/doc/src/ref_man.xml
index 662f0d61d6..7fb71b9c45 100644
--- a/lib/mnesia/doc/src/ref_man.xml
+++ b/lib/mnesia/doc/src/ref_man.xml
@@ -33,7 +33,7 @@
<file>refman.sgml</file>
</header>
<description>
- <p>The <c>Mnesia</c> application is a distributed Database Management
+ <p>The Mnesia application is a distributed Database Management
System (DBMS), appropriate for telecommunications applications and other
Erlang applications, which require continuous operation and exhibit soft
real-time properties.</p>
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index 9586adbf93..34efeca4fa 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -1409,8 +1409,14 @@ select_cont(Tid,_,State=#mnesia_select{tid=Tid,written=[]}) ->
select_state(dirty_sel_cont(State),State);
select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid}) ->
trans_select(dirty_sel_cont(State), State);
-select_cont(_Tid2,_,#mnesia_select{tid=_Tid1}) -> % Missmatching tids
+select_cont(Tid2,_,#mnesia_select{tid=_Tid1})
+ when element(1,Tid2) == tid -> % Mismatching tids
abort(wrong_transaction);
+select_cont(Tid,Ts,State=#mnesia_select{}) ->
+ % Repair mismatching tids in non-transactional contexts
+ RepairedState = State#mnesia_select{tid = Tid, written = [],
+ spec = undefined, type = undefined},
+ select_cont(Tid,Ts,RepairedState);
select_cont(_,_,Cont) ->
abort({badarg, Cont}).
@@ -1876,9 +1882,10 @@ any_table_info(Tab, Item) when is_atom(Tab) ->
[] ->
abort({no_exists, Tab, Item});
Props ->
- lists:map(fun({setorbag, Type}) -> {type, Type};
- (Prop) -> Prop end,
- Props)
+ Rename = fun ({setorbag, Type}) -> {type, Type};
+ (Prop) -> Prop
+ end,
+ lists:sort(lists:map(Rename, Props))
end;
name ->
Tab;
diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl
index 9eb939e8d3..fc626940b4 100644
--- a/lib/mnesia/src/mnesia_checkpoint.erl
+++ b/lib/mnesia/src/mnesia_checkpoint.erl
@@ -909,7 +909,7 @@ retainer_loop(Cp = #checkpoint_args{name=Name}) ->
retainer_loop(Cp2);
{From, {iter_end, Iter}} ->
- retainer_fixtable(Iter#iter.oid_tab, false),
+ ?SAFE(retainer_fixtable(Iter#iter.oid_tab, false)),
Iters = Cp#checkpoint_args.iterators -- [Iter],
reply(From, Name, ok),
retainer_loop(Cp#checkpoint_args{iterators = Iters});
@@ -971,7 +971,8 @@ do_stop(Cp) ->
unset({checkpoint, Name}),
lists:foreach(fun deactivate_tab/1, Cp#checkpoint_args.retainers),
Iters = Cp#checkpoint_args.iterators,
- lists:foreach(fun(I) -> retainer_fixtable(I#iter.oid_tab, false) end, Iters).
+ [?SAFE(retainer_fixtable(Tab, false)) || #iter{main_tab=Tab} <- Iters],
+ ok.
deactivate_tab(R) ->
Name = R#retainer.cp_name,
@@ -1151,7 +1152,7 @@ do_change_copy(Cp, Tab, FromType, ToType) ->
Cp#checkpoint_args{retainers = Rs, nodes = writers(Rs)}.
check_iter(From, Iter) when Iter#iter.pid == From ->
- retainer_fixtable(Iter#iter.oid_tab, false),
+ ?SAFE(retainer_fixtable(Iter#iter.oid_tab, false)),
false;
check_iter(_From, _Iter) ->
true.
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 4791e2e290..17b47c059e 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -1703,9 +1703,10 @@ add_active_replica(Tab, Node, Cs = #cstruct{}) ->
block_table(Tab) ->
Var = {Tab, where_to_commit},
- Old = val(Var),
- New = {blocked, Old},
- set(Var, New). % where_to_commit
+ case is_tab_blocked(val(Var)) of
+ {true, _} -> ok;
+ {false, W2C} -> set(Var, mark_blocked_tab(true, W2C))
+ end.
unblock_table(Tab) ->
call({unblock_table, Tab}).
diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl
index 7320d381ea..6f7531245f 100644
--- a/lib/mnesia/src/mnesia_event.erl
+++ b/lib/mnesia/src/mnesia_event.erl
@@ -114,7 +114,8 @@ handle_table_event({Oper, Record, TransId}, State) ->
handle_system_event({mnesia_checkpoint_activated, _Checkpoint}, State) ->
{ok, State};
-handle_system_event({mnesia_checkpoint_deactivated, _Checkpoint}, State) ->
+handle_system_event({mnesia_checkpoint_deactivated, Checkpoint}, State) ->
+ report_error("Checkpoint '~p' has been deactivated, last table copy deleted.\n",[Checkpoint]),
{ok, State};
handle_system_event({mnesia_up, Node}, State) ->
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 71e5829c87..c710470a2c 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -342,9 +342,12 @@ spawned_receiver(ReplyTo,Tab,Storage,Cs, SenderPid,TabSize,DetsData, Init) ->
Done = do_init_table(Tab,Storage,Cs,
SenderPid,TabSize,DetsData,
ReplyTo, Init),
- ReplyTo ! {self(),Done},
- unlink(ReplyTo),
- unlink(whereis(mnesia_controller)),
+ try
+ ReplyTo ! {self(),Done},
+ unlink(ReplyTo),
+ unlink(whereis(mnesia_controller))
+ catch _:_ -> ok %% avoid error reports when stopping down mnesia
+ end,
exit(normal).
wait_on_load_complete(Pid) ->
@@ -916,9 +919,15 @@ send_packet(_N, _Pid, _Chunk, DataState) ->
finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) ->
RecNode = node(Pid),
DatBin = dat2bin(Tab, Storage, RemoteS),
+ Node = node(Pid),
Trans =
fun() ->
NeedLock andalso mnesia:read_lock_table(Tab),
+ %% Check that receiver is still alive
+ receive {copier_done, Node} ->
+ throw(receiver_died)
+ after 0 -> ok
+ end,
A = val({Tab, access_mode}),
mnesia_controller:sync_and_block_table_whereabouts(Tab, RecNode, RemoteS, A),
cleanup_tab_copier(Pid, Storage, Tab),
@@ -927,7 +936,7 @@ finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) ->
receive
{Pid, no_more} -> % Dont bother about the spurious 'more' message
no_more;
- {copier_done, Node} when Node == node(Pid)->
+ {copier_done, Node} ->
verbose("Tab receiver ~p crashed (more): ~p~n", [Tab, Node]),
receiver_died
end
diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl
index 9536effd42..685d512acf 100644
--- a/lib/mnesia/src/mnesia_log.erl
+++ b/lib/mnesia/src/mnesia_log.erl
@@ -752,8 +752,8 @@ abort_write(B, What, Args, Reason) ->
Opaque = B#backup_args.opaque,
dbg_out("Failed to perform backup. M=~p:F=~p:A=~p -> ~p~n",
[Mod, What, Args, Reason]),
- try apply(Mod, abort_write, [Opaque]) of
- {ok, _Res} -> throw({error, Reason})
+ try {ok, _Res} = apply(Mod, abort_write, [Opaque]) of
+ _ -> throw({error, Reason})
catch _:Other ->
error("Failed to abort backup. ~p:~p~p -> ~p~n",
[Mod, abort_write, [Opaque], Other]),
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index 0e4017e4c3..bb5e38f7c1 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -952,19 +952,9 @@ get_index_plugins() ->
get_schema_user_property(mnesia_index_plugins).
get_schema_user_property(Key) ->
- Tab = schema,
- %% Must work reliably both within transactions and outside of transactions
- Res = case get(mnesia_activity_state) of
- undefined ->
- dirty_read_table_property(Tab, Key);
- _ ->
- do_read_table_property(Tab, Key)
- end,
- case Res of
- undefined ->
- [];
- {_, Types} ->
- Types
+ case dirty_read_table_property(schema, Key) of
+ undefined -> [];
+ {_, Types} -> Types
end.
get_ext_types_disc() ->
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index b116b48312..305bf14bcf 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -80,6 +80,7 @@ start() ->
init(Parent) ->
register(?MODULE, self()),
process_flag(trap_exit, true),
+ process_flag(message_queue_data, off_heap),
%% Initialize the schema
IgnoreFallback = mnesia_monitor:get_env(ignore_fallback_at_startup),
@@ -950,7 +951,7 @@ return_abort(Fun, Args, Reason) ->
if
Level == 1 ->
mnesia_locker:async_release_tid(Nodes, Tid),
- ?MODULE ! {delete_transaction, Tid},
+ ?SAFE(?MODULE ! {delete_transaction, Tid}),
erase(mnesia_activity_state),
flush_downs(),
?SAFE(unlink(whereis(?MODULE))),
diff --git a/lib/mnesia/test/ext_test.erl b/lib/mnesia/test/ext_test.erl
index 45ddb148bc..3d1cc40c09 100644
--- a/lib/mnesia/test/ext_test.erl
+++ b/lib/mnesia/test/ext_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl
index e745ec9b04..044cf501fd 100644
--- a/lib/mnesia/test/mnesia_evil_backup.erl
+++ b/lib/mnesia/test/mnesia_evil_backup.erl
@@ -723,18 +723,18 @@ bup_records(File, Mod) ->
exit(Reason)
end.
-sops_with_checkpoint(doc) ->
+sops_with_checkpoint(doc) ->
["Test schema operations during a checkpoint"];
sops_with_checkpoint(suite) -> [];
sops_with_checkpoint(Config) when is_list(Config) ->
- Ns = ?acquire_nodes(2, Config),
-
+ Ns = [N1,N2] = ?acquire_nodes(2, Config),
+
?match({ok, cp1, Ns}, mnesia:activate_checkpoint([{name, cp1},{max,mnesia:system_info(tables)}])),
- Tab = tab,
+ Tab = tab,
?match({atomic, ok}, mnesia:create_table(Tab, [{disc_copies,Ns}])),
OldRecs = [{Tab, K, -K} || K <- lists:seq(1, 5)],
[mnesia:dirty_write(R) || R <- OldRecs],
-
+
?match({ok, cp2, Ns}, mnesia:activate_checkpoint([{name, cp2},{max,mnesia:system_info(tables)}])),
File1 = "cp1_delete_me.BUP",
?match(ok, mnesia:dirty_write({Tab,6,-6})),
@@ -742,16 +742,16 @@ sops_with_checkpoint(Config) when is_list(Config) ->
?match(ok, mnesia:dirty_write({Tab,7,-7})),
File2 = "cp2_delete_me.BUP",
?match(ok, mnesia:backup_checkpoint(cp2, File2)),
-
+
?match(ok, mnesia:deactivate_checkpoint(cp1)),
?match(ok, mnesia:backup_checkpoint(cp2, File1)),
?match(ok, mnesia:dirty_write({Tab,8,-8})),
-
+
?match({atomic,ok}, mnesia:delete_table(Tab)),
?match({error,_}, mnesia:backup_checkpoint(cp2, File2)),
?match({'EXIT',_}, mnesia:dirty_write({Tab,9,-9})),
- ?match({atomic,_}, mnesia:restore(File1, [{default_op, recreate_tables}])),
+ ?match({atomic,_}, mnesia:restore(File1, [{default_op, recreate_tables}])),
Test = fun(N) when N > 5 -> ?error("To many records in backup ~p ~n", [N]);
(N) -> case mnesia:dirty_read(Tab,N) of
[{Tab,N,B}] when -B =:= N -> ok;
@@ -759,8 +759,29 @@ sops_with_checkpoint(Config) when is_list(Config) ->
end
end,
[Test(N) || N <- mnesia:dirty_all_keys(Tab)],
- ?match({aborted,enoent}, mnesia:restore(File2, [{default_op, recreate_tables}])),
-
+ ?match({aborted,enoent}, mnesia:restore(File2, [{default_op, recreate_tables}])),
+
+ %% Mnesia crashes when deleting a table during backup
+ ?match([], mnesia_test_lib:stop_mnesia([N2])),
+ Tab2 = ram,
+ ?match({atomic, ok}, mnesia:create_table(Tab2, [{ram_copies,[N1]}])),
+ ?match({ok, cp3, _}, mnesia:activate_checkpoint([{name, cp3},
+ {ram_overrides_dump,true},
+ {min,[Tab2]}])),
+ Write = fun Loop (N) ->
+ case N > 0 of
+ true ->
+ mnesia:dirty_write({Tab2, N+100, N+100}),
+ Loop(N-1);
+ false ->
+ ok
+ end
+ end,
+ ok = Write(100000),
+ spawn_link(fun() -> ?match({atomic, ok},mnesia:delete_table(Tab2)) end),
+
+ %% We don't check result here, depends on timing of above call
+ mnesia:backup_checkpoint(cp3, File2),
file:delete(File1), file:delete(File2),
- ?verify_mnesia(Ns, []).
+ ?verify_mnesia([N1], [N2]).
diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl
index 6e84a27ec9..0fabdc7929 100644
--- a/lib/mnesia/test/mnesia_test_lib.erl
+++ b/lib/mnesia/test/mnesia_test_lib.erl
@@ -263,6 +263,7 @@ slave_start_link(Host, Name, Retries) ->
Path = code:get_path(),
ok = rpc:call(NewNode, file, set_cwd, [Cwd]),
true = rpc:call(NewNode, code, set_path, [Path]),
+ ok = rpc:call(NewNode, error_logger, tty, [false]),
spawn_link(NewNode, ?MODULE, slave_sup, []),
rpc:multicall([node() | nodes()], global, sync, []),
{ok, NewNode};
diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl
index aa50ee4cb1..4ed73ea859 100644
--- a/lib/mnesia/test/mnesia_trans_access_test.erl
+++ b/lib/mnesia/test/mnesia_trans_access_test.erl
@@ -307,6 +307,7 @@ select14(Config) when is_list(Config) ->
%% Some Helpers
Trans = fun(Fun) -> mnesia:transaction(Fun) end,
+ Dirty = fun(Fun) -> mnesia:async_dirty(Fun) end,
LoopHelp = fun('$end_of_table',_) -> [];
({Recs,Cont},Fun) ->
Sel = mnesia:select(Cont),
@@ -334,8 +335,13 @@ select14(Config) when is_list(Config) ->
?match({atomic, [OneRec]}, Trans(fun() -> Loop(Tab, OnePat) end)),
?match({atomic, All}, Trans(fun() -> Loop(Tab, AllPat) end)),
- {atomic,{_, Cont}} = Trans(fun() -> mnesia:select(Tab, OnePat, 1, read) end),
- ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(Cont) end)),
+ {atomic,{_, ContOne}} = Trans(fun() -> mnesia:select(Tab, OnePat, 1, read) end),
+ ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(ContOne) end)),
+ ?match('$end_of_table', Dirty(fun() -> mnesia:select(ContOne) end)),
+
+ {atomic,{_, ContAll}} = Trans(fun() -> mnesia:select(Tab, AllPat, 1, read) end),
+ ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(ContAll) end)),
+ ?match({[_], _}, Dirty(fun() -> mnesia:select(ContAll) end)),
?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, {match, '$1', 2},1,read) end)),
?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, [{'_', [], '$1'}],1,read) end)),
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index fb4200f62d..b1e8568490 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.14
+MNESIA_VSN = 4.14.3.1
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 505d0dcc89..79e2b2b9db 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -32,6 +32,134 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ etop erroneously reported the average scheduler
+ utilization since the tool was first started instead of
+ the scheduler utilization since last update. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-14090 Aux Id: seq13232 </p>
+ </item>
+ <item>
+ <p>
+ crashdump_viewer crashed when the 'Slogan' had more than
+ one line. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14093 Aux Id: ERL-318 </p>
+ </item>
+ <item>
+ <p>
+ When clicking an HTML-link to a port before the port tab
+ has been opened for the first time, observer would crash
+ since port info is not initiated. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14151 Aux Id: PR-1296 </p>
+ </item>
+ <item>
+ <p>The dialyzer and observer applications will now use a
+ portable way to find the home directory. That means that
+ there is no longer any need to manually set the HOME
+ environment variable on Windows.</p>
+ <p>
+ Own Id: OTP-14249 Aux Id: ERL-161 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The shell script (priv/bin/cdv) and bat file
+ (priv/bin/cdv.bat) which can be used for starting
+ crashdump_viewer both started a distributed erlang node.
+ This would cause any attempt at starting a second
+ instance of the crashdump_viewer to fail. To solve this
+ problem, cdv and cdv.bat now use non-distributed nodes
+ when starting the crashdump_viewer.</p>
+ <p>
+ Own Id: OTP-14010</p>
+ </item>
+ <item>
+ <p>
+ A bug caused the number of buckets to be shown in the
+ 'Objects' column, and the number of objects to be shown
+ in the 'Memory' column for ets table in crashdump_viewer.
+ This is now corrected.</p>
+ <p>
+ Own Id: OTP-14064</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add option <c>queue_size</c> to ttb:tracer/2. This sets
+ the maximum queue size for the IP trace driver which is
+ used when tracing to shell and/or <c>{local,File}</c>.</p>
+ <p>
+ The default value for <c>queue_size</c> is specified by
+ <c>dbg</c>, and it is now changed from 50 to 200.</p>
+ <p>
+ Own Id: OTP-13829 Aux Id: seq13171 </p>
+ </item>
+ <item>
+ <p>
+ The port information page is updated to show more
+ information per port.</p>
+ <p>
+ Own Id: OTP-13948 Aux Id: ERL-272 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed error handling in observer when mnesia tables was
+ requested and not available.</p>
+ <p>
+ Own Id: OTP-13845 Aux Id: ERL-237 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a crash happening when observing another node, who
+ have a different number of schedulers than the current
+ one.</p>
+ <p>
+ Own Id: OTP-13702 Aux Id: ERL-171 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/observer/doc/src/ttb.xml b/lib/observer/doc/src/ttb.xml
index 94ecef24b4..7cd15e15d3 100644
--- a/lib/observer/doc/src/ttb.xml
+++ b/lib/observer/doc/src/ttb.xml
@@ -114,7 +114,8 @@ ttb:p(all, call).</input></pre>
<v>Opt = {file,Client} | {handler, FormatHandler} | {process_info,PI} |
shell | {shell, ShellSpec} | {timer, TimerSpec} |
{overload_check, {MSec, Module, Function}} |
- {flush, MSec} | resume | {resume, FetchTimeout}</v>
+ {flush, MSec} | resume | {resume, FetchTimeout} |
+ {queue_size, QueueSize}</v>
<v>TimerSpec = MSec | {MSec, StopOpts}</v>
<v>MSec = FetchTimeout = integer()</v>
<v>Module = Function = atom() </v>
@@ -126,6 +127,7 @@ ttb:p(all, call).</input></pre>
<v>FormatHandler = See format/2</v>
<v>PI = true | false </v>
<v>ShellSpec = true | false | only</v>
+ <v>QueueSize = non_neg_integer()</v>
</type>
<desc>
<p>Starts a file trace port on all specified nodes
@@ -147,6 +149,18 @@ ttb:p(all, call).</input></pre>
<c>Client</c> must be <c>{local, File}</c>. All
trace information is then sent to the trace control node where
it is written to file.</p></item>
+ <tag><c>queue_size</c></tag>
+ <item><p>When tracing to shell or <c>{local,File}</c>, an ip
+ trace driver is used internally. The ip trace driver has a
+ queue of maximum <c>QueueSize</c> messages waiting to be
+ delivered. If the driver cannot deliver messages as fast as
+ they are produced, the queue size might be exceeded and
+ messages are dropped. This parameter is optional, and is
+ only useful if many <c>{drop,N}</c> trace messages are
+ received by the trace handler. It has no meaning if shell
+ or <c>{local,File}</c> is not used. See
+ <seealso marker="runtime_tools:dbg#trace_port/2">dbg:trace_port/2</seealso>
+ for more information about the ip trace driver.</p></item>
<tag><c>process_info</c></tag>
<item><p>Indicates if process
information is to be collected. If <c>PI = true</c> (which is
@@ -485,7 +499,7 @@ ttb:p(all, call).</input></pre>
<p>For a description of the <c>match_spec()</c> syntax,
see section
<seealso marker="erts:match_spec"><c>Match Specifications in Erlang</c></seealso>
- in <c>ERTS</c>, which explains the general match specification "language".
+ in ERTS, which explains the general match specification "language".
</p>
<note>
<p>The <em>system tracer</em> for sequential tracing is
diff --git a/lib/observer/priv/bin/cdv b/lib/observer/priv/bin/cdv
index 1c44785ac2..d14fd47e41 100755
--- a/lib/observer/priv/bin/cdv
+++ b/lib/observer/priv/bin/cdv
@@ -1,4 +1,4 @@
#!/bin/sh
-erl -sname cdv -noinput -s crashdump_viewer script_start $@
+erl -noinput -s crashdump_viewer script_start $@
diff --git a/lib/observer/priv/bin/cdv.bat b/lib/observer/priv/bin/cdv.bat
index efa8bf8687..18136a30d6 100644
--- a/lib/observer/priv/bin/cdv.bat
+++ b/lib/observer/priv/bin/cdv.bat
@@ -1,2 +1,2 @@
@ECHO OFF
-CALL werl -sname cdv -s crashdump_viewer script_start %*
+CALL werl -s crashdump_viewer script_start %*
diff --git a/lib/observer/priv/crashdump_viewer.tool b/lib/observer/priv/crashdump_viewer.tool
deleted file mode 100644
index b6bd6bbdef..0000000000
--- a/lib/observer/priv/crashdump_viewer.tool
+++ /dev/null
@@ -1,2 +0,0 @@
-{version,"1.2"}.
-[{config_func,{crashdump_viewer,configData,[]}}].
diff --git a/lib/observer/priv/crashdump_viewer/collapsd.gif b/lib/observer/priv/crashdump_viewer/collapsd.gif
deleted file mode 100644
index 0b90c08a9a..0000000000
--- a/lib/observer/priv/crashdump_viewer/collapsd.gif
+++ /dev/null
Binary files differ
diff --git a/lib/observer/priv/crashdump_viewer/exploded.gif b/lib/observer/priv/crashdump_viewer/exploded.gif
deleted file mode 100644
index e3ab5ca2e9..0000000000
--- a/lib/observer/priv/crashdump_viewer/exploded.gif
+++ /dev/null
Binary files differ
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index dd7831fa2b..ff2bcbdb99 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -92,7 +92,7 @@ EXAMPLE_FILES= multitrace.erl
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
PRIVDIR= ../priv
-WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool $(PRIVDIR)/erlang_observer.png
+PNGFILES= $(PRIVDIR)/erlang_observer.png
BINDIR= $(PRIVDIR)/bin
ifeq ($(findstring win32,$(TARGET)),win32)
WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/cdv.bat
@@ -103,10 +103,6 @@ EXECUTABLES= \
$(BINDIR)/etop \
$(BINDIR)/cdv \
$(WIN32_EXECUTABLES)
-CDVDIR= $(PRIVDIR)/crashdump_viewer
-GIF_FILES= \
- $(CDVDIR)/collapsd.gif \
- $(CDVDIR)/exploded.gif
APP_FILE= observer.app
@@ -163,9 +159,7 @@ release_spec: opt
$(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
$(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
$(INSTALL_SCRIPT) $(EXECUTABLES) "$(RELSYSDIR)/priv/bin"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/crashdump_viewer"
- $(INSTALL_DATA) $(WEBTOOLFILES) "$(RELSYSDIR)/priv"
- $(INSTALL_DATA) $(GIF_FILES) "$(RELSYSDIR)/priv/crashdump_viewer"
+ $(INSTALL_DATA) $(PNGFILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/observer/src/cdv_bin_cb.erl b/lib/observer/src/cdv_bin_cb.erl
index 0cea1fdcf0..5472d36a6f 100644
--- a/lib/observer/src/cdv_bin_cb.erl
+++ b/lib/observer/src/cdv_bin_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ binary_to_term_fun(Bin) ->
try binary_to_term(Bin) of
Term -> plain_html(io_lib:format("~p",[Term]))
catch error:badarg ->
- Warning = "This binary can not be coverted to an Erlang term",
+ Warning = "This binary can not be converted to an Erlang term",
observer_html_lib:warning(Warning)
end
end.
diff --git a/lib/observer/src/cdv_detail_wx.erl b/lib/observer/src/cdv_detail_wx.erl
index 44f121f359..27057fd27f 100644
--- a/lib/observer/src/cdv_detail_wx.erl
+++ b/lib/observer/src/cdv_detail_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ init([Id, Data, ParentFrame, Callback, Parent]) ->
end,
{stop,normal};
{info,Info} ->
- observer_lib:display_info_dialog(Info),
+ observer_lib:display_info_dialog(ParentFrame,Info),
{stop,normal}
end.
diff --git a/lib/observer/src/cdv_ets_cb.erl b/lib/observer/src/cdv_ets_cb.erl
index 52a90b093b..ddd2d42df6 100644
--- a/lib/observer/src/cdv_ets_cb.erl
+++ b/lib/observer/src/cdv_ets_cb.erl
@@ -34,10 +34,8 @@
-define(COL_NAME, ?COL_ID+1).
-define(COL_SLOT, ?COL_NAME+1).
-define(COL_OWNER, ?COL_SLOT+1).
--define(COL_BUCK, ?COL_OWNER+1).
--define(COL_OBJ, ?COL_BUCK+1).
+-define(COL_OBJ, ?COL_OWNER+1).
-define(COL_MEM, ?COL_OBJ+1).
--define(COL_TYPE, ?COL_MEM+1).
%% Callbacks for cdv_virtual_list_wx
col_to_elem(id) -> col_to_elem(?COL_ID);
@@ -45,8 +43,6 @@ col_to_elem(?COL_ID) -> #ets_table.id;
col_to_elem(?COL_NAME) -> #ets_table.name;
col_to_elem(?COL_SLOT) -> #ets_table.slot;
col_to_elem(?COL_OWNER) -> #ets_table.pid;
-col_to_elem(?COL_TYPE) -> #ets_table.data_type;
-col_to_elem(?COL_BUCK) -> #ets_table.buckets;
col_to_elem(?COL_OBJ) -> #ets_table.size;
col_to_elem(?COL_MEM) -> #ets_table.memory.
@@ -57,7 +53,6 @@ col_spec() ->
{"Owner", ?wxLIST_FORMAT_CENTRE, 120},
{"Objects", ?wxLIST_FORMAT_RIGHT, 80},
{"Memory", ?wxLIST_FORMAT_RIGHT, 80}
-% {"Type", ?wxLIST_FORMAT_LEFT, 50}
].
get_info(Owner) ->
diff --git a/lib/observer/src/cdv_mem_cb.erl b/lib/observer/src/cdv_mem_cb.erl
index ba972d6963..abeddc7335 100644
--- a/lib/observer/src/cdv_mem_cb.erl
+++ b/lib/observer/src/cdv_mem_cb.erl
@@ -77,6 +77,10 @@ fix_alloc([{Title,Columns,Data}|Tables]) ->
fix_alloc(Tables)];
fix_alloc([{Title,[{_,V}|_]=Data}|Tables]) ->
fix_alloc([{Title,lists:duplicate(length(V),[]),Data}|Tables]);
+fix_alloc([{"",[]}|Tables]) -> % no name and no data, probably truncated dump
+ fix_alloc(Tables);
+fix_alloc([{Title,[]=Data}|Tables]) -> % no data, probably truncated dump
+ fix_alloc([{Title,[],Data}|Tables]);
fix_alloc([]) ->
[].
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index 9268dac180..13e73f027d 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -90,6 +90,7 @@
%% All possible tags - use macros in order to avoid misspelling in the code
+-define(abort,abort).
-define(allocated_areas,allocated_areas).
-define(allocator,allocator).
-define(atoms,atoms).
@@ -321,8 +322,16 @@ handle_call(general_info,_From,State=#state{file=File}) ->
NumAtoms = GenInfo#general_info.num_atoms,
WS = parse_vsn_str(GenInfo#general_info.system_vsn,4),
TW = case get(truncated) of
- true -> ["WARNING: The crash dump is truncated. "
- "Some information might be missing."];
+ true ->
+ case get(truncated_reason) of
+ undefined ->
+ ["WARNING: The crash dump is truncated. "
+ "Some information might be missing."];
+ Reason ->
+ ["WARNING: The crash dump is truncated "
+ "("++Reason++"). "
+ "Some information might be missing."]
+ end;
false -> []
end,
ets:insert(cdv_reg_proc_table,
@@ -515,8 +524,15 @@ truncated_warning([Tag|Tags]) ->
false -> truncated_warning(Tags)
end.
truncated_warning() ->
- ["WARNING: The crash dump is truncated here. "
- "Some information might be missing."].
+ case get(truncated_reason) of
+ undefined ->
+ ["WARNING: The crash dump is truncated here. "
+ "Some information might be missing."];
+ Reason ->
+ ["WARNING: The crash dump is truncated here "
+ "("++Reason++"). "
+ "Some information might be missing."]
+ end.
truncated_here(Tag) ->
case get(truncated) of
@@ -692,6 +708,7 @@ val(Fd, NoExist) ->
{eof,[]} -> NoExist;
[] -> NoExist;
{eof,Val} -> Val;
+ "=abort:"++_ -> NoExist;
Val -> Val
end.
@@ -787,7 +804,7 @@ do_read_file(File) ->
?erl_crash_dump ->
reset_index_table(),
insert_index(Tag,Id,N1+1),
- put(last_tag,{Tag,""}),
+ put_last_tag(Tag,""),
indexify(Fd,Rest,N1),
end_progress(),
check_if_truncated(),
@@ -831,7 +848,7 @@ indexify(Fd,Bin,N) ->
<<_:Pos/binary,TagAndRest/binary>> = Bin,
{Tag,Id,Rest,N1} = tag(Fd,TagAndRest,N+Pos),
insert_index(Tag,Id,N1+1), % +1 to get past newline
- put(last_tag,{Tag,Id}),
+ put_last_tag(Tag,Id),
indexify(Fd,Rest,N1);
nomatch ->
case progress_read(Fd) of
@@ -911,7 +928,10 @@ general_info(File) ->
WholeLine -> WholeLine
end,
- GI = get_general_info(Fd,#general_info{created=Created}),
+ {Slogan,SysVsn} = get_slogan_and_sysvsn(Fd,[]),
+ GI = get_general_info(Fd,#general_info{created=Created,
+ slogan=Slogan,
+ system_vsn=SysVsn}),
{MemTot,MemMax} =
case lookup_index(?memory) of
@@ -965,12 +985,20 @@ general_info(File) ->
mem_max=MemMax,
instr_info=InstrInfo}.
+get_slogan_and_sysvsn(Fd,Acc) ->
+ case val(Fd,eof) of
+ "Slogan: " ++ SloganPart when Acc==[] ->
+ get_slogan_and_sysvsn(Fd,[SloganPart]);
+ "System version: " ++ SystemVsn ->
+ {lists:append(lists:reverse(Acc)),SystemVsn};
+ eof ->
+ {lists:append(lists:reverse(Acc)),"-1"};
+ SloganPart ->
+ get_slogan_and_sysvsn(Fd,[[$\n|SloganPart]|Acc])
+ end.
+
get_general_info(Fd,GenInfo) ->
case line_head(Fd) of
- "Slogan" ->
- get_general_info(Fd,GenInfo#general_info{slogan=val(Fd)});
- "System version" ->
- get_general_info(Fd,GenInfo#general_info{system_vsn=val(Fd)});
"Compiled" ->
get_general_info(Fd,GenInfo#general_info{compile_time=val(Fd)});
"Taints" ->
@@ -1174,7 +1202,11 @@ parse_link_list("{from,"++Str,Links,Monitors,MonitoredBy) ->
parse_link_list(", "++Rest,Links,Monitors,MonitoredBy) ->
parse_link_list(Rest,Links,Monitors,MonitoredBy);
parse_link_list([],Links,Monitors,MonitoredBy) ->
- {lists:reverse(Links),lists:reverse(Monitors),lists:reverse(MonitoredBy)}.
+ {lists:reverse(Links),lists:reverse(Monitors),lists:reverse(MonitoredBy)};
+parse_link_list(Unexpected,Links,Monitors,MonitoredBy) ->
+ io:format("WARNING: found unexpected data in link list:~n~s~n",[Unexpected]),
+ parse_link_list([],Links,Monitors,MonitoredBy).
+
parse_port(Str) ->
{Port,Rest} = parse_link(Str,[]),
@@ -1813,16 +1845,16 @@ main_modinfo(_Fd,LM,_LineHead) ->
all_modinfo(Fd,LM,LineHead) ->
case LineHead of
"Current attributes" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{current_attrib=Str};
"Current compilation info" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{current_comp_info=Str};
"Old attributes" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{old_attrib=Str};
"Old compilation info" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{old_comp_info=Str};
Other ->
unexpected(Fd,Other,"loaded modules info"),
@@ -1848,7 +1880,12 @@ hex_to_term([],Acc) ->
Bin};
Term ->
Term
- end.
+ end;
+hex_to_term(Rest,Acc) ->
+ {"WARNING: The term is probably truncated!",
+ "I can not convert hex to term.",
+ Rest,list_to_binary(lists:reverse(Acc))}.
+
hex_to_dec("F") -> 15;
hex_to_dec("E") -> 14;
@@ -2159,7 +2196,8 @@ sort_allocator_types([{Name,Data}|Allocators],Acc,DoTotal) ->
Type =
case string:tokens(Name,"[]") of
[T,_Id] -> T;
- [Name] -> Name
+ [Name] -> Name;
+ Other -> Other
end,
TypeData = proplists:get_value(Type,Acc,[]),
{NewTypeData,NewDoTotal} = sort_type_data(Type,Data,TypeData,DoTotal),
@@ -2686,6 +2724,7 @@ count_index(Tag) ->
%%-----------------------------------------------------------------
%% Convert tags read from crashdump to atoms used as first part of key
%% in cdv_dump_index_table
+tag_to_atom("abort") -> ?abort;
tag_to_atom("allocated_areas") -> ?allocated_areas;
tag_to_atom("allocator") -> ?allocator;
tag_to_atom("atoms") -> ?atoms;
@@ -2720,6 +2759,14 @@ tag_to_atom(UnknownTag) ->
list_to_atom(UnknownTag).
%%%-----------------------------------------------------------------
+%%% Store last tag for use when truncated, and reason if aborted
+put_last_tag(?abort,Reason) ->
+ %% Don't overwrite the real last tag
+ put(truncated_reason,Reason);
+put_last_tag(Tag,Id) ->
+ put(last_tag,{Tag,Id}).
+
+%%%-----------------------------------------------------------------
%%% Fetch next chunk from crashdump file
lookup_and_parse_index(File,What,ParseFun,Str) when is_list(File) ->
Indices = lookup_index(What),
@@ -2815,7 +2862,16 @@ collect(Pids,Acc) ->
update_progress(),
collect(Pids,Acc);
{'DOWN', _Ref, process, Pid, {pmap_done,Result}} ->
- collect(lists:delete(Pid,Pids),[Result|Acc])
+ collect(lists:delete(Pid,Pids),[Result|Acc]);
+ {'DOWN', _Ref, process, Pid, _Error} ->
+ Warning =
+ "WARNING: an error occured while parsing data.\n" ++
+ case get(truncated) of
+ true -> "This might be because the dump is truncated.\n";
+ false -> ""
+ end,
+ io:format(Warning),
+ collect(lists:delete(Pid,Pids),Acc)
end.
%%%-----------------------------------------------------------------
diff --git a/lib/observer/src/etop.erl b/lib/observer/src/etop.erl
index fcb900960b..925f4456bb 100644
--- a/lib/observer/src/etop.erl
+++ b/lib/observer/src/etop.erl
@@ -23,7 +23,7 @@
-export([start/0, start/1, config/2, stop/0, dump/1, help/0]).
%% Internal
-export([update/1]).
--export([loadinfo/1, meminfo/2, getopt/2]).
+-export([loadinfo/2, meminfo/2, getopt/2]).
-include("etop.hrl").
-include("etop_defs.hrl").
@@ -319,18 +319,18 @@ output(graphical) -> exit({deprecated, "Use observer instead"});
output(text) -> etop_txt.
-loadinfo(SysI) ->
+loadinfo(SysI,Prev) ->
#etop_info{n_procs = Procs,
run_queue = RQ,
now = Now,
wall_clock = WC,
runtime = RT} = SysI,
- Cpu = calculate_cpu_utilization(WC,RT),
+ Cpu = calculate_cpu_utilization(WC,RT,Prev#etop_info.runtime),
Clock = io_lib:format("~2.2.0w:~2.2.0w:~2.2.0w",
tuple_to_list(element(2,calendar:now_to_datetime(Now)))),
{Cpu,Procs,RQ,Clock}.
-calculate_cpu_utilization({_,WC},{_,RT}) ->
+calculate_cpu_utilization({_,WC},{_,RT},_) ->
%% Old version of observer_backend, using statistics(wall_clock)
%% and statistics(runtime)
case {WC,RT} of
@@ -341,15 +341,23 @@ calculate_cpu_utilization({_,WC},{_,RT}) ->
_ ->
round(100*RT/WC)
end;
-calculate_cpu_utilization(_,undefined) ->
+calculate_cpu_utilization(_,undefined,_) ->
%% First time collecting - no cpu utilization has been measured
%% since scheduler_wall_time flag is not yet on
0;
-calculate_cpu_utilization(_,RTInfo) ->
+calculate_cpu_utilization(WC,RTInfo,undefined) ->
+ %% Second time collecting - RTInfo shows scheduler_wall_time since
+ %% flag was set to true. Faking previous values by setting
+ %% everything to zero.
+ ZeroRT = [{Id,0,0} || {Id,_,_} <- RTInfo],
+ calculate_cpu_utilization(WC,RTInfo,ZeroRT);
+calculate_cpu_utilization(_,RTInfo,PrevRTInfo) ->
%% New version of observer_backend, using statistics(scheduler_wall_time)
- Sum = lists:foldl(fun({_,A,T},{AAcc,TAcc}) -> {A+AAcc,T+TAcc} end,
+ Sum = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}},{AAcc,TAcc}) ->
+ {(A1 - A0)+AAcc,(T1 - T0)+TAcc}
+ end,
{0,0},
- RTInfo),
+ lists:zip(PrevRTInfo,RTInfo)),
case Sum of
{0,0} ->
0;
diff --git a/lib/observer/src/etop_txt.erl b/lib/observer/src/etop_txt.erl
index 3b4c176478..6b8f9df24f 100644
--- a/lib/observer/src/etop_txt.erl
+++ b/lib/observer/src/etop_txt.erl
@@ -22,35 +22,35 @@
%%-compile(export_all).
-export([init/1,stop/1]).
--export([do_update/3]).
+-export([do_update/4]).
-include("etop.hrl").
-include("etop_defs.hrl").
--import(etop,[loadinfo/1,meminfo/2]).
+-import(etop,[loadinfo/2,meminfo/2]).
-define(PROCFORM,"~-15w~-20s~8w~8w~8w~8w ~-20s~n").
stop(Pid) -> Pid ! stop.
init(Config) ->
- loop(Config).
+ loop(#etop_info{},Config).
-loop(Config) ->
- Info = do_update(Config),
+loop(Prev,Config) ->
+ Info = do_update(Prev,Config),
receive
stop -> stopped;
- {dump,Fd} -> do_update(Fd,Info,Config), loop(Config);
- {config,_,Config1} -> loop(Config1)
- after Config#opts.intv -> loop(Config)
+ {dump,Fd} -> do_update(Fd,Info,Prev,Config), loop(Info,Config);
+ {config,_,Config1} -> loop(Info,Config1)
+ after Config#opts.intv -> loop(Info,Config)
end.
-do_update(Config) ->
+do_update(Prev,Config) ->
Info = etop:update(Config),
- do_update(standard_io,Info,Config).
+ do_update(standard_io,Info,Prev,Config).
-do_update(Fd,Info,Config) ->
- {Cpu,NProcs,RQ,Clock} = loadinfo(Info),
+do_update(Fd,Info,Prev,Config) ->
+ {Cpu,NProcs,RQ,Clock} = loadinfo(Info,Prev),
io:nl(Fd),
writedoubleline(Fd),
case Info#etop_info.memi of
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
index 77609b11ce..ca54080e15 100644
--- a/lib/observer/src/observer_alloc_wx.erl
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl
index 936b2783e2..d41cb8ca42 100644
--- a/lib/observer/src/observer_app_wx.erl
+++ b/lib/observer/src/observer_app_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -191,8 +191,8 @@ handle_event(#wx{event=#wxMouse{type=Type, x=X0, y=Y0}},
end;
handle_event(#wx{event=#wxCommand{type=command_menu_selected}},
- State = #state{sel=undefined}) ->
- observer_lib:display_info_dialog("Select process first"),
+ State = #state{panel=Panel,sel=undefined}) ->
+ observer_lib:display_info_dialog(Panel,"Select process first"),
{noreply, State};
handle_event(#wx{id=?ID_PROC_INFO, event=#wxCommand{type=command_menu_selected}},
@@ -205,7 +205,7 @@ handle_event(#wx{id=?ID_PROC_MSG, event=#wxCommand{type=command_menu_selected}},
case observer_lib:user_term(Panel, "Enter message", "") of
cancel -> ok;
{ok, Term} -> Pid ! Term;
- {error, Error} -> observer_lib:display_info_dialog(Error)
+ {error, Error} -> observer_lib:display_info_dialog(Panel,Error)
end,
{noreply, State};
@@ -214,7 +214,7 @@ handle_event(#wx{id=?ID_PROC_KILL, event=#wxCommand{type=command_menu_selected}}
case observer_lib:user_term(Panel, "Enter Exit Reason", "kill") of
cancel -> ok;
{ok, Term} -> exit(Pid, Term);
- {error, Error} -> observer_lib:display_info_dialog(Error)
+ {error, Error} -> observer_lib:display_info_dialog(Panel,Error)
end,
{noreply, State};
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 7c1337025f..7ce4cf45c7 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,12 +20,12 @@
-module(observer_lib).
-export([get_wx_parent/1,
- display_info_dialog/1, display_yes_no_dialog/1,
+ display_info_dialog/2, display_yes_no_dialog/1,
display_progress_dialog/2, destroy_progress_dialog/0,
wait_for_progress/0, report_progress/1,
user_term/3, user_term_multiline/3,
interval_dialog/4, start_timer/1, stop_timer/1,
- display_info/2, fill_info/2, update_info/2, to_str/1,
+ display_info/2, display_info/3, fill_info/2, update_info/2, to_str/1,
create_menus/3, create_menu_item/3,
create_attrs/0,
set_listctrl_col_size/2,
@@ -105,10 +105,10 @@ setup_timer(Bool, {Timer, Old}) ->
timer:cancel(Timer),
setup_timer(Bool, {false, Old}).
-display_info_dialog(Str) ->
- display_info_dialog("",Str).
-display_info_dialog(Title,Str) ->
- Dlg = wxMessageDialog:new(wx:null(), Str, [{caption,Title}]),
+display_info_dialog(Parent,Str) ->
+ display_info_dialog(Parent,"",Str).
+display_info_dialog(Parent,Title,Str) ->
+ Dlg = wxMessageDialog:new(Parent, Str, [{caption,Title}]),
wxMessageDialog:showModal(Dlg),
wxMessageDialog:destroy(Dlg),
ok.
@@ -124,6 +124,11 @@ display_info(Frame, Info) ->
Panel = wxPanel:new(Frame),
wxWindow:setBackgroundStyle(Panel, ?wxBG_STYLE_SYSTEM),
Sizer = wxBoxSizer:new(?wxVERTICAL),
+ InfoFs = display_info(Panel, Sizer, Info),
+ wxWindow:setSizerAndFit(Panel, Sizer),
+ {Panel, Sizer, InfoFs}.
+
+display_info(Panel, Sizer, Info) ->
wxSizer:addSpacer(Sizer, 5),
Add = fun(BoxInfo) ->
case create_box(Panel, BoxInfo) of
@@ -136,9 +141,7 @@ display_info(Frame, Info) ->
[]
end
end,
- InfoFs = [Add(I) || I <- Info],
- wxWindow:setSizerAndFit(Panel, Sizer),
- {Panel, Sizer, InfoFs}.
+ [Add(I) || I <- Info].
fill_info([{dynamic, Key}|Rest], Data)
when is_atom(Key); is_function(Key) ->
@@ -254,6 +257,11 @@ 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({inet, Addr}) ->
+ case inet:ntoa(Addr) of
+ {error,einval} -> to_str(Addr);
+ AddrStr -> AddrStr
+ end;
to_str({{format,Fun},Value}) when is_function(Fun) ->
Fun(Value);
to_str({A, B}) when is_atom(A), is_atom(B) ->
@@ -453,14 +461,16 @@ create_box(Parent, Data) ->
link_entry(Panel,Value);
_ ->
Value = to_str(Value0),
- case length(Value) > 100 of
- true ->
- Shown = lists:sublist(Value, 80),
+ case string:sub_word(lists:sublist(Value, 80),1,$\n) of
+ Value ->
+ %% Short string, no newlines - show all
+ wxStaticText:new(Panel, ?wxID_ANY, Value);
+ Shown ->
+ %% Long or with newlines,
+ %% use tooltip to show all
TCtrl = wxStaticText:new(Panel, ?wxID_ANY, [Shown,"..."]),
wxWindow:setToolTip(TCtrl,wxToolTip:new(Value)),
- TCtrl;
- false ->
- wxStaticText:new(Panel, ?wxID_ANY, Value)
+ TCtrl
end
end,
wxSizer:add(Line, 10, 0), % space of size 10 horisontally
@@ -714,7 +724,7 @@ progress_loop(Title,PD,Caller) ->
if is_list(Reason) -> Reason;
true -> file:format_error(Reason)
end,
- display_info_dialog("Crashdump Viewer Error",FailMsg),
+ display_info_dialog(PD,"Crashdump Viewer Error",FailMsg),
Caller ! error,
unregister(?progress_handler),
unlink(Caller);
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index 1010a6af4c..b0ead42e3f 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -235,12 +235,14 @@ terminate(_Event, #state{appmon=Pid}) ->
code_change(_, _, State) ->
State.
-restart_fetcher(Node, #state{appmon=Old, panel=Panel, time=#ti{fetch=Freq}=Ti}=State) ->
+restart_fetcher(Node, #state{appmon=Old, panel=Panel, time=#ti{fetch=Freq}=Ti, wins=Wins0}=State) ->
catch Old ! exit,
Me = self(),
Pid = spawn_link(Node, observer_backend, fetch_stats, [Me, round(1000/Freq)]),
wxWindow:refresh(Panel),
- precalc(State#state{active=true, appmon=Pid, samples=reset_data(), time=Ti#ti{tick=0}}).
+ Wins = [W#win{state=undefined} || W <- Wins0],
+ precalc(State#state{active=true, appmon=Pid, samples=reset_data(),
+ wins=Wins, time=Ti#ti{tick=0}}).
reset_data() ->
{0, queue:new()}.
@@ -253,18 +255,25 @@ add_data(Stats, {N, Q}, Wins, _, Active) ->
add_data_1([#win{state={_,St}}|_]=Wins0, Last, N, {Drop, Q}, Active)
when St /= undefined ->
- {Wins, Stat} =
- lists:mapfoldl(fun(Win0, Entry) ->
- {Win1,Stat} = add_data_2(Win0, Last, Entry),
- case Active of
- true ->
- Win = add_data_3(Win1, N, Drop, Stat, Q),
- {Win, Stat};
- false ->
- {Win1, Stat}
- end
- end, #{}, Wins0),
- {Wins, {N,queue:in(Stat#{}, Q)}};
+ try
+ {Wins, Stat} =
+ lists:mapfoldl(fun(Win0, Entry) ->
+ {Win1,Stat} = add_data_2(Win0, Last, Entry),
+ case Active of
+ true ->
+ Win = add_data_3(Win1, N, Drop, Stat, Q),
+ {Win, Stat};
+ false ->
+ {Win1, Stat}
+ end
+ end, #{}, Wins0),
+ {Wins, {N,queue:in(Stat#{}, Q)}}
+ catch no_scheduler_change ->
+ {[Win#win{state=init_data(Id, Last),
+ info = info(Id, Last)}
+ || #win{name=Id}=Win <- Wins0], {0,queue:new()}}
+ end;
+
add_data_1(Wins, Stats, 1, {_, Q}, _) ->
{[Win#win{state=init_data(Id, Stats),
info = info(Id, Stats)}
@@ -374,8 +383,8 @@ lmax(MState, Values, State) ->
init_data(runq, {stats, _, T0, _, _}) -> {mk_max(),lists:sort(T0)};
init_data(io, {stats, _, _, {{_,In0}, {_,Out0}}, _}) -> {mk_max(), {In0,Out0}};
init_data(memory, _) -> {mk_max(), info(memory, undefined)};
-init_data(alloc, _) -> {mk_max(), ok};
-init_data(utilz, _) -> {mk_max(), ok}.
+init_data(alloc, _) -> {mk_max(), unused};
+init_data(utilz, _) -> {mk_max(), unused}.
info(runq, {stats, _, T0, _, _}) -> lists:seq(1, length(T0));
info(memory, _) -> [total, processes, atom, binary, code, ets];
@@ -401,15 +410,16 @@ collect_data(memory, {stats, _, _, _, MemInfo}, {Max, MemTypes}) ->
collect_data(alloc, MemInfo, Max) ->
Vs = [Carrier || {_Type,_Block,Carrier} <- MemInfo],
Sample = list_to_tuple(Vs),
- {Sample, lmax(Max, Vs, Sample)};
+ {Sample, {lmax(Max, Vs, Sample),unused}};
collect_data(utilz, MemInfo, Max) ->
Vs = [round(100*Block/Carrier) || {_Type,Block,Carrier} <- MemInfo],
Sample = list_to_tuple(Vs),
- {Sample, lmax(Max,Vs,Sample)}.
+ {Sample, {lmax(Max,Vs,Sample),unused}}.
calc_delta([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) ->
[100*(WN-WP) div (TN-TP)|calc_delta(Ss, Ps)];
-calc_delta([], []) -> [].
+calc_delta([], []) -> [];
+calc_delta(_, _) -> throw(no_scheduler_change).
precalc(#state{samples=Data0, paint=Paint, time=Ti, wins=Wins0}=State) ->
Wins = [precalc(Ti, Data0, Paint, Win) || Win <- Wins0],
diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl
index 3b788642cc..5b9e5c5671 100644
--- a/lib/observer/src/observer_port_wx.erl
+++ b/lib/observer/src/observer_port_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,7 +52,13 @@
slot,
id_str,
links,
- monitors}).
+ monitors,
+ monitored_by,
+ parallelism,
+ locking,
+ queue_size,
+ memory,
+ inet}).
-record(opt, {sort_key=2,
sort_incr=true
@@ -261,10 +267,19 @@ handle_cast(Event, _State) ->
error({unhandled_cast, Event}).
handle_info({portinfo_open, PortIdStr},
- State = #state{grid=Grid, ports=Ports, open_wins=Opened}) ->
- Port = lists:keyfind(PortIdStr,#port.id_str,Ports),
- NewOpened = display_port_info(Grid, Port, Opened),
- {noreply, State#state{open_wins = NewOpened}};
+ State = #state{node=Node, grid=Grid, opt=Opt, open_wins=Opened}) ->
+ Ports0 = get_ports(Node),
+ Ports = update_grid(Grid, Opt, Ports0),
+ Port = lists:keyfind(PortIdStr, #port.id_str, Ports),
+ NewOpened =
+ case Port of
+ false ->
+ self() ! {error,"No such port: " ++ PortIdStr},
+ Opened;
+ _ ->
+ display_port_info(Grid, Port, Opened)
+ end,
+ {noreply, State#state{ports=Ports, open_wins=NewOpened}};
handle_info(refresh_interval, State = #state{node=Node, grid=Grid, opt=Opt,
ports=OldPorts}) ->
@@ -290,8 +305,9 @@ handle_info(not_active, State = #state{timer = Timer0}) ->
Timer = observer_lib:stop_timer(Timer0),
{noreply, State#state{timer=Timer}};
-handle_info({error, Error}, State) ->
- handle_error(Error),
+handle_info({error, Error}, #state{panel=Panel} = State) ->
+ Str = io_lib:format("ERROR: ~s~n",[Error]),
+ observer_lib:display_info_dialog(Panel, Str),
{noreply, State};
handle_info(_Event, State) ->
@@ -358,7 +374,13 @@ list_to_portrec(PL) ->
links = proplists:get_value(links, PL, []),
name = proplists:get_value(registered_name, PL, []),
monitors = proplists:get_value(monitors, PL, []),
- controls = proplists:get_value(name, PL)}.
+ monitored_by = proplists:get_value(monitored_by, PL, []),
+ controls = proplists:get_value(name, PL),
+ parallelism = proplists:get_value(parallelism, PL),
+ locking = proplists:get_value(locking, PL),
+ queue_size = proplists:get_value(queue_size, PL, 0),
+ memory = proplists:get_value(memory, PL, 0),
+ inet = proplists:get_value(inet, PL, [])}.
portrec_to_list(#port{id = Id,
slot = Slot,
@@ -366,14 +388,26 @@ portrec_to_list(#port{id = Id,
links = Links,
name = Name,
monitors = Monitors,
- controls = Controls}) ->
+ monitored_by = MonitoredBy,
+ controls = Controls,
+ parallelism = Parallelism,
+ locking = Locking,
+ queue_size = QueueSize,
+ memory = Memory,
+ inet = Inet}) ->
[{id,Id},
{slot,Slot},
{connected,Connected},
{links,Links},
{name,Name},
{monitors,Monitors},
- {controls,Controls}].
+ {monitored_by,MonitoredBy},
+ {controls,Controls},
+ {parallelism,Parallelism},
+ {locking,Locking},
+ {queue_size,QueueSize},
+ {memory,Memory} |
+ Inet].
display_port_info(Parent, PortRec, Opened) ->
PortIdStr = PortRec#port.id_str,
@@ -391,40 +425,92 @@ do_display_port_info(Parent0, PortRec) ->
Title = "Port Info: " ++ PortRec#port.id_str,
Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title,
[{style, ?wxSYSTEM_MENU bor ?wxCAPTION
- bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}]),
-
+ bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER},
+ {size,{600,400}}]),
+ ScrolledWin = wxScrolledWindow:new(Frame,[{style,?wxHSCROLL bor ?wxVSCROLL}]),
+ wxScrolledWindow:enableScrolling(ScrolledWin,true,true),
+ wxScrolledWindow:setScrollbars(ScrolledWin,20,20,0,0),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxWindow:setSizer(ScrolledWin,Sizer),
Port = portrec_to_list(PortRec),
Fields0 = port_info_fields(Port),
- {_FPanel, _Sizer, _UpFields} = observer_lib:display_info(Frame, Fields0),
+ _UpFields = observer_lib:display_info(ScrolledWin, Sizer, Fields0),
wxFrame:center(Frame),
wxFrame:connect(Frame, close_window, [{skip, true}]),
wxFrame:show(Frame),
Frame.
-port_info_fields(Port) ->
+
+port_info_fields(Port0) ->
+ {InetStruct,Port} = inet_extra_fields(Port0),
Struct =
[{"Overview",
- [{"Name", name},
+ [{"Registered Name", name},
{"Connected", {click,connected}},
{"Slot", slot},
- {"Controls", controls}]},
+ {"Controls", controls},
+ {"Parallelism", parallelism},
+ {"Locking", locking},
+ {"Queue Size", {bytes,queue_size}},
+ {"Memory", {bytes,memory}}]},
{scroll_boxes,
[{"Links",1,{click,links}},
- {"Monitors",1,{click,filter_monitor_info()}}]}],
+ {"Monitors",1,{click,filter_monitor_info()}},
+ {"Monitored by",1,{click,monitored_by}}]} | InetStruct],
observer_lib:fill_info(Struct, Port).
+inet_extra_fields(Port) ->
+ Statistics = proplists:get_value(statistics,Port,[]),
+ Options = proplists:get_value(options,Port,[]),
+ Struct =
+ case proplists:get_value(controls,Port) of
+ Inet when Inet=="tcp_inet"; Inet=="udp_inet"; Inet=="sctp_inet" ->
+ [{"Inet",
+ [{"Local Address", {inet,local_address}},
+ {"Local Port Number", local_port},
+ {"Remote Address", {inet,remote_address}},
+ {"Remote Port Number", remote_port}]},
+ {"Statistics",
+ [stat_name_and_unit(Key) || {Key,_} <- Statistics]},
+ {"Options",
+ [{atom_to_list(Key),Key} || {Key,_} <- Options]}];
+ _ ->
+ []
+ end,
+ Port1 = lists:keydelete(statistics,1,Port),
+ Port2 = lists:keydelete(options,1,Port1),
+ {Struct,Port2 ++ Statistics ++ Options}.
+
+stat_name_and_unit(recv_avg) ->
+ {"Average package size received", {bytes,recv_avg}};
+stat_name_and_unit(recv_cnt) ->
+ {"Number of packets received", recv_cnt};
+stat_name_and_unit(recv_dvi) ->
+ {"Average packet size deviation received", {bytes,recv_dvi}};
+stat_name_and_unit(recv_max) ->
+ {"Largest packet received", {bytes,recv_max}};
+stat_name_and_unit(recv_oct) ->
+ {"Total received", {bytes,recv_oct}};
+stat_name_and_unit(send_avg) ->
+ {"Average packet size sent", {bytes, send_avg}};
+stat_name_and_unit(send_cnt) ->
+ {"Number of packets sent", send_cnt};
+stat_name_and_unit(send_max) ->
+ {"Largest packet sent", {bytes, send_max}};
+stat_name_and_unit(send_oct) ->
+ {"Total sent", {bytes, send_oct}};
+stat_name_and_unit(send_pend) ->
+ {"Data waiting to be sent from driver", {bytes,send_pend}};
+stat_name_and_unit(Key) ->
+ {atom_to_list(Key), Key}.
+
filter_monitor_info() ->
fun(Data) ->
Ms = proplists:get_value(monitors, Data),
[Pid || {process, Pid} <- Ms]
end.
-
-handle_error(Foo) ->
- Str = io_lib:format("ERROR: ~s~n",[Foo]),
- observer_lib:display_info_dialog(Str).
-
update_grid(Grid, Opt, Ports) ->
wx:batch(fun() -> update_grid2(Grid, Opt, Ports) end).
update_grid2(Grid, #opt{sort_key=Sort,sort_incr=Dir}, Ports) ->
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index ee6829b847..f07b9e295a 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -511,7 +511,13 @@ table_holder(#holder{info=Info, attrs=Attrs,
table_holder(S0);
{dump, Fd} ->
EtopInfo = (S0#holder.etop)#etop_info{procinfo=array:to_list(Info)},
- etop_txt:do_update(Fd, EtopInfo, #opts{node=Node}),
+ %% The empty #etop_info{} below is a dummy previous info
+ %% value. It is used by etop to calculate the scheduler
+ %% utilization since last update. When dumping to file,
+ %% there is no previous measurement to use, so we just add
+ %% a dummy here, and the value shown will be since the
+ %% tool was started.
+ etop_txt:do_update(Fd, EtopInfo, #etop_info{}, #opts{node=Node}),
file:close(Fd),
table_holder(S0);
stop ->
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 620979dcc9..8d19d77488 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@ init([Pid, ParentFrame, Parent]) ->
observer_wx:return_to_localnode(ParentFrame, node(Pid)),
{stop, badrpc};
process_undefined ->
- observer_lib:display_info_dialog("No such alive process"),
+ observer_lib:display_info_dialog(ParentFrame,"No such alive process"),
{stop, normal}
end.
@@ -434,7 +434,7 @@ get_gc_info(Arg) ->
filter_monitor_info() ->
fun(Data) ->
Ms = proplists:get_value(monitors, Data),
- [Pid || {process, Pid} <- Ms]
+ [Id || {_Type, Id} <- Ms] % Type is process or port
end.
stringify_bins(Data) ->
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index 59f6443551..bf2afee2a5 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -124,6 +124,8 @@ handle_event(#wx{id=Id}, State = #state{node=Node, grid=Grid, opt=Opt0})
end,
case get_tables2(Node, Opt) of
Error = {error, _} ->
+ Id =:= ?ID_MNESIA andalso
+ wxMenuBar:check(observer_wx:get_menubar(), ?ID_ETS, true),
self() ! Error,
{noreply, State};
Tables ->
@@ -217,22 +219,33 @@ handle_info(refresh_interval, State = #state{node=Node, grid=Grid, opt=Opt,
{noreply, State#state{tabs=Tabs}}
end;
-handle_info({active, Node}, State = #state{parent=Parent, grid=Grid, opt=Opt,
+handle_info({active, Node}, State = #state{parent=Parent, grid=Grid, opt=Opt0,
timer=Timer0}) ->
- Tables = get_tables(Node, Opt),
+ {Tables, Opt} = case Opt0#opt.type =:= mnesia andalso get_tables2(Node, Opt0) of
+ Ts when is_list(Ts) ->
+ {Ts, Opt0};
+ _ -> % false or error getting mnesia tables
+ Opt1 = Opt0#opt{type=ets},
+ {get_tables(Node, Opt1), Opt1}
+ end,
Tabs = update_grid(Grid, Opt, Tables),
wxWindow:setFocus(Grid),
create_menus(Parent, Opt),
Timer = observer_lib:start_timer(Timer0),
- {noreply, State#state{node=Node, tabs=Tabs, timer=Timer}};
+ {noreply, State#state{node=Node, tabs=Tabs, timer=Timer, opt=Opt}};
handle_info(not_active, State = #state{timer = Timer0}) ->
Timer = observer_lib:stop_timer(Timer0),
{noreply, State#state{timer=Timer}};
-handle_info({error, Error}, State) ->
- handle_error(Error),
- {noreply, State};
+handle_info({error, Error}, #state{panel=Panel,opt=Opt}=State) ->
+ Str = io_lib:format("ERROR: ~s~n",[Error]),
+ observer_lib:display_info_dialog(Panel,Str),
+ case Opt#opt.type of
+ mnesia -> wxMenuBar:check(observer_wx:get_menubar(), ?ID_ETS, true);
+ _ -> ok
+ end,
+ {noreply, State#state{opt=Opt#opt{type=ets}}};
handle_info(_Event, State) ->
{noreply, State}.
@@ -353,10 +366,6 @@ list_to_strings([A]) -> integer_to_list(A);
list_to_strings([A|B]) ->
integer_to_list(A) ++ " ," ++ list_to_strings(B).
-handle_error(Foo) ->
- Str = io_lib:format("ERROR: ~s~n",[Foo]),
- observer_lib:display_info_dialog(Str).
-
update_grid(Grid, Opt, Tables) ->
wx:batch(fun() -> update_grid2(Grid, Opt, Tables) end).
update_grid2(Grid, #opt{sort_key=Sort,sort_incr=Dir}, Tables) ->
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 301bb4b32f..738a00180f 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-behaviour(wx_object).
-export([start/0, stop/0]).
--export([create_menus/2, get_attrib/1, get_tracer/0, get_active_node/0,
+-export([create_menus/2, get_attrib/1, get_tracer/0, get_active_node/0, get_menubar/0,
set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
@@ -94,6 +94,9 @@ get_tracer() ->
get_active_node() ->
wx_object:call(observer, get_active_node).
+get_menubar() ->
+ wx_object:call(observer, get_menubar).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(_Args) ->
@@ -391,6 +394,9 @@ handle_call(get_tracer, _From, State=#state{trace_panel=TraceP}) ->
handle_call(get_active_node, _From, State=#state{node=Node}) ->
{reply, Node, State};
+handle_call(get_menubar, _From, State=#state{menubar=MenuBar}) ->
+ {reply, MenuBar, State};
+
handle_call(stop, From, State) ->
stop_servers(State),
{noreply, State#state{reply_to=From}};
@@ -461,10 +467,10 @@ handle_info(_Info, State) ->
stop_servers(#state{node=Node, log=LogOn, sys_panel=Sys, pro_panel=Procs, tv_panel=TVs,
trace_panel=Trace, app_panel=Apps, perf_panel=Perfs,
- allc_panel=Alloc} = _State) ->
+ allc_panel=Alloc, port_panel=Ports} = _State) ->
LogOn andalso rpc:block_call(Node, rb, stop, []),
Me = self(),
- Tabs = [Sys, Procs, TVs, Trace, Apps, Perfs, Alloc],
+ Tabs = [Sys, Procs, Ports, TVs, Trace, Apps, Perfs, Alloc],
Stop = fun() ->
try
_ = [wx_object:stop(Panel) || Panel <- Tabs],
@@ -574,9 +580,10 @@ get_active_pid(#state{notebook=Notebook, pro_panel=Pro, sys_panel=Sys,
pid2panel(Pid, #state{pro_panel=Pro, sys_panel=Sys,
tv_panel=Tv, trace_panel=Trace, app_panel=App,
- perf_panel=Perf, allc_panel=Alloc}) ->
+ perf_panel=Perf, allc_panel=Alloc, port_panel=Port}) ->
case Pid of
Pro -> "Processes";
+ Port -> "Ports";
Sys -> "System";
Tv -> "Table Viewer" ;
Trace -> ?TRACE_STR;
@@ -629,7 +636,8 @@ create_connect_dialog(connect, #state{frame = Frame}) ->
wxWindow:setSizerAndFit(Dialog, VSizer),
wxSizer:setSizeHints(VSizer, Dialog),
- CookiePath = filename:join(os:getenv("HOME"), ".erlang.cookie"),
+ {ok,[[HomeDir]]} = init:get_argument(home),
+ CookiePath = filename:join(HomeDir, ".erlang.cookie"),
DefaultCookie = case filelib:is_file(CookiePath) of
true ->
{ok, Bin} = file:read_file(CookiePath),
diff --git a/lib/observer/src/ttb.erl b/lib/observer/src/ttb.erl
index ac6c4572eb..87a50e046b 100644
--- a/lib/observer/src/ttb.erl
+++ b/lib/observer/src/ttb.erl
@@ -78,6 +78,11 @@ do_tracer(Nodes0,PI,Client,Traci) ->
do_tracer(Clients,PI,Traci) ->
Shell = proplists:get_value(shell, Traci, false),
+ IpPortSpec =
+ case proplists:get_value(queue_size, Traci) of
+ undefined -> 0;
+ QS -> {0,QS}
+ end,
DefShell = fun(Trace) -> dbg:dhandler(Trace, standard_io) end,
{ClientSucc,Succ} =
lists:foldl(
@@ -98,7 +103,7 @@ do_tracer(Clients,PI,Traci) ->
[_,H] = string:tokens(atom_to_list(N),"@"),
H
end,
- case catch dbg:tracer(N,port,dbg:trace_port(ip,0)) of
+ case catch dbg:tracer(N,port,dbg:trace_port(ip,IpPortSpec)) of
{ok,N} ->
{ok,Port} = dbg:trace_port_control(N,get_listen_port),
{ok,T} = dbg:get_tracer(N),
@@ -160,6 +165,8 @@ opt([{resume,MSec}|O],{PI,Client,Traci}) ->
opt(O,{PI,Client,[{resume, {true, MSec}}|Traci]});
opt([{flush,MSec}|O],{PI,Client,Traci}) ->
opt(O,{PI,Client,[{flush, MSec}|Traci]});
+opt([{queue_size,QueueSize}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{queue_size,QueueSize}|Traci]});
opt([],Opt) ->
ensure_opt(Opt).
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 73ed890802..8df69c6624 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -420,6 +420,10 @@ special(File,Procs) ->
%% ".trunc" ->
%% %% ????
%% ok;
+ ".trunc.bytes" ->
+ {ok,_,[TW]} = crashdump_viewer:general_info(),
+ {match,_} = re:run(TW,"CRASH DUMP SIZE LIMIT REACHED"),
+ ok;
_ ->
ok
end,
@@ -481,7 +485,11 @@ do_create_dumps(DataDir,Rel) ->
current ->
CD3 = dump_with_args(DataDir,Rel,"instr","+Mim true"),
CD4 = dump_with_strange_module_name(DataDir,Rel,"strangemodname"),
- {[CD1,CD2,CD3,CD4], DosDump};
+ Bytes = rand:uniform(300000) + 100,
+ CD5 = dump_with_args(DataDir,Rel,"trunc.bytes",
+ "-env ERL_CRASH_DUMP_BYTES " ++
+ integer_to_list(Bytes)),
+ {[CD1,CD2,CD3,CD4,CD5], DosDump};
_ ->
{[CD1,CD2], DosDump}
end.
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index 4c882ad951..41726b1521 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,8 @@
%% Test cases
-export([app_file/1, appup_file/1,
- basic/1, process_win/1, table_win/1
+ basic/1, process_win/1, table_win/1,
+ port_win_when_tab_not_initiated/1
]).
%% Default timetrap timeout (set in init_per_testcase)
@@ -49,7 +50,8 @@ groups() ->
[{gui, [],
[basic,
process_win,
- table_win
+ table_win,
+ port_win_when_tab_not_initiated
]
}].
@@ -299,6 +301,17 @@ table_win(Config) when is_list(Config) ->
observer:stop(),
ok.
+%% Test PR-1296/OTP-14151
+%% Clicking a link to a port before the port tab has been activated the
+%% first time crashes observer.
+port_win_when_tab_not_initiated(Config) ->
+ {ok,Port} = gen_tcp:listen(0,[]),
+ ok = observer:start(),
+ Notebook = setup_whitebox_testing(),
+ observer ! {open_link,erlang:port_to_list(Port)},
+ timer:sleep(1000),
+ observer:stop(),
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index f214810199..ca9ad72473 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.2
+OBSERVER_VSN = 2.3.1
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index cb2b23d534..2dec6e5abf 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -65,7 +65,7 @@ dnl ---------------------------------------------------------------------
dnl Special windows stuff regarding CFLAGS and details in the environment...
dnl ---------------------------------------------------------------------
LM_WINDOWS_ENVIRONMENT
-
+
AC_PROG_MAKE_SET
AC_CHECK_PROGS(LD, ld.sh)
@@ -136,8 +136,8 @@ AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_addr], [], [],
dnl Checks for library functions.
AC_CHECK_FUNCS([memset socket])
-
-# ODBC
+
+# ODBC
$RM -f "$ERL_TOP/lib/odbc/SKIP"
LM_CHECK_THR_LIB
@@ -146,24 +146,24 @@ AC_SUBST(THR_LIBS)
odbc_lib_link_success=no
AC_SUBST(TARGET_FLAGS)
- case $host_os in
- darwin1[[0-4]].*|darwin[[0-9]].*)
+ case $host_os in
+ darwin1[[0-9]].*)
TARGET_FLAGS="-DUNIX"
if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then
- ODBC_LIB= -L"/usr/lib"
- ODBC_INCLUDE="-I/usr/lib/include"
+ ODBC_LIB= -L"/usr/local/lib"
+ ODBC_INCLUDE="-I/usr/local/include"
else
ODBC_LIB=-L"$with_odbc/lib"
ODBC_INCLUDE="-I$with_odbc/include"
fi
-
- AC_CHECK_LIB(iodbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -liodbc"; odbc_lib_link_success=yes])
+
+ AC_CHECK_LIB(iodbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes])
;;
win32|cygwin)
TARGET_FLAGS="-DWIN32"
AC_CHECK_LIB(ws2_32, main)
if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then
- ODBC_LIB=""
+ ODBC_LIB=""
ODBC_INCLUDE=""
else
ODBC_LIB=-L"$with_odbc/lib"
@@ -196,7 +196,7 @@ AC_SUBST(TARGET_FLAGS)
elif test -d "${libdir}/64/."; then
libdir="${libdir}/64"
fi
- fi
+ fi
ODBC_LIB="-L$libdir"
ODBC_INCLUDE="-I$erl_xcomp_isysroot$rdir/include"
break
@@ -207,7 +207,7 @@ AC_SUBST(TARGET_FLAGS)
echo "No odbc library found" > "$ERL_TOP/lib/odbc/SKIP"
else
AC_MSG_RESULT($ODBC_LIB)
- AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes])
+ AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes])
fi
;;
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index d3dd39616f..cc25a21c74 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -32,7 +32,44 @@
<p>This document describes the changes made to the odbc application.
</p>
- <section><title>ODBC 2.11.2</title>
+ <section><title>ODBC 2.12</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Change configure to skip odbc for old MACs, the change in
+ PR-1227 is not backwards compatible with old MACs, and we
+ do not see a need to continue support for such old
+ versions. However it is still possible to make it work on
+ such machines using the --with-odbc configure option.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14083</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.11.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ODBC build configure has been updated to accept Mac OS X
+ El Capitan. Fixed by Lee Bannard.</p>
+ <p>
+ Own Id: OTP-13781</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.11.2</title>
<section><title>Improvements and New Features</title>
<list>
@@ -585,7 +622,7 @@
also been extended. </item><item> The <c>configure</c>
scripts of <c>erl_interface</c> and <c>odbc</c> now
search for thread libraries and thread library quirks the
- same way as <c>erts</c> do. </item><item> The
+ same way as ERTS do. </item><item> The
<c>configure</c> script of the <c>odbc</c> application
now also looks for odbc libraries in <c>lib64</c> and
<c>lib/64</c> directories when building on a 64-bit
diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl
index 5727c1ca50..261dfc6f20 100644
--- a/lib/odbc/test/odbc_connect_SUITE.erl
+++ b/lib/odbc/test/odbc_connect_SUITE.erl
@@ -89,6 +89,7 @@ init_per_suite(Config) when is_list(Config) ->
[{auto_commit, off}] ++ odbc_test_lib:platform_options()) of
{ok, Ref} ->
odbc:disconnect(Ref),
+ ct:timetrap(?default_timeout),
[{tableName, odbc_test_lib:unique_table_name()} | Config];
_ ->
{skip, "ODBC is not properly setup"}
@@ -129,11 +130,8 @@ init_per_testcase(_TestCase, Config) ->
init_per_testcase_common(Config).
init_per_testcase_common(Config) ->
- test_server:format("ODBCINI = ~p~n", [os:getenv("ODBCINI")]),
- Dog = test_server:timetrap(?default_timeout),
- Temp = lists:keydelete(connection_ref, 1, Config),
- NewConfig = lists:keydelete(watchdog, 1, Temp),
- [{watchdog, Dog} | NewConfig].
+ ct:pal("ODBCINI = ~p~n", [os:getenv("ODBCINI")]),
+ lists:keydelete(connection_ref, 1, Config).
%%--------------------------------------------------------------------
%% Function: end_per_testcase(Case, Config) -> _
@@ -153,25 +151,22 @@ end_per_testcase(_TestCase, Config) ->
end_per_testcase_common(Config).
end_per_testcase_common(Config) ->
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
Result = odbc:sql_query(Ref, "DROP TABLE " ++ Table),
io:format("Drop table: ~p ~p~n", [Table, Result]),
- odbc:disconnect(Ref),
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog).
+ odbc:disconnect(Ref).
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
-commit(doc)->
- ["Test the use of explicit commit"];
-commit(suite) -> [];
+commit()->
+ [{doc,"Test the use of explicit commit"}].
commit(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{auto_commit, off}] ++ odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
TransStr = transaction_support_str(?RDBMS),
{updated, _} =
@@ -205,14 +200,13 @@ commit(Config) ->
ok = odbc:disconnect(Ref).
%%-------------------------------------------------------------------------
-rollback(doc)->
- ["Test the use of explicit rollback"];
-rollback(suite) -> [];
+rollback()->
+ [{doc,"Test the use of explicit rollback"}].
rollback(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{auto_commit, off}] ++ odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
TransStr = transaction_support_str(?RDBMS),
@@ -245,9 +239,8 @@ rollback(Config) ->
ok = odbc:disconnect(Ref).
%%-------------------------------------------------------------------------
-not_explicit_commit(doc) ->
- ["Test what happens if you try using commit on a auto_commit connection."];
-not_explicit_commit(suite) -> [];
+not_explicit_commit() ->
+ [{doc,"Test what happens if you try using commit on a auto_commit connection."}].
not_explicit_commit(_Config) ->
{ok, Ref} =
odbc:connect(?RDBMS:connection_string(), [{auto_commit, on}] ++
@@ -256,19 +249,17 @@ not_explicit_commit(_Config) ->
ok = odbc:disconnect(Ref).
%%-------------------------------------------------------------------------
-not_exist_db(doc) ->
- ["Tests valid data format but invalid data in the connection parameters."];
-not_exist_db(suite) -> [];
+not_exist_db() ->
+ [{doc,"Tests valid data format but invalid data in the connection parameters."}].
not_exist_db(_Config) ->
{error, _} = odbc:connect("DSN=foo;UID=bar;PWD=foobar",
odbc_test_lib:platform_options()),
%% So that the odbc control server can be stoped "in the correct way"
- test_server:sleep(100).
+ ct:sleep(100).
%%-------------------------------------------------------------------------
-no_c_executable(doc) ->
- "Test what happens if the port-program can not be found";
-no_c_executable(suite) -> [];
+no_c_executable() ->
+ [{doc,"Test what happens if the port-program can not be found"}].
no_c_executable(_Config) ->
process_flag(trap_exit, true),
Dir = filename:nativename(filename:join(code:priv_dir(odbc),
@@ -293,9 +284,8 @@ no_c_executable(_Config) ->
end.
%%------------------------------------------------------------------------
-port_dies(doc) ->
- "Tests what happens if the port program dies";
-port_dies(suite) -> [];
+port_dies() ->
+ [{doc,"Tests what happens if the port program dies"}].
port_dies(_Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
{status, _} = process_info(Ref, status),
@@ -307,7 +297,7 @@ port_dies(_Config) ->
%% Wait for exit_status from port 5000 ms (will not get a exit
%% status in this case), then wait a little longer to make sure
%% the port and the controlprocess has had time to terminate.
- test_server:sleep(10000),
+ ct:sleep(10000),
undefined = process_info(Ref, status);
[] ->
ct:fail([erlang:port_info(P, name) || P <- erlang:ports()])
@@ -315,9 +305,8 @@ port_dies(_Config) ->
%%-------------------------------------------------------------------------
-control_process_dies(doc) ->
- "Tests what happens if the Erlang control process dies";
-control_process_dies(suite) -> [];
+control_process_dies() ->
+ [{doc,"Tests what happens if the Erlang control process dies"}].
control_process_dies(_Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
process_flag(trap_exit, true),
@@ -326,7 +315,7 @@ control_process_dies(_Config) ->
[Port] ->
{connected, Ref} = erlang:port_info(Port, connected),
exit(Ref, kill),
- test_server:sleep(500),
+ ct:sleep(500),
undefined = erlang:port_info(Port, connected);
%% Check for c-program still running, how?
[] ->
@@ -334,9 +323,8 @@ control_process_dies(_Config) ->
end.
%%-------------------------------------------------------------------------
-client_dies_normal(doc) ->
- ["Client dies with reason normal."];
-client_dies_normal(suite) -> [];
+client_dies_normal() ->
+ [{doc,"Client dies with reason normal."}].
client_dies_normal(Config) when is_list(Config) ->
Pid = spawn(?MODULE, client_normal, [self()]),
@@ -352,7 +340,7 @@ client_dies_normal(Config) when is_list(Config) ->
{'DOWN', MonitorReference, _Type, _Object, _Info} ->
ok
after 5000 ->
- test_server:fail(control_process_not_stopped)
+ ct:fail(control_process_not_stopped)
end.
client_normal(Pid) ->
@@ -366,9 +354,8 @@ client_normal(Pid) ->
%%-------------------------------------------------------------------------
-client_dies_timeout(doc) ->
- ["Client dies with reason timeout."];
-client_dies_timeout(suite) -> [];
+client_dies_timeout() ->
+ [{doc,"Client dies with reason timeout."}].
client_dies_timeout(Config) when is_list(Config) ->
Pid = spawn(?MODULE, client_timeout, [self()]),
@@ -384,7 +371,7 @@ client_dies_timeout(Config) when is_list(Config) ->
{'DOWN', MonitorReference, _Type, _Object, _Info} ->
ok
after 5000 ->
- test_server:fail(control_process_not_stopped)
+ ct:fail(control_process_not_stopped)
end.
client_timeout(Pid) ->
@@ -398,9 +385,8 @@ client_timeout(Pid) ->
%%-------------------------------------------------------------------------
-client_dies_error(doc) ->
- ["Client dies with reason error."];
-client_dies_error(suite) -> [];
+client_dies_error() ->
+ [{doc,"Client dies with reason error."}].
client_dies_error(Config) when is_list(Config) ->
Pid = spawn(?MODULE, client_error, [self()]),
@@ -416,7 +402,7 @@ client_dies_error(Config) when is_list(Config) ->
{'DOWN', MonitorReference, _Type, _Object, _Info} ->
ok
after 5000 ->
- test_server:fail(control_process_not_stopped)
+ ct:fail(control_process_not_stopped)
end.
client_error(Pid) ->
@@ -430,9 +416,8 @@ client_error(Pid) ->
%%-------------------------------------------------------------------------
-connect_timeout(doc) ->
- ["Test the timeout for the connect function."];
-connect_timeout(suite) -> [];
+connect_timeout() ->
+ [{doc,"Test the timeout for the connect function."}].
connect_timeout(Config) when is_list(Config) ->
{'EXIT',timeout} = (catch odbc:connect(?RDBMS:connection_string(),
[{timeout, 0}] ++
@@ -442,10 +427,9 @@ connect_timeout(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-connect_port_timeout(doc) ->
- ["Test the timeout for the port program to connect back to the odbc "
- "application within the connect function."];
-connect_port_timeout(suite) -> [];
+connect_port_timeout() ->
+ [{"Test the timeout for the port program to connect back to the odbc "
+ "application within the connect function."}].
connect_port_timeout(Config) when is_list(Config) ->
%% Application environment var 'port_timeout' has been set to 0 by
%% init_per_testcase/2.
@@ -453,15 +437,14 @@ connect_port_timeout(Config) when is_list(Config) ->
odbc_test_lib:platform_options()).
%%-------------------------------------------------------------------------
-timeout(doc) ->
- ["Test that timeouts don't cause unwanted behavior sush as receiving"
- " an anwser to a previously tiemed out query."];
-timeout(suite) -> [];
+timeout() ->
+ [{"Test that timeouts don't cause unwanted behavior sush as receiving"
+ " an anwser to a previously tiemed out query."}].
timeout(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{auto_commit, off}]),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
TransStr = transaction_support_str(?RDBMS),
@@ -512,7 +495,7 @@ update_table_timeout(Table, TimeOut, Pid) ->
{'EXIT', timeout} ->
Pid ! timout_occurred;
{updated, 1} ->
- test_server:fail(database_locker_failed)
+ ct:fail(database_locker_failed)
end,
receive
@@ -537,15 +520,14 @@ update_table_timeout(Table, TimeOut, Pid) ->
ok = odbc:disconnect(Ref).
%%-------------------------------------------------------------------------
-many_timeouts(doc) ->
- ["Tests that many consecutive timeouts lead to that the connection "
- "is shutdown."];
-many_timeouts(suite) -> [];
+many_timeouts() ->
+ [{doc, "Tests that many consecutive timeouts lead to that the connection "
+ "is shutdown."}].
many_timeouts(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{auto_commit, off}] ++ odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
TransStr = transaction_support_str(?RDBMS),
{updated, _} =
@@ -592,19 +574,18 @@ loop_many_timouts(Ref, UpdateQuery, TimeOut) ->
{'EXIT',timeout} ->
loop_many_timouts(Ref, UpdateQuery, TimeOut);
{updated, 1} ->
- test_server:fail(database_locker_failed);
+ ct:fail(database_locker_failed);
{error, connection_closed} ->
ok
end.
%%-------------------------------------------------------------------------
-timeout_reset(doc) ->
- ["Check that the number of consecutive timouts is reset to 0 when "
- "a successful call to the database is made."];
-timeout_reset(suite) -> [];
+timeout_reset() ->
+ [{doc, "Check that the number of consecutive timouts is reset to 0 when "
+ "a successful call to the database is made."}].
timeout_reset(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{auto_commit, off}] ++ odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
TransStr = transaction_support_str(?RDBMS),
{updated, _} =
@@ -688,21 +669,20 @@ loop_timout_reset(Ref, UpdateQuery, TimeOut, NumTimeouts) ->
loop_timout_reset(Ref, UpdateQuery,
TimeOut, NumTimeouts - 1);
{updated, 1} ->
- test_server:fail(database_locker_failed);
+ ct:fail(database_locker_failed);
{error, connection_closed} ->
- test_server:fail(connection_closed_premature)
+ ct:fail(connection_closed_premature)
end.
%%-------------------------------------------------------------------------
-disconnect_on_timeout(doc) ->
- ["Check that disconnect after a time out works properly"];
-disconnect_on_timeout(suite) -> [];
+disconnect_on_timeout() ->
+ [{doc,"Check that disconnect after a time out works properly"}].
disconnect_on_timeout(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{auto_commit, off}] ++ odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
TransStr = transaction_support_str(?RDBMS),
{updated, _} =
@@ -726,7 +706,7 @@ disconnect_on_timeout(Config) when is_list(Config) ->
ok ->
ok = odbc:commit(Ref, commit);
nok ->
- test_server:fail(database_locker_failed)
+ ct:fail(database_locker_failed)
end.
update_table_disconnect_on_timeout(Table, TimeOut, Pid) ->
@@ -744,14 +724,13 @@ update_table_disconnect_on_timeout(Table, TimeOut, Pid) ->
end.
%%-------------------------------------------------------------------------
-connection_closed(doc) ->
- ["Checks that you get an appropriate error message if you try to"
- " use a connection that has been closed"];
-connection_closed(suite) -> [];
+connection_closed() ->
+ [{doc, "Checks that you get an appropriate error message if you try to"
+ " use a connection that has been closed"}].
connection_closed(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -771,14 +750,13 @@ connection_closed(Config) when is_list(Config) ->
{error, connection_closed} = odbc:commit(Ref, commit).
%%-------------------------------------------------------------------------
-disable_scrollable_cursors(doc) ->
- ["Test disabling of scrollable cursors."];
-disable_scrollable_cursors(suite) -> [];
+disable_scrollable_cursors() ->
+ [{doc,"Test disabling of scrollable cursors."}].
disable_scrollable_cursors(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{scrollable_cursors, off}]),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -792,10 +770,10 @@ disable_scrollable_cursors(Config) when is_list(Config) ->
NextResult = ?RDBMS:selected_ID(1, next),
- test_server:format("Expected: ~p~n", [NextResult]),
+ ct:pal("Expected: ~p~n", [NextResult]),
Result = odbc:next(Ref),
- test_server:format("Got: ~p~n", [Result]),
+ ct:pal("Got: ~p~n", [Result]),
NextResult = Result,
{error, scrollable_cursors_disabled} = odbc:first(Ref),
@@ -809,15 +787,14 @@ disable_scrollable_cursors(Config) when is_list(Config) ->
{selected, _ColNames,[]} = odbc:select(Ref, next, 1).
%%-------------------------------------------------------------------------
-return_rows_as_lists(doc)->
- ["Test the option that a row may be returned as a list instead "
- "of a tuple. Too be somewhat backward compatible."];
-return_rows_as_lists(suite) -> [];
+return_rows_as_lists()->
+ [{doc,"Test the option that a row may be returned as a list instead "
+ "of a tuple. Too be somewhat backward compatible."}].
return_rows_as_lists(Config) when is_list(Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(),
[{tuple_row, off}] ++ odbc_test_lib:platform_options()),
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -854,29 +831,28 @@ return_rows_as_lists(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-api_missuse(doc)->
- ["Test that behaviour of the control process if the api is abused"];
-api_missuse(suite) -> [];
+api_missuse()->
+ [{doc,"Test that behaviour of the control process if the api is abused"}].
api_missuse(Config) when is_list(Config)->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
%% Serious programming fault, connetion will be shut down
gen_server:call(Ref, {self(), foobar, 10}, infinity),
- test_server:sleep(10),
+ ct:sleep(10),
undefined = process_info(Ref, status),
{ok, Ref2} = odbc:connect(?RDBMS:connection_string(),
odbc_test_lib:platform_options()),
%% Serious programming fault, connetion will be shut down
gen_server:cast(Ref2, {self(), foobar, 10}),
- test_server:sleep(10),
+ ct:sleep(10),
undefined = process_info(Ref2, status),
{ok, Ref3} = odbc:connect(?RDBMS:connection_string(),
odbc_test_lib:platform_options()),
%% Could be an innocent misstake the connection lives.
Ref3 ! foobar,
- test_server:sleep(10),
+ ct:sleep(10),
{status, _} = process_info(Ref3, status).
transaction_support_str(mysql) ->
@@ -886,13 +862,13 @@ transaction_support_str(_) ->
%%-------------------------------------------------------------------------
-extended_errors(doc)->
- ["Test the extended errors connection option: When off; the old behaviour of just an error "
- "string is returned on error. When on, the error string is replaced by a 3 element tuple "
- "that also exposes underlying ODBC provider error codes."];
-extended_errors(suite) -> [];
+extended_errors()->
+ [{doc,
+ "Test the extended errors connection option: When off; the old behaviour of just an error "
+ "string is returned on error. When on, the error string is replaced by a 3 element tuple "
+ "that also exposes underlying ODBC provider error codes."}].
extended_errors(Config) when is_list(Config)->
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
{updated, _} = odbc:sql_query(Ref, "create table " ++ Table ++" ( id integer, data varchar(10))"),
diff --git a/lib/odbc/test/odbc_data_type_SUITE.erl b/lib/odbc/test/odbc_data_type_SUITE.erl
index c88c00725e..a3a4bc78eb 100644
--- a/lib/odbc/test/odbc_data_type_SUITE.erl
+++ b/lib/odbc/test/odbc_data_type_SUITE.erl
@@ -120,6 +120,7 @@ init_per_suite(Config) when is_list(Config) ->
false ->
case (catch odbc:start()) of
ok ->
+ ct:timetrap(?default_timeout),
[{tableName, odbc_test_lib:unique_table_name()}| Config];
_ ->
{skip, "ODBC not startable"}
@@ -191,23 +192,22 @@ init_per_testcase(Case, Config) ->
common_init_per_testcase(Case, Config) ->
PlatformOptions = odbc_test_lib:platform_options(),
- case atom_to_list(Case) of
- "binary" ++ _ ->
- {ok, Ref} = odbc:connect(?RDBMS:connection_string(),
- [{binary_strings, on}] ++ PlatformOptions);
- LCase when LCase == "utf8";
- LCase == "nchar";
- LCase == "nvarchar" ->
- {ok, Ref} = odbc:connect(?RDBMS:connection_string(),
- [{binary_strings, on}] ++ PlatformOptions);
- _ ->
- {ok, Ref} = odbc:connect(?RDBMS:connection_string(), PlatformOptions)
- end,
+ {ok, Ref} =
+ case atom_to_list(Case) of
+ "binary" ++ _ ->
+ odbc:connect(?RDBMS:connection_string(),
+ [{binary_strings, on}] ++ PlatformOptions);
+ LCase when LCase == "utf8";
+ LCase == "nchar";
+ LCase == "nvarchar" ->
+ odbc:connect(?RDBMS:connection_string(),
+ [{binary_strings, on}] ++ PlatformOptions);
+ _ ->
+ odbc:connect(?RDBMS:connection_string(), PlatformOptions)
+ end,
odbc_test_lib:strict(Ref, ?RDBMS),
- Dog = test_server:timetrap(?default_timeout),
- Temp = lists:keydelete(connection_ref, 1, Config),
- NewConfig = lists:keydelete(watchdog, 1, Temp),
- [{watchdog, Dog}, {connection_ref, Ref} | NewConfig].
+ NewConfig = lists:keydelete(connection_ref, 1, Config),
+ [{connection_ref, Ref} | NewConfig].
is_fixed_upper_limit(mysql) ->
false;
@@ -231,28 +231,23 @@ is_supported_bit(_) ->
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, Config) ->
- Ref = ?config(connection_ref, Config),
+ Ref = proplists:get_value(connection_ref, Config),
ok = odbc:disconnect(Ref),
%% Clean up if needed
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{ok, NewRef} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
odbc:sql_query(NewRef, "DROP TABLE " ++ Table),
- odbc:disconnect(NewRef),
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
+ odbc:disconnect(NewRef).
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
-char_fixed_lower_limit(doc) ->
- ["Tests fixed length char data type lower boundaries."];
-char_fixed_lower_limit(suite) ->
- [];
+char_fixed_lower_limit() ->
+ [{doc,"Tests fixed length char data type lower boundaries."}].
char_fixed_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Below limit
{error, _} =
@@ -287,18 +282,16 @@ char_fixed_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-char_fixed_upper_limit(doc) ->
- ["Tests fixed length char data type upper boundaries."];
-char_fixed_upper_limit(suite) ->
- [];
+char_fixed_upper_limit() ->
+ [{doc,"Tests fixed length char data type upper boundaries."}].
char_fixed_upper_limit(Config) when is_list(Config) ->
case ?RDBMS of
postgres ->
{skip, "Limit unknown"};
_ ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Upper limit
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -337,14 +330,12 @@ char_fixed_upper_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-char_fixed_padding(doc) ->
- ["Tests that data that is shorter than the given size is padded "
- "with blanks."];
-char_fixed_padding(suite) ->
- [];
+char_fixed_padding() ->
+ [{doc, "Tests that data that is shorter than the given size is padded "
+ "with blanks."}].
char_fixed_padding(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Data should be padded with blanks
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -365,13 +356,11 @@ char_fixed_padding(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-varchar_lower_limit(doc) ->
- ["Tests variable length char data type lower boundaries."];
-varchar_lower_limit(suite) ->
- [];
+varchar_lower_limit() ->
+ [{doc,"Tests variable length char data type lower boundaries."}].
varchar_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Below limit
{error, _} =
@@ -405,13 +394,11 @@ varchar_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-varchar_upper_limit(doc) ->
- ["Tests variable length char data type upper boundaries."];
-varchar_upper_limit(suite) ->
- [];
+varchar_upper_limit() ->
+ [{doc,"Tests variable length char data type upper boundaries."}].
varchar_upper_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
case ?RDBMS of
oracle ->
@@ -455,14 +442,12 @@ varchar_upper_limit(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-varchar_no_padding(doc) ->
- ["Tests that data that is shorter than the given max size is not padded "
- "with blanks."];
-varchar_no_padding(suite) ->
- [];
+varchar_no_padding() ->
+ [{doc, "Tests that data that is shorter than the given max size is not padded "
+ "with blanks."}].
varchar_no_padding(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Data should NOT be padded with blanks
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -481,13 +466,11 @@ varchar_no_padding(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-text_lower_limit(doc) ->
- ["Tests 'long' char data type lower boundaries."];
-text_lower_limit(suite) ->
- [];
+text_lower_limit() ->
+ [{doc,"Tests 'long' char data type lower boundaries."}].
text_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -504,15 +487,13 @@ text_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-text_upper_limit(doc) ->
- [];
-text_upper_limit(suite) ->
- [];
+text_upper_limit() ->
+ [{doc,"Tests 'text' char data type upper boundaries."}].
text_upper_limit(Config) when is_list(Config) ->
{skip,"Consumes too much resources" }.
-%% Ref = ?config(connection_ref, Config),
-%% Table = ?config(tableName, Config),
+%% Ref = proplists:get_value(connection_ref, Config),
+%% Table = proplists:get_value(tableName, Config),
%% {updated, _} = % Value == 0 || -1 driver dependent!
%% odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -534,13 +515,11 @@ text_upper_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-binary_char_fixed_lower_limit(doc) ->
- ["Tests fixed length char data type lower boundaries."];
-binary_char_fixed_lower_limit(suite) ->
- [];
+binary_char_fixed_lower_limit() ->
+ [{doc,"Tests fixed length char data type lower boundaries."}].
binary_char_fixed_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Below limit
{error, _} =
@@ -579,18 +558,16 @@ binary_char_fixed_lower_limit(Config) when is_list(Config) ->
++ "')").
%%-------------------------------------------------------------------------
-binary_char_fixed_upper_limit(doc) ->
- ["Tests fixed length char data type upper boundaries."];
-binary_char_fixed_upper_limit(suite) ->
- [];
+binary_char_fixed_upper_limit() ->
+ [{doc,"Tests fixed length char data type upper boundaries."}].
binary_char_fixed_upper_limit(Config) when is_list(Config) ->
case ?RDBMS of
postgres ->
{skip, "Limit unknown"};
_ ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Upper limit
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -630,14 +607,12 @@ binary_char_fixed_upper_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-binary_char_fixed_padding(doc) ->
- ["Tests that data that is shorter than the given size is padded "
- "with blanks."];
-binary_char_fixed_padding(suite) ->
- [];
+binary_char_fixed_padding() ->
+ [{doc, "Tests that data that is shorter than the given size is padded "
+ "with blanks."}].
binary_char_fixed_padding(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Data should be padded with blanks
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -658,13 +633,11 @@ binary_char_fixed_padding(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-binary_varchar_lower_limit(doc) ->
- ["Tests variable length char data type lower boundaries."];
-binary_varchar_lower_limit(suite) ->
- [];
+binary_varchar_lower_limit() ->
+ [{doc,"Tests variable length char data type lower boundaries."}].
binary_varchar_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Below limit
{error, _} =
@@ -701,13 +674,11 @@ binary_varchar_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-binary_varchar_upper_limit(doc) ->
- ["Tests variable length char data type upper boundaries."];
-binary_varchar_upper_limit(suite) ->
- [];
+binary_varchar_upper_limit() ->
+ [{doc,"Tests variable length char data type upper boundaries."}].
binary_varchar_upper_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
case ?RDBMS of
oracle ->
@@ -750,14 +721,12 @@ binary_varchar_upper_limit(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-binary_varchar_no_padding(doc) ->
- ["Tests that data that is shorter than the given max size is not padded "
- "with blanks."];
-binary_varchar_no_padding(suite) ->
- [];
+binary_varchar_no_padding() ->
+ [{doc,"Tests that data that is shorter than the given max size is not padded "
+ "with blanks."}].
binary_varchar_no_padding(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
%% Data should NOT be padded with blanks
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -776,13 +745,11 @@ binary_varchar_no_padding(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-binary_text_lower_limit(doc) ->
- ["Tests 'long' char data type lower boundaries."];
-binary_text_lower_limit(suite) ->
- [];
+binary_text_lower_limit() ->
+ [{doc,"Tests 'long' char data type lower boundaries."}].
binary_text_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -799,15 +766,13 @@ binary_text_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-binary_text_upper_limit(doc) ->
- [];
-binary_text_upper_limit(suite) ->
- [];
+binary_text_upper_limit() ->
+ [{doc,"Tests text char data type upper boundaries."}].
binary_text_upper_limit(Config) when is_list(Config) ->
{skip,"Consumes too much resources" }.
-%% Ref = ?config(connection_ref, Config),
-%% Table = ?config(tableName, Config),
+%% Ref = proplists:get_value(connection_ref, Config),
+%% Table = proplists:get_value(tableName, Config),
%% {updated, _} = % Value == 0 || -1 driver dependent!
%% odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -830,17 +795,15 @@ binary_text_upper_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-tiny_int_lower_limit(doc) ->
- ["Tests integer of type tinyint."];
-tiny_int_lower_limit(suite) ->
- [];
+tiny_int_lower_limit() ->
+ [{doc,"Tests integer of type tinyint."}].
tiny_int_lower_limit(Config) when is_list(Config) ->
case ?RDBMS of
postgres ->
{skip, "Type tiniyint not supported"};
_ ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -864,17 +827,15 @@ tiny_int_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-tiny_int_upper_limit(doc) ->
- ["Tests integer of type tinyint."];
-tiny_int_upper_limit(suite) ->
- [];
+tiny_int_upper_limit() ->
+ [{doc,"Tests integer of type tinyint."}].
tiny_int_upper_limit(Config) when is_list(Config) ->
case ?RDBMS of
postgres ->
{skip, "Type tiniyint not supported"};
_ ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -898,13 +859,11 @@ tiny_int_upper_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-small_int_lower_limit(doc) ->
- ["Tests integer of type smallint."];
-small_int_lower_limit(suite) ->
- [];
+small_int_lower_limit() ->
+ [{doc,"Tests integer of type smallint."}].
small_int_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -927,13 +886,11 @@ small_int_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-small_int_upper_limit(doc) ->
- ["Tests integer of type smallint."];
-small_int_upper_limit(suite) ->
- [];
+small_int_upper_limit() ->
+ [{doc,"Tests integer of type smallint."}].
small_int_upper_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -955,13 +912,11 @@ small_int_upper_limit(Config) when is_list(Config) ->
++ "')").
%%-------------------------------------------------------------------------
-int_lower_limit(doc) ->
- ["Tests integer of type int."];
-int_lower_limit(suite) ->
- [];
+int_lower_limit() ->
+ [{doc,"Tests integer of type int."}].
int_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -983,13 +938,11 @@ int_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-int_upper_limit(doc) ->
- ["Tests integer of type int."];
-int_upper_limit(suite) ->
- [];
+int_upper_limit() ->
+ [{doc,"Tests integer of type int."}].
int_upper_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1011,13 +964,11 @@ int_upper_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-big_int_lower_limit(doc) ->
- ["Tests integer of type bigint"];
-big_int_lower_limit(suite) ->
- [];
+big_int_lower_limit() ->
+ [{doc,"Tests integer of type bigint"}].
big_int_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1040,13 +991,11 @@ big_int_lower_limit(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-big_int_upper_limit(doc) ->
- ["Tests integer of type bigint."];
-big_int_upper_limit(suite) ->
- [];
+big_int_upper_limit() ->
+ [{doc,"Tests integer of type bigint."}].
big_int_upper_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1068,17 +1017,13 @@ big_int_upper_limit(Config) when is_list(Config) ->
++ "')").
%%-------------------------------------------------------------------------
-bit_false(doc) ->
- [""];
-bit_false(suite) ->
- [];
bit_false(Config) when is_list(Config) ->
case ?RDBMS of
oracle ->
{skip, "Not supported by driver"};
_ ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1102,17 +1047,13 @@ bit_false(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-bit_true(doc) ->
- [""];
-bit_true(suite) ->
- [];
bit_true(Config) when is_list(Config) ->
case ?RDBMS of
oracle ->
{skip, "Not supported by driver"};
_ ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
@@ -1136,14 +1077,11 @@ bit_true(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-float_lower_limit(doc) ->
- [""];
-float_lower_limit(suite) ->
- [];
+
float_lower_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
case ?RDBMS of
mysql ->
@@ -1186,13 +1124,10 @@ float_lower_limit(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-float_upper_limit(doc) ->
- [""];
-float_upper_limit(suite) ->
- [];
+
float_upper_limit(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
case ?RDBMS of
mysql ->
@@ -1218,13 +1153,11 @@ float_upper_limit(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-float_zero(doc) ->
- ["Test the float value zero."];
-float_zero(suite) ->
- [];
+float_zero() ->
+ [{doc,"Test the float value zero."}].
float_zero(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1237,13 +1170,11 @@ float_zero(Config) when is_list(Config) ->
SelectResult =
odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table).
%%-------------------------------------------------------------------------
-real_zero(doc) ->
- ["Test the real value zero."];
-real_zero(suite) ->
- [];
+real_zero() ->
+ [{doc,"Test the real value zero."}].
real_zero(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
case ?RDBMS of
oracle ->
@@ -1262,13 +1193,11 @@ real_zero(Config) when is_list(Config) ->
odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table)
end.
%%------------------------------------------------------------------------
-dec_long(doc) ->
- [""];
dec_long(suit) ->
[];
dec_long(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1281,13 +1210,11 @@ dec_long(Config) when is_list(Config) ->
odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table),
["FIELD"] = odbc_test_lib:to_upper(Fields).
%%------------------------------------------------------------------------
-dec_double(doc) ->
- [""];
dec_double(suit) ->
[];
dec_double(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1329,13 +1256,11 @@ dec_double(Config) when is_list(Config) ->
["FIELD"] = odbc_test_lib:to_upper(Fields2).
%%------------------------------------------------------------------------
-dec_bignum(doc) ->
- [""];
dec_bignum(suit) ->
[];
dec_bignum(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1361,13 +1286,11 @@ dec_bignum(Config) when is_list(Config) ->
odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table),
["FIELD"] = odbc_test_lib:to_upper(Fields1).
%%------------------------------------------------------------------------
-num_long(doc) ->
- [""];
num_long(suit) ->
[];
num_long(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1380,13 +1303,11 @@ num_long(Config) when is_list(Config) ->
odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table),
["FIELD"] = odbc_test_lib:to_upper(Fields).
%%------------------------------------------------------------------------
-num_double(doc) ->
- [""];
num_double(suit) ->
[];
num_double(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1426,13 +1347,11 @@ num_double(Config) when is_list(Config) ->
odbc:sql_query(Ref,"SELECT FIELD FROM " ++ Table),
["FIELD"] = odbc_test_lib:to_upper(Fields2).
%%------------------------------------------------------------------------
-num_bignum(doc) ->
- [""];
num_bignum(suit) ->
[];
num_bignum(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1459,13 +1378,13 @@ num_bignum(Config) when is_list(Config) ->
["FIELD"] = odbc_test_lib:to_upper(Fields1).
%%------------------------------------------------------------------------
-utf8(doc) ->
- ["Test unicode support"];
+utf8() ->
+ [{doc,"Test unicode support"}].
utf8(suit) ->
[];
utf8(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ "(FIELD text)"),
@@ -1487,30 +1406,30 @@ utf8(Config) when is_list(Config) ->
end,
Latin1Data),
- test_server:format("UnicodeIn: ~p ~n",[UnicodeIn]),
+ ct:pal("UnicodeIn: ~p ~n",[UnicodeIn]),
{updated, _} = odbc:param_query(Ref,"INSERT INTO " ++ Table ++ "(FIELD) values(?)",
[{{sql_varchar,50}, UnicodeIn}]),
{selected,_,UnicodeOut} = odbc:sql_query(Ref,"SELECT * FROM " ++ Table),
- test_server:format("UnicodeOut: ~p~n", [UnicodeOut]),
+ ct:pal("UnicodeOut: ~p~n", [UnicodeOut]),
Result = lists:map(fun({Char}) ->
unicode:characters_to_list(Char,utf8)
end, UnicodeOut),
- test_server:format("Result: ~p ~n", [Result]),
+ ct:pal("Result: ~p ~n", [Result]),
Latin1Data = Result.
%%------------------------------------------------------------------------
-nchar(doc) ->
- ["Test unicode nchar support in sqlserver"];
+nchar() ->
+ [{doc,"Test unicode nchar support in sqlserver"}].
nchar(suit) ->
[];
nchar(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1520,13 +1439,13 @@ nchar(Config) when is_list(Config) ->
%%------------------------------------------------------------------------
-nvarchar(doc) ->
- ["Test 'unicode' nvarchar support"];
+nvarchar() ->
+ [{doc,"Test 'unicode' nvarchar support"}].
nvarchar(suit) ->
[];
nvarchar(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1535,13 +1454,11 @@ nvarchar(Config) when is_list(Config) ->
w_char_support(Ref, Table, sql_wlongvarchar, 50).
%%------------------------------------------------------------------------
-timestamp(doc) ->
- [""];
timestamp(suit) ->
[];
timestamp(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1582,21 +1499,21 @@ w_char_support(Ref, Table, CharType, Size) ->
end,
Latin1Data),
- test_server:format("UnicodeIn (utf 16): ~p ~n",[UnicodeIn]),
+ ct:pal("UnicodeIn (utf 16): ~p ~n",[UnicodeIn]),
{updated, _} = odbc:param_query(Ref, "INSERT INTO " ++ Table ++ "(FIELD) values(?)",
[{{CharType, Size},UnicodeIn}]),
{selected,_,UnicodeOut} = odbc:sql_query(Ref,"SELECT * FROM " ++ Table),
- test_server:format("UnicodeOut: ~p~n", [UnicodeOut]),
+ ct:pal("UnicodeOut: ~p~n", [UnicodeOut]),
PadResult = lists:map(fun({Unicode}) ->
unicode:characters_to_list(Unicode,{utf16,little})
end,
UnicodeOut),
- test_server:format("Result: ~p~n", [PadResult]),
+ ct:pal("Result: ~p~n", [PadResult]),
Result = lists:map(fun(Str) -> string:strip(Str) end, PadResult),
diff --git a/lib/odbc/test/odbc_query_SUITE.erl b/lib/odbc/test/odbc_query_SUITE.erl
index 5f719b7287..c283872965 100644
--- a/lib/odbc/test/odbc_query_SUITE.erl
+++ b/lib/odbc/test/odbc_query_SUITE.erl
@@ -113,6 +113,7 @@ init_per_suite(Config) when is_list(Config) ->
false ->
case (catch odbc:start()) of
ok ->
+ ct:timetrap(?default_timeout),
[{tableName, odbc_test_lib:unique_table_name()}| Config];
_ ->
{skip, "ODBC not startable"}
@@ -144,10 +145,10 @@ end_per_suite(_Config) ->
init_per_testcase(_Case, Config) ->
{ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
odbc_test_lib:strict(Ref, ?RDBMS),
- Dog = test_server:timetrap(?default_timeout),
- Temp = lists:keydelete(connection_ref, 1, Config),
- NewConfig = lists:keydelete(watchdog, 1, Temp),
- [{watchdog, Dog}, {connection_ref, Ref} | NewConfig].
+
+ NewConfig = lists:keydelete(connection_ref, 1, Config),
+
+ [{connection_ref, Ref} | NewConfig].
%%--------------------------------------------------------------------
%% Function: end_per_testcase(Case, Config) -> _
@@ -158,27 +159,23 @@ init_per_testcase(_Case, Config) ->
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
end_per_testcase(_Case, Config) ->
- Ref = ?config(connection_ref, Config),
+ Ref = proplists:get_value(connection_ref, Config),
ok = odbc:disconnect(Ref),
%% Clean up if needed
- Table = ?config(tableName, Config),
+ Table = proplists:get_value(tableName, Config),
{ok, NewRef} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()),
odbc:sql_query(NewRef, "DROP TABLE " ++ Table),
- odbc:disconnect(NewRef),
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
+ odbc:disconnect(NewRef).
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
-stored_proc(doc)->
- ["Test stored proc with OUT param"];
-stored_proc(suite) -> [];
+stored_proc()->
+ [{doc, "Test stored proc with OUT param"}].
stored_proc(Config) when is_list(Config) ->
case ?RDBMS of
X when X == oracle; X == postgres->
- Ref = ?config(connection_ref, Config),
+ Ref = proplists:get_value(connection_ref, Config),
{updated, _} =
odbc:sql_query(Ref,
?RDBMS:stored_proc_integer_out()),
@@ -192,12 +189,11 @@ stored_proc(Config) when is_list(Config) ->
{skip, "stored proc not yet supported"}
end.
-sql_query(doc)->
- ["Test the common cases"];
-sql_query(suite) -> [];
+sql_query()->
+ [{doc, "Test the common cases"}].
sql_query(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -235,14 +231,14 @@ sql_query(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-select_count(doc) ->
- ["Tests select_count/[2,3]'s timeout, "
- " select_count's functionality will be better tested by other tests "
- " such as first."];
+select_count() ->
+ [{doc, "Tests select_count/[2,3]'s timeout, "
+ " select_count's functionality will be better tested by other tests "
+ " such as first."}].
select_count(sute) -> [];
select_count(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -257,12 +253,11 @@ select_count(Config) when is_list(Config) ->
(catch odbc:select_count(Ref, "SELECT * FROM ", -1)),
ok.
%%-------------------------------------------------------------------------
-first(doc) ->
- ["Tests first/[1,2]"];
-first(suite) -> [];
+first() ->
+ [doc, {"Tests first/[1,2]"}].
first(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -284,12 +279,11 @@ first(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-last(doc) ->
- ["Tests last/[1,2]"];
-last(suite) -> [];
+last() ->
+ [{doc, "Tests last/[1,2]"}].
last(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -311,12 +305,11 @@ last(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-next(doc) ->
- ["Tests next/[1,2]"];
-next(suite) -> [];
+next() ->
+ [{doc, "Tests next/[1,2]"}].
next(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -337,12 +330,11 @@ next(Config) when is_list(Config) ->
{'EXIT', {function_clause, _}} = (catch odbc:next(Ref, -1)),
ok.
%%-------------------------------------------------------------------------
-prev(doc) ->
- ["Tests prev/[1,2]"];
-prev(suite) -> [];
+prev() ->
+ [{doc, "Tests prev/[1,2]"}].
prev(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -366,12 +358,12 @@ prev(Config) when is_list(Config) ->
{'EXIT', {function_clause, _}} = (catch odbc:prev(Ref, -1)),
ok.
%%-------------------------------------------------------------------------
-select_next(doc) ->
- ["Tests select/[4,5] with CursorRelation = next "];
+select_next() ->
+ [{doc, "Tests select/[4,5] with CursorRelation = next "}].
select_next(suit) -> [];
select_next(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -407,12 +399,12 @@ select_next(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-select_relative(doc) ->
- ["Tests select/[4,5] with CursorRelation = relative "];
+select_relative() ->
+ [{doc, "Tests select/[4,5] with CursorRelation = relative "}].
select_relative(suit) -> [];
select_relative(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -448,12 +440,12 @@ select_relative(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-select_absolute(doc) ->
- ["Tests select/[4,5] with CursorRelation = absolute "];
+select_absolute() ->
+ [{doc, "Tests select/[4,5] with CursorRelation = absolute "}].
select_absolute(suit) -> [];
select_absolute(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = odbc:sql_query(Ref,
"CREATE TABLE " ++ Table ++
@@ -482,12 +474,11 @@ select_absolute(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-create_table_twice(doc) ->
- ["Test what happens if you try to create the same table twice."];
-create_table_twice(suite) -> [];
+create_table_twice() ->
+ [{doc, "Test what happens if you try to create the same table twice."}].
create_table_twice(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -501,12 +492,11 @@ create_table_twice(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-delete_table_twice(doc) ->
- ["Test what happens if you try to delete the same table twice."];
-delete_table_twice(suite) -> [];
+delete_table_twice() ->
+ [{doc, "Test what happens if you try to delete the same table twice."}].
delete_table_twice(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -518,12 +508,12 @@ delete_table_twice(Config) when is_list(Config) ->
ok.
%-------------------------------------------------------------------------
-duplicate_key(doc) ->
- ["Test what happens if you try to use the same key twice"];
+duplicate_key() ->
+ [{doc, "Test what happens if you try to use the same key twice"}].
duplicate_key(suit) -> [];
duplicate_key(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -539,13 +529,12 @@ duplicate_key(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-not_connection_owner(doc) ->
- ["Test what happens if a process that did not start the connection"
- " tries to acess it."];
-not_connection_owner(suite) -> [];
+not_connection_owner() ->
+ [{doc, "Test what happens if a process that did not start the connection"
+ " tries to acess it."}].
not_connection_owner(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
spawn_link(?MODULE, not_owner, [self(), Ref, Table]),
@@ -564,12 +553,11 @@ not_owner(Pid, Ref, Table) ->
Pid ! continue.
%%-------------------------------------------------------------------------
-no_result_set(doc) ->
- ["Tests what happens if you try to use a function that needs an "
- "associated result set when there is none."];
-no_result_set(suite) -> [];
+no_result_set() ->
+ [{doc, "Tests what happens if you try to use a function that needs an "
+ "associated result set when there is none."}].
no_result_set(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
+ Ref = proplists:get_value(connection_ref, Config),
{error, result_set_does_not_exist} = odbc:first(Ref),
{error, result_set_does_not_exist} = odbc:last(Ref),
@@ -582,13 +570,11 @@ no_result_set(Config) when is_list(Config) ->
odbc:select(Ref, {relative, 2}, 1),
ok.
%%-------------------------------------------------------------------------
-query_error(doc) ->
- ["Test what happens if there is an error in the query."];
-query_error(suite) ->
- [];
+query_error() ->
+ [{doc, "Test what happens if there is an error in the query."}].
query_error(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -605,15 +591,13 @@ query_error(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-multiple_select_result_sets(doc) ->
- ["Test what happens if you have a batch of select queries."];
-multiple_select_result_sets(suite) ->
- [];
+multiple_select_result_sets() ->
+ [{doc, "Test what happens if you have a batch of select queries."}].
multiple_select_result_sets(Config) when is_list(Config) ->
case ?RDBMS of
sqlserver ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -640,16 +624,14 @@ multiple_select_result_sets(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-multiple_mix_result_sets(doc) ->
- ["Test what happens if you have a batch of select and other type of"
- " queries."];
-multiple_mix_result_sets(suite) ->
- [];
+multiple_mix_result_sets() ->
+ [{doc, "Test what happens if you have a batch of select and other type of"
+ " queries."}].
multiple_mix_result_sets(Config) when is_list(Config) ->
case ?RDBMS of
sqlserver ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -674,15 +656,13 @@ multiple_mix_result_sets(Config) when is_list(Config) ->
{skip, "multiple result_set not supported"}
end.
%%-------------------------------------------------------------------------
-multiple_result_sets_error(doc) ->
- ["Test what happens if one of the batched queries fails."];
-multiple_result_sets_error(suite) ->
- [];
+multiple_result_sets_error() ->
+ [{doc, "Test what happens if one of the batched queries fails."}].
multiple_result_sets_error(Config) when is_list(Config) ->
case ?RDBMS of
sqlserver ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -709,15 +689,13 @@ multiple_result_sets_error(Config) when is_list(Config) ->
end.
%%-------------------------------------------------------------------------
-param_insert_tiny_int(doc)->
- ["Test insertion of tiny ints by parameterized queries."];
-param_insert_tiny_int(suite) ->
- [];
+param_insert_tiny_int()->
+ [{doc,"Test insertion of tiny ints by parameterized queries."}].
param_insert_tiny_int(Config) when is_list(Config) ->
case ?RDBMS of
sqlserver ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -746,13 +724,11 @@ param_insert_tiny_int(Config) when is_list(Config) ->
{skip, "Type tiniyint not supported"}
end.
%%-------------------------------------------------------------------------
-param_insert_small_int(doc)->
- ["Test insertion of small ints by parameterized queries."];
-param_insert_small_int(suite) ->
- [];
+param_insert_small_int()->
+ [{doc,"Test insertion of small ints by parameterized queries."}].
param_insert_small_int(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -778,13 +754,11 @@ param_insert_small_int(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_int(doc)->
- ["Test insertion of ints by parameterized queries."];
-param_insert_int(suite) ->
- [];
+param_insert_int()->
+ [{doc,"Test insertion of ints by parameterized queries."}].
param_insert_int(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -810,13 +784,11 @@ param_insert_int(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_integer(doc)->
- ["Test insertion of integers by parameterized queries."];
-param_insert_integer(suite) ->
- [];
+param_insert_integer()->
+ [{doc,"Test insertion of integers by parameterized queries."}].
param_insert_integer(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -842,13 +814,11 @@ param_insert_integer(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_decimal(doc)->
- ["Test insertion of decimal numbers by parameterized queries."];
-param_insert_decimal(suite) ->
- [];
+param_insert_decimal()->
+ [{doc,"Test insertion of decimal numbers by parameterized queries."}].
param_insert_decimal(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -893,13 +863,11 @@ param_insert_decimal(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_numeric(doc)->
- ["Test insertion of numeric numbers by parameterized queries."];
-param_insert_numeric(suite) ->
- [];
+param_insert_numeric()->
+ [{doc,"Test insertion of numeric numbers by parameterized queries."}].
param_insert_numeric(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -944,13 +912,11 @@ param_insert_numeric(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_char(doc)->
- ["Test insertion of fixed length string by parameterized queries."];
-param_insert_char(suite) ->
- [];
+param_insert_char()->
+ [{doc,"Test insertion of fixed length string by parameterized queries."}].
param_insert_char(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -980,13 +946,11 @@ param_insert_char(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_character(doc)->
- ["Test insertion of fixed length string by parameterized queries."];
-param_insert_character(suite) ->
- [];
+param_insert_character()->
+ [{doc,"Test insertion of fixed length string by parameterized queries."}].
param_insert_character(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1017,13 +981,11 @@ param_insert_character(Config) when is_list(Config) ->
ok.
%%------------------------------------------------------------------------
-param_insert_char_varying(doc)->
- ["Test insertion of variable length strings by parameterized queries."];
-param_insert_char_varying(suite) ->
- [];
+param_insert_char_varying()->
+ [{doc,"Test insertion of variable length strings by parameterized queries."}].
param_insert_char_varying(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1054,13 +1016,11 @@ param_insert_char_varying(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_character_varying(doc)->
- ["Test insertion of variable length strings by parameterized queries."];
-param_insert_character_varying(suite) ->
- [];
+param_insert_character_varying()->
+ [{doc,"Test insertion of variable length strings by parameterized queries."}].
param_insert_character_varying(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1091,13 +1051,11 @@ param_insert_character_varying(Config) when is_list(Config) ->
[{{sql_varchar, 10}, ["1", 2]}])),
ok.
%%-------------------------------------------------------------------------
-param_insert_float(doc)->
- ["Test insertion of floats by parameterized queries."];
-param_insert_float(suite) ->
- [];
+param_insert_float()->
+ [{doc,"Test insertion of floats by parameterized queries."}].
param_insert_float(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1120,7 +1078,7 @@ param_insert_float(Config) when is_list(Config) ->
true ->
ok;
false ->
- test_server:fail(float_numbers_do_not_match)
+ ct:fail(float_numbers_do_not_match)
end,
{'EXIT',{badarg,odbc,param_query,'Params'}} =
@@ -1130,13 +1088,11 @@ param_insert_float(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_real(doc)->
- ["Test insertion of real numbers by parameterized queries."];
-param_insert_real(suite) ->
- [];
+param_insert_real()->
+ [{doc,"Test insertion of real numbers by parameterized queries."}].
param_insert_real(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1161,7 +1117,7 @@ param_insert_real(Config) when is_list(Config) ->
true ->
ok;
false ->
- test_server:fail(real_numbers_do_not_match)
+ ct:fail(real_numbers_do_not_match)
end,
{'EXIT',{badarg,odbc,param_query,'Params'}} =
@@ -1171,13 +1127,11 @@ param_insert_real(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_double(doc)->
- ["Test insertion of doubles by parameterized queries."];
-param_insert_double(suite) ->
- [];
+param_insert_double()->
+ [{doc,"Test insertion of doubles by parameterized queries."}].
param_insert_double(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1200,7 +1154,7 @@ param_insert_double(Config) when is_list(Config) ->
true ->
ok;
false ->
- test_server:fail(double_numbers_do_not_match)
+ ct:fail(double_numbers_do_not_match)
end,
{'EXIT',{badarg,odbc,param_query,'Params'}} =
@@ -1210,13 +1164,11 @@ param_insert_double(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_insert_mix(doc)->
- ["Test insertion of a mixture of datatypes by parameterized queries."];
-param_insert_mix(suite) ->
- [];
+param_insert_mix()->
+ [{doc,"Test insertion of a mixture of datatypes by parameterized queries."}].
param_insert_mix(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1237,13 +1189,11 @@ param_insert_mix(Config) when is_list(Config) ->
odbc:sql_query(Ref, "SELECT * FROM " ++ Table),
ok.
%%-------------------------------------------------------------------------
-param_update(doc)->
- ["Test parameterized update query."];
-param_update(suite) ->
- [];
+param_update()->
+ [{doc,"Test parameterized update query."}].
param_update(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1272,12 +1222,12 @@ param_update(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-delete_nonexisting_row(doc) -> % OTP-5759
- ["Make a delete...where with false conditions (0 rows deleted). ",
- "This used to give an error message (see ticket OTP-5759)."];
+delete_nonexisting_row() -> % OTP-5759
+ [{doc, "Make a delete...where with false conditions (0 rows deleted). ",
+ "This used to give an error message (see ticket OTP-5759)."}].
delete_nonexisting_row(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref, "CREATE TABLE " ++ Table
@@ -1301,13 +1251,11 @@ delete_nonexisting_row(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_delete(doc) ->
- ["Test parameterized delete query."];
-param_delete(suite) ->
- [];
+param_delete() ->
+ [{doc,"Test parameterized delete query."}].
param_delete(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1336,13 +1284,11 @@ param_delete(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-param_select(doc) ->
- ["Test parameterized select query."];
-param_select(suite) ->
- [];
+param_select() ->
+ [{doc,"Test parameterized select query."}].
param_select(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1366,13 +1312,11 @@ param_select(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_select_empty_params(doc) ->
- ["Test parameterized select query with no parameters."];
-param_select_empty_params(suite) ->
- [];
+param_select_empty_params() ->
+ [{doc,"Test parameterized select query with no parameters."}].
param_select_empty_params(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1396,13 +1340,11 @@ param_select_empty_params(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-param_delete_empty_params(doc) ->
- ["Test parameterized delete query with no parameters."];
-param_delete_empty_params(suite) ->
- [];
+param_delete_empty_params() ->
+ [{doc,"Test parameterized delete query with no parameters."}].
param_delete_empty_params(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1430,13 +1372,11 @@ param_delete_empty_params(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-describe_integer(doc) ->
- ["Test describe_table/[2,3] for integer columns."];
-describe_integer(suite) ->
- [];
+describe_integer() ->
+ [{doc,"Test describe_table/[2,3] for integer columns."}].
describe_integer(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1449,13 +1389,11 @@ describe_integer(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-describe_string(doc) ->
- ["Test describe_table/[2,3] for string columns."];
-describe_string(suite) ->
- [];
+describe_string() ->
+ [{doc,"Test describe_table/[2,3] for string columns."}].
describe_string(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1470,13 +1408,11 @@ describe_string(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-describe_floating(doc) ->
- ["Test describe_table/[2,3] for floting columns."];
-describe_floating(suite) ->
- [];
+describe_floating() ->
+ [{doc,"Test describe_table/[2,3] for floting columns."}].
describe_floating(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1490,14 +1426,12 @@ describe_floating(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-describe_dec_num(doc) ->
- ["Test describe_table/[2,3] for decimal and numerical columns"];
-describe_dec_num(suite) ->
- [];
+describe_dec_num() ->
+ [{doc,"Test describe_table/[2,3] for decimal and numerical columns"}].
describe_dec_num(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} =
odbc:sql_query(Ref,
@@ -1511,14 +1445,12 @@ describe_dec_num(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-describe_timestamp(doc) ->
- ["Test describe_table/[2,3] for tinmestap columns"];
-describe_timestamp(suite) ->
- [];
+describe_timestamp() ->
+ [{doc,"Test describe_table/[2,3] for tinmestap columns"}].
describe_timestamp(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{updated, _} = % Value == 0 || -1 driver dependent!
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++
@@ -1530,14 +1462,12 @@ describe_timestamp(Config) when is_list(Config) ->
ok.
%%-------------------------------------------------------------------------
-describe_no_such_table(doc) ->
- ["Test what happens if you try to describe a table that does not exist."];
-describe_no_such_table(suite) ->
- [];
+describe_no_such_table() ->
+ [{doc,"Test what happens if you try to describe a table that does not exist."}].
describe_no_such_table(Config) when is_list(Config) ->
- Ref = ?config(connection_ref, Config),
- Table = ?config(tableName, Config),
+ Ref = proplists:get_value(connection_ref, Config),
+ Table = proplists:get_value(tableName, Config),
{error, _ } = odbc:describe_table(Ref, Table),
ok.
@@ -1549,10 +1479,10 @@ describe_no_such_table(Config) when is_list(Config) ->
is_driver_error(Error) ->
case is_list(Error) of
true ->
- test_server:format("Driver error ~p~n", [Error]),
+ ct:pal("Driver error ~p~n", [Error]),
ok;
false ->
- test_server:fail(Error)
+ ct:fail(Error)
end.
is_supported_multiple_resultsets(sqlserver) ->
true;
diff --git a/lib/odbc/test/odbc_start_SUITE.erl b/lib/odbc/test/odbc_start_SUITE.erl
index f055eeb60e..310b92ca29 100644
--- a/lib/odbc/test/odbc_start_SUITE.erl
+++ b/lib/odbc/test/odbc_start_SUITE.erl
@@ -49,6 +49,7 @@ init_per_suite(Config) ->
_ ->
%% Make sure odbc is not already started
odbc:stop(),
+ ct:timetrap(?TIMEOUT),
[{tableName, odbc_test_lib:unique_table_name()} | Config]
end
end.
@@ -74,11 +75,9 @@ end_per_suite(_Config) ->
%% variable, but should NOT alter/remove any existing entries.
%% Description: Initialization before each test case
%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- test_server:format("ODBCINI = ~p~n", [os:getenv("ODBCINI")]),
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
+init_per_testcase(_TestCase, Config) ->
+ ct:pal("ODBCINI = ~p~n", [os:getenv("ODBCINI")]),
+ Config.
%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config) -> _
@@ -88,15 +87,8 @@ init_per_testcase(_TestCase, Config0) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
+end_per_testcase(_TestCase, _Config) ->
+ ok.
%%--------------------------------------------------------------------
%% Function: all(Clause) -> TestCases
%% Clause - atom() - suite | doc
@@ -135,10 +127,8 @@ app(Config) when is_list(Config) ->
appup(Config) when is_list(Config) ->
ok = ?t:appup_test(odbc).
-start(doc) ->
- ["Test start/stop of odbc"];
-start(suite) ->
- [];
+start() ->
+ [{doc,"Test start/stop of odbc"}].
start(Config) when is_list(Config) ->
PlatformOptions = odbc_test_lib:platform_options(),
{error,odbc_not_started} = odbc:connect(?RDBMS:connection_string(),
@@ -153,9 +143,9 @@ start(Config) when is_list(Config) ->
start_odbc(transient),
start_odbc(permanent);
{error, odbc_not_started} ->
- test_server:fail(start_failed);
+ ct:fail(start_failed);
Error ->
- test_server:format("Connection failed: ~p~n", [Error]),
+ ct:pal("Connection failed: ~p~n", [Error]),
{skip, "ODBC is not properly setup"}
end.
@@ -166,13 +156,12 @@ start_odbc(Type) ->
ok = odbc:disconnect(Ref),
odbc:stop();
{error, odbc_not_started} ->
- test_server:fail(start_failed)
+ ct:fail(start_failed)
end.
-long_connection_line(doc)->
- ["Test a connection line longer than 127 characters"];
-long_connection_line(suite) -> [];
+long_connection_line()->
+ [{doc,"Test a connection line longer than 127 characters"}].
long_connection_line(_Config) ->
odbc:start(),
String133 = "unknown_odbc_parameter=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
diff --git a/lib/odbc/test/odbc_test_lib.erl b/lib/odbc/test/odbc_test_lib.erl
index 37c2249303..cf82d4d32a 100644
--- a/lib/odbc/test/odbc_test_lib.erl
+++ b/lib/odbc/test/odbc_test_lib.erl
@@ -61,13 +61,13 @@ odbc_check() ->
end.
check_row_count(Count, Count) ->
- test_server:format("Correct row count Count: ~p~n", [Count]),
+ ct:pal("Correct row count Count: ~p~n", [Count]),
true;
check_row_count(_, undefined) ->
- test_server:format("Undefined row count ~n", []),
+ ct:pal("Undefined row count ~n", []),
true;
check_row_count(Expected, Count) ->
- test_server:format("Incorrect row count Expected ~p Got ~p~n",
+ ct:pal("Incorrect row count Expected ~p Got ~p~n",
[Expected, Count]),
false.
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index 957c6b42eb..2e313570e1 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.11.2
+ODBC_VSN = 2.12
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index e6e80b046d..df4151147c 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.4.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Support s390x in os_mon.</p>
+ <p>
+ Own Id: OTP-14161 Aux Id: PR-1309 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 4729d090f8..428e5587ba 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -701,6 +701,7 @@ get_os_wordsize_with_uname() ->
"sparc64" -> 64;
"amd64" -> 64;
"ppc64" -> 64;
+ "s390x" -> 64;
_ -> 32
end.
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index 1ac0fb1d27..59a3d9dee4 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.4.1
+OS_MON_VSN = 2.4.2
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index b826b4d03a..5a16445577 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -31,6 +31,42 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.1.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Correct counting of newlines when rules with newlines
+ are used in Leex. </p>
+ <p>
+ Own Id: OTP-13916 Aux Id: ERL-263 </p>
+ </item>
+ <item>
+ <p> Correct handling of Unicode in Leex. </p>
+ <p>
+ Own Id: OTP-13919</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Parsetools 2.1.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Yecc generates Dialyzer suppressions to avoid
+ warnings when operator precedence declarations are used.
+ </p>
+ <p>
+ Own Id: OTP-13681</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.1.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml
index 6ec9fb5f0e..9188bd2a22 100644
--- a/lib/parsetools/doc/src/yecc.xml
+++ b/lib/parsetools/doc/src/yecc.xml
@@ -201,7 +201,7 @@
<p>The grammar starts with an optional <c>header</c> section. The
header is put first in the generated file, before the module
declaration. The purpose of the header is to provide a means to
- make the documentation generated by <c>EDoc</c> look nicer. Each
+ make the documentation generated by EDoc look nicer. Each
header line should be enclosed in double quotes, and newlines
will be inserted between the lines. For example:</p>
<code>
diff --git a/lib/parsetools/include/leexinc.hrl b/lib/parsetools/include/leexinc.hrl
index 2657fdcfaa..b4449607cb 100644
--- a/lib/parsetools/include/leexinc.hrl
+++ b/lib/parsetools/include/leexinc.hrl
@@ -36,8 +36,10 @@ string(Ics0, L0, Tcs, Ts) ->
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts);
{reject,_Alen,Tlen,_Ics1,L1,_S1} -> % After a non-accepting state
{error,{L0,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},L1};
- {A,Alen,_Tlen,_Ics1,_L1,_S1} ->
- string_cont(yysuf(Tcs, Alen), L0, yyaction(A, Alen, Tcs, L0), Ts)
+ {A,Alen,Tlen,_Ics1,L1,_S1} ->
+ Tcs1 = yysuf(Tcs, Alen),
+ L2 = adjust_line(Tlen, Alen, Tcs1, L1),
+ string_cont(Tcs1, L2, yyaction(A, Alen, Tcs, L0), Ts)
end.
%% string_cont(RestChars, Line, Token, Tokens)
@@ -107,8 +109,10 @@ token(S0, Ics0, L0, Tcs, Tlen0, Tline, A0, Alen0) ->
{reject,_Alen1,Tlen1,Ics1,L1,_S1} -> % No token match
Error = {Tline,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}},
{done,{error,Error,L1},Ics1};
- {A1,Alen1,_Tlen1,_Ics1,_L1,_S1} -> % Use last accept match
- token_cont(yysuf(Tcs, Alen1), L0, yyaction(A1, Alen1, Tcs, Tline))
+ {A1,Alen1,Tlen1,_Ics1,L1,_S1} -> % Use last accept match
+ Tcs1 = yysuf(Tcs, Alen1),
+ L2 = adjust_line(Tlen1, Alen1, Tcs1, L1),
+ token_cont(Tcs1, L2, yyaction(A1, Alen1, Tcs, Tline))
end.
%% token_cont(RestChars, Line, Token)
@@ -181,9 +185,11 @@ tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Ts, A0, Alen0) ->
%% Skip rest of tokens.
Error = {L1,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}},
skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error);
- {A1,Alen1,_Tlen1,_Ics1,_L1,_S1} ->
+ {A1,Alen1,Tlen1,_Ics1,L1,_S1} ->
Token = yyaction(A1, Alen1, Tcs, Tline),
- tokens_cont(yysuf(Tcs, Alen1), L0, Token, Ts)
+ Tcs1 = yysuf(Tcs, Alen1),
+ L2 = adjust_line(Tlen1, Alen1, Tcs1, L1),
+ tokens_cont(Tcs1, L2, Token, Ts)
end.
%% tokens_cont(RestChars, Line, Token, Tokens)
@@ -235,9 +241,11 @@ skip_tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Error, A0, Alen0) ->
{done,{error,Error,L1},eof};
{reject,_Alen1,Tlen1,_Ics1,L1,_S1} ->
skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error);
- {A1,Alen1,_Tlen1,_Ics1,L1,_S1} ->
+ {A1,Alen1,Tlen1,_Ics1,L1,_S1} ->
Token = yyaction(A1, Alen1, Tcs, Tline),
- skip_cont(yysuf(Tcs, Alen1), L1, Token, Error)
+ Tcs1 = yysuf(Tcs, Alen1),
+ L2 = adjust_line(Tlen1, Alen1, Tcs1, L1),
+ skip_cont(Tcs1, L2, Token, Error)
end.
%% skip_cont(RestChars, Line, Token, Error)
@@ -269,6 +277,17 @@ yyrev(List, Tail) -> lists:reverse(List, Tail).
yypre(List, N) -> lists:sublist(List, N).
yysuf(List, N) -> lists:nthtail(N, List).
+%% adjust_line(TokenLength, AcceptLength, Chars, Line) -> NewLine
+%% Make sure that newlines in Chars are not counted twice.
+%% Line has been updated with respect to newlines in the prefix of
+%% Chars consisting of (TokenLength - AcceptLength) characters.
+
+adjust_line(N, N, _Cs, L) -> L;
+adjust_line(T, A, [$\n|Cs], L) ->
+ adjust_line(T-1, A, Cs, L-1);
+adjust_line(T, A, [_|Cs], L) ->
+ adjust_line(T-1, A, Cs, L).
+
%% yystate() -> InitialState.
%% yystate(State, InChars, Line, CurrTokLen, AcceptAction, AcceptLen) ->
%% {Action, AcceptLen, RestChars, Line} |
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl
index 15d42a4d9c..602e47404d 100644
--- a/lib/parsetools/src/leex.erl
+++ b/lib/parsetools/src/leex.erl
@@ -1586,6 +1586,8 @@ out_dfa_graph(St, DFA, DF) ->
case file:open(St#leex.gfile, [write]) of
{ok,Gfile} ->
try
+ %% Set the same encoding as infile:
+ set_encoding(St, Gfile),
io:fwrite(Gfile, "digraph DFA {~n", []),
out_dfa_states(Gfile, DFA, DF),
out_dfa_edges(Gfile, DFA),
@@ -1621,7 +1623,7 @@ out_dfa_edges(File, DFA) ->
foreach(fun (T) ->
Crs = orddict:fetch(T, Tdict),
Edgelab = dfa_edgelabel(Crs),
- io:fwrite(File, " ~b -> ~b [label=\"~s\"];~n",
+ io:fwrite(File, " ~b -> ~b [label=\"~ts\"];~n",
[S,T,Edgelab])
end, sort(orddict:fetch_keys(Tdict)))
end, DFA).
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index 1b426141a1..f6b80eb1b4 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1978,7 +1978,8 @@ output_goto(St, [{_Nonterminal, []} | Go], StateInfo) ->
output_goto(St, Go, StateInfo);
output_goto(St0, [{Nonterminal, List} | Go], StateInfo) ->
F = function_name(yeccgoto, Nonterminal),
- St10 = output_goto1(St0, List, F, StateInfo, true),
+ St05 = fwrite(St0, <<"-dialyzer({nowarn_function, ~w/7}).\n">>, [F]),
+ St10 = output_goto1(St05, List, F, StateInfo, true),
St = output_goto_fini(F, Nonterminal, St10),
output_goto(St, Go, StateInfo);
output_goto(St, [], _StateInfo) ->
diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl
index 949ef3c36e..54602848ec 100644
--- a/lib/parsetools/test/leex_SUITE.erl
+++ b/lib/parsetools/test/leex_SUITE.erl
@@ -45,7 +45,7 @@
pt/1, man/1, ex/1, ex2/1, not_yet/1,
line_wrap/1,
- otp_10302/1, otp_11286/1, unicode/1]).
+ otp_10302/1, otp_11286/1, unicode/1, otp_13916/1]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(1)).
@@ -62,12 +62,12 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [{group, checks}, {group, examples}, {group, bugs}].
+ [{group, checks}, {group, examples}, {group, tickets}, {group, bugs}].
groups() ->
[{checks, [], [file, compile, syntax]},
{examples, [], [pt, man, ex, ex2, not_yet, unicode]},
- {tickets, [], [otp_10302, otp_11286]},
+ {tickets, [], [otp_10302, otp_11286, otp_13916]},
{bugs, [], [line_wrap]}].
init_per_suite(Config) ->
@@ -408,12 +408,12 @@ unicode(Config) when is_list(Config) ->
Ts = [{unicode_1,
<<"%% -*- coding: utf-8 -*-\n"
"Definitions.\n"
- "RTLarrow = (←)\n"
+ "RTLarrow = (←)\n"
"Rules.\n"
- "{RTLarrow} : {token,{'<-',TokenLine}}.\n"
+ "{RTLarrow} : {token,{\"←\",TokenLine}}.\n"
"Erlang code.\n"
"-export([t/0]).\n"
- "t() -> {ok, [{'<-', 1}], 1} = string(\"←\"), ok.">>,
+ "t() -> {ok, [{\"←\", 1}], 1} = string(\"←\"), ok.">>,
default,
ok}],
@@ -1052,7 +1052,7 @@ otp_11286(Config) when is_list(Config) ->
Dir = ?privdir,
UName = [1024] ++ "u",
UDir = filename:join(Dir, UName),
- ok = rpc:call(Node, file, make_dir, [UDir]),
+ _ = rpc:call(Node, file, make_dir, [UDir]),
%% Note: Cannot use UName as filename since the filename is used
%% as module name. To be fixed in R18.
@@ -1095,6 +1095,42 @@ otp_11286(Config) when is_list(Config) ->
true = test_server:stop_node(Node),
ok.
+otp_13916(doc) ->
+ "OTP-13916. Leex rules with newlines result in bad line numbers";
+otp_13916(suite) -> [];
+otp_13916(Config) when is_list(Config) ->
+ Ts = [{otp_13916_1,
+ <<"Definitions.\n"
+ "W = [a-zA-Z0-9]\n"
+ "S = [\\s\\t]\n"
+ "B = [\\n\\r]\n"
+ "Rules.\n"
+ "%% mark line break(s) and empty lines by token 'break'\n"
+ "%% in order to use as delimiters\n"
+ "{B}({S}*{B})+ : {token, {break, TokenLine}}.\n"
+ "{B} : {token, {break, TokenLine}}.\n"
+ "{S}+ : {token, {blank, TokenLine, TokenChars}}.\n"
+ "{W}+ : {token, {word, TokenLine, TokenChars}}.\n"
+ "Erlang code.\n"
+ "-export([t/0]).\n"
+ "t() ->\n"
+ " {ok,[{break,1},{blank,4,\" \"},{word,4,\"breaks\"}],4} =\n"
+ " string(\"\\n\\n \\n breaks\"),\n"
+ " {ok,[{break,1},{word,4,\"works\"}],4} =\n"
+ " string(\"\\n\\n \\nworks\"),\n"
+ " {ok,[{break,1},{word,4,\"L4\"},{break,4},\n"
+ " {word,5,\"L5\"},{break,5},{word,7,\"L7\"}], 7} =\n"
+ " string(\"\\n\\n \\nL4\\nL5\\n\\nL7\"),\n"
+ " {ok,[{break,1},{blank,4,\" \"},{word,4,\"L4\"},\n"
+ " {break,4},{blank,5,\" \"},{word,5,\"L5\"},\n"
+ " {break,5},{blank,7,\" \"},{word,7,\"L7\"}], 7} =\n"
+ " string(\"\\n\\n \\n L4\\n L5\\n\\n L7\"),\n"
+ " ok.\n">>,
+ default,
+ ok}],
+ ?line run(Config, Ts),
+ ok.
+
start_node(Name, Args) ->
[_,Host] = string:tokens(atom_to_list(node()), "@"),
ct:log("Trying to start ~w@~s~n", [Name,Host]),
@@ -1137,7 +1173,7 @@ run_test(Config, Def, Pre) ->
XrlFile = filename:join(DataDir, DefFile),
ErlFile = filename:join(DataDir, Filename),
Opts = [return, warn_unused_vars,{outdir,DataDir}],
- ok = file:write_file(XrlFile, Def, [{encoding, unicode}]),
+ ok = file:write_file(XrlFile, Def),
LOpts = [return, {report, false} |
case Pre of
default ->
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 3710569aba..5bd71d5d19 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -342,7 +342,7 @@ syntax(Config) when is_list(Config) ->
{L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
[]} = compile:file(Parserfile1, [basic_validation,return]),
?line L1 = 31 + SzYeccPre,
- ?line L2 = 38 + SzYeccPre
+ ?line L2 = 39 + SzYeccPre
end(),
%% Bad macro in action. OTP-7224.
@@ -360,7 +360,7 @@ syntax(Config) when is_list(Config) ->
{L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
[]} = compile:file(Parserfile1, [basic_validation,return]),
?line L1 = 31 + SzYeccPre,
- ?line L2 = 38 + SzYeccPre
+ ?line L2 = 39 + SzYeccPre
end(),
%% Check line numbers. OTP-7224.
@@ -1623,7 +1623,7 @@ otp_7292(Config) when is_list(Config) ->
[{_,[{16,_,{unused_function,{foo,0}}}]}]} =
compile:file(Parserfile1, [basic_validation, return]),
L1 = 41 + SzYeccPre,
- L2 = 48 + SzYeccPre
+ L2 = 49 + SzYeccPre
end(),
YeccPre = filename:join(Dir, "yeccpre.hrl"),
@@ -1641,7 +1641,7 @@ otp_7292(Config) when is_list(Config) ->
[{_,[{16,_,{unused_function,{foo,0}}}]}]} =
compile:file(Parserfile1, [basic_validation, return]),
?line L1 = 40 + SzYeccPre,
- ?line L2 = 47 + SzYeccPre
+ ?line L2 = 48 + SzYeccPre
end(),
file:delete(YeccPre),
@@ -2009,7 +2009,7 @@ otp_11286(Config) when is_list(Config) ->
Dir = ?privdir,
UName = [1024] ++ "u",
UDir = filename:join(Dir, UName),
- ok = rpc:call(Node, file, make_dir, [UDir]),
+ _ = rpc:call(Node, file, make_dir, [UDir]),
%% Note: Cannot use UName as filename since the filename is used
%% as module name. To be fixed in R18.
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index befdd82d6e..d102c63730 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.1.2
+PARSETOOLS_VSN = 2.1.4
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index c4d930c01f..92e314186e 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,51 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New function <c>pkix_verify_hostname/2,3</c> Implements
+ certificate hostname checking. See the manual and RFC
+ 6125.</p>
+ <p>
+ Own Id: OTP-13009</p>
+ </item>
+ <item>
+ <p>
+ The ssh host key fingerprint generation now also takes a
+ list of algorithms and returns a list of corresponding
+ fingerprints. See
+ <c>public_key:ssh_hostkey_fingerprint/2</c> and the
+ option <c>silently_accept_hosts</c> in
+ <c>ssh:connect</c>.</p>
+ <p>
+ Own Id: OTP-14223</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New function
+ <c>public_key:ssh_hostkey_fingerprint/1,2</c> to
+ calculate the SSH host key fingerprint string.</p>
+ <p>
+ Own Id: OTP-13888 Aux Id: OTP-13887 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 385604677c..a34c9de76b 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2015</year>
+ <year>2017</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -757,6 +757,39 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
+ <name>pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()</name>
+ <name>pkix_verify_hostname(Cert, ReferenceIDs, Opts) -> boolean()</name>
+ <fsummary>Verifies that a PKIX x.509 certificate <i>presented identifier</i> (e.g hostname) is
+ an expected one.</fsummary>
+ <type>
+ <v>Cert = der_encoded() | #'OTPCertificate'{} </v>
+ <v>ReferenceIDs = [ RefID ]</v>
+ <v>RefID = {IdType,string()}</v>
+ <v>IdType = dns_id | srv_id | uri_id</v>
+ <v>Opts = [ PvhOpt() ]</v>
+ <v>PvhOpt = [MatchOpt | FailCallBackOpt | FqdnExtractOpt]</v>
+ <v>MatchOpt = {fun(RefId | FQDN::string(), PresentedID) -> boolean() | default}</v>
+ <v>PresentedID = {dNSName,string()} | {uniformResourceIdentifier,string()}</v>
+ <v>FailCallBackOpt = {fail_callback, fun(#'OTPCertificate'{}) -> boolean()}</v>
+ <v>FqdnExtractOpt = {fqdn_fun, fun(RefID) -> FQDN::string() | default | undefined}</v>
+ </type>
+ <desc>
+ <p>This function checks that the <i>Presented Identifier</i> (e.g hostname) in a peer certificate
+ conforms with the Expected Identifier that the client wants to connect to.
+ This functions is intended to be added as an extra client check to the peer certificate when performing
+ <seealso marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
+ </p>
+ <p>See <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url>
+ for detailed information about hostname verification.
+ The <seealso marker="using_public_key#verify_hostname">User's Manual</seealso>
+ and
+ <seealso marker="using_public_key#verify_hostname_examples">code examples</seealso>
+ describes this function more detailed.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>sign(Msg, DigestType, Key) -> binary()</name>
<fsummary>Creates a digital signature.</fsummary>
<type>
@@ -822,6 +855,41 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
+ <name>ssh_hostkey_fingerprint(HostKey) -> string()</name>
+ <name>ssh_hostkey_fingerprint(DigestType, HostKey) -> string()</name>
+ <name>ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()]</name>
+ <fsummary>Calculates a ssh fingerprint for a hostkey.</fsummary>
+ <type>
+ <v>Key = public_key()</v>
+ <v>DigestType = digest_type()</v>
+ </type>
+ <desc>
+ <p>Calculates a ssh fingerprint from a public host key as openssh does.</p>
+ <p>The algorithm in <c>ssh_hostkey_fingerprint/1</c> is md5 to be compatible with older
+ ssh-keygen commands. The string from the second variant is prepended by the algorithm name
+ in uppercase as in newer ssh-keygen commands.</p>
+ <p>Examples:</p>
+ <code>
+ 2> public_key:ssh_hostkey_fingerprint(Key).
+ "f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"
+
+ 3> public_key:ssh_hostkey_fingerprint(md5,Key).
+ "MD5:f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"
+
+ 4> public_key:ssh_hostkey_fingerprint(sha,Key).
+ "SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY"
+
+ 5> public_key:ssh_hostkey_fingerprint(sha256,Key).
+ "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"
+
+ 6> public_key:ssh_hostkey_fingerprint([sha,sha256],Key).
+ ["SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY",
+ "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"]
+ </code>
+ </desc>
+ </func>
+
+ <func>
<name>verify(Msg, DigestType, Signature, Key) -> boolean()</name>
<fsummary>Verifies a digital signature.</fsummary>
<type>
diff --git a/lib/public_key/doc/src/public_key_app.xml b/lib/public_key/doc/src/public_key_app.xml
index 1f87932b6c..923a9f1dfb 100644
--- a/lib/public_key/doc/src/public_key_app.xml
+++ b/lib/public_key/doc/src/public_key_app.xml
@@ -61,7 +61,7 @@
<section>
<title>DEPENDENCIES</title>
<p>The <c>public_key</c> application uses the
- Crypto application to preform cryptographic operations and the
+ Crypto application to perform cryptographic operations and the
ASN-1 application to handle PKIX-ASN-1 specifications, hence
these applications must be loaded for the <c>public_key</c> application to work.
In an embedded environment this means they must be started with
@@ -72,7 +72,7 @@
<section>
<title>ERROR LOGGER AND EVENT HANDLERS</title>
<p> The <c>public_key</c> application is a library application
- and does not use the error logger. The functions will either sucssed
+ and does not use the error logger. The functions will either succeed
or fail with a runtime error.
</p>
</section>
diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml
index e3a1eed4be..417d479da3 100644
--- a/lib/public_key/doc/src/using_public_key.xml
+++ b/lib/public_key/doc/src/using_public_key.xml
@@ -417,6 +417,259 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code>
</section>
+ <section>
+ <marker id="verify_hostname"></marker>
+ <title>Verifying a certificate hostname</title>
+ <section>
+ <title>Background</title>
+ <p>When a client checks a server certificate there are a number of checks available like
+ checks that the certificate is not revoked, not forged or not out-of-date.
+ </p>
+ <p>There are however attacks that are not detected by those checks. Suppose a bad guy has
+ succeded with a DNS infection. Then the client could belive it is connecting to one host but
+ ends up at another but evil one. Though it is evil, it could have a perfectly legal
+ certificate! The certificate has a valid signature, it is not revoked, the certificate chain
+ is not faked and has a trusted root and so on.
+ </p>
+ <p>To detect that the server is not the intended one, the client must additionaly perform
+ a <i>hostname verification</i>. This procedure is described in
+ <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url>. The idea is that the certificate
+ lists the hostnames it could be fetched from. This is checked by the certificate issuer when
+ the certificate is signed. So if the certificate is issued by a trusted root the client
+ could trust the host names signed in it.
+ </p>
+ <p>There is a default hostname matching procedure defined in
+ <url href="https://tools.ietf.org/html/rfc6125#section-6">RFC 6125, section 6</url>
+ as well as protocol dependent variations defined in
+ <url href="https://tools.ietf.org/html/rfc6125#appendix-B">RFC 6125 appendix B</url>.
+ The default procedure is implemented in
+ <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2,3</seealso>.
+ It is possible for a client to hook in modified rules using the options list.
+ </p>
+ <p>Some terminology is needed: the certificate presents hostname(s) on which it is valid.
+ Those are called <i>Presented IDs</i>. The hostname(s) the client belives it connects to
+ are called <i>Reference IDs</i>. The matching rules aims to verify that there is at least
+ one of the Reference IDs that matches one of the Presented IDs. If not, the verification fails.
+ </p>
+ <p>The IDs contains normal fully qualified domain names like e.g <c>foo.example.com</c>,
+ but IP addresses are not recommended. The rfc describes why this is not recommended as well
+ as security considerations about how to aquire the Reference IDs.
+ </p>
+ <p>Internationalized domain names are not supported.
+ </p>
+ </section>
+ <section>
+ <title>The verification process</title>
+ <p>Traditionally the Presented IDs were found in the <c>Subject</c> certificate field as <c>CN</c>
+ names. This is still quite common. When printing a certificate they show up as:
+ </p>
+ <code>
+ $ openssl x509 -text &lt; cert.pem
+ ...
+ Subject: C=SE, CN=example.com, CN=*.example.com, O=erlang.org
+ ...
+ </code>
+ <p>The example <c>Subject</c> field has one C, two CN and one O part. It is only the
+ CN (Common Name) that is used by hostname verification. The two other (C and O) is not used
+ here even when they contain a domain name like the O part. The C and O parts are defined
+ elsewhere and meaningful only for other functions.
+ </p>
+ <p>In the example the Presented IDs are <c>example.com</c> as well as hostnames matching
+ <c>*.example.com</c>. For example <c>foo.example.com</c> and <c>bar.example.com</c> both
+ matches but not <c>foo.bar.example.com</c>. The name <c>erlang.org</c> matches neither
+ since it is not a CN.
+ </p>
+ <p>In case where the Presented IDs are fetched from the <c>Subject</c> certificate field, the
+ names may contain wildcard characters. The function handles this as defined in
+ <url href="https://tools.ietf.org/html/rfc6125#section-6.4.3">chapter 6.4.3 in RFC 6125</url>.
+ </p>
+ <p>There may only be one wildcard character and that is in the first label, for example:
+ <c>*.example.com</c>. This matches <c>foo.example.com</c> but neither <c>example.com</c> nor
+ <c>foo.bar.example.com</c>.
+ </p>
+ <p>There may be label characters before or/and after the wildcard. For example:
+ <c>a*d.example.com</c> matches <c>abcd.example.com</c> and <c>ad.example.com</c>,
+ but not <c>ab.cd.example.com</c>.
+ </p>
+ <p>In the previous example there is no indication of which protocols are expected. So a client
+ has no indication of whether it is a web server, an ldap server or maybe a sip server it is
+ connected to.
+ There are fields in the certificate that can indicate this. To be more exact, the rfc
+ introduces the usage of the <c>X509v3 Subject Alternative Name</c> in the <c>X509v3 extensions</c>
+ field:
+ </p>
+ <code>
+ $ openssl x509 -text &lt; cert.pem
+ ...
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:kb.example.org, URI:https://www.example.org
+ ...
+ </code>
+ <p>Here <c>kb.example.org</c> serves any protocol while <c>www.example.org</c> presents a secure
+ web server.
+ </p>
+
+ <p>The next example has both <c>Subject</c> and <c>Subject Alternate Name</c> present:</p>
+ <code>
+ $ openssl x509 -text &lt; cert.pem
+ ...
+ Subject: C=SE, CN=example.com, CN=*.example.com, O=erlang.org
+ ...
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:kb.example.org, URI:https://www.example.org
+ ...
+ </code>
+ <p>The RFC states that if a certificate defines Reference IDs in a <c>Subject Alternate Name</c>
+ field, the <c>Subject</c> field MUST NOT be used for host name checking, even if it contains
+ valid CN names.
+ Therefore only <c>kb.example.org</c> and <c>https://www.example.org</c> matches. The match fails
+ both for <c>example.com</c> and <c>foo.example.com</c> becuase they are in the <c>Subject</c>
+ field which is not checked because the <c>Subject Alternate Name</c> field is present.
+ </p>
+ </section>
+
+ <section>
+ <marker id="verify_hostname_examples"></marker>
+ <title>Function call examples</title>
+ <note>
+ <p>Other applications like ssl/tls or https might have options that are passed
+ down to the <c>public_key:pkix_verify_hostname</c>. You will probably not
+ have to call it directly</p>
+ </note>
+ <p>Suppose our client expects to connect to the web server https://www.example.net. This
+ URI is therefore the Reference IDs of the client.
+ The call will be:
+ </p>
+ <code>
+ public_key:pkix_verify_hostname(CertFromHost,
+ [{uri_id, "https://www.example.net"}
+ ]).
+ </code>
+ <p>The call will return <c>true</c> or <c>false</c> depending on the check. The caller
+ do not need to handle the matching rules in the rfc. The matching will proceed as:
+ </p>
+ <list>
+ <item>If there is a <c>Subject Alternate Name</c> field, the <c>{uri_id,string()}</c> in the
+ function call will be compared to any
+ <c>{uniformResourceIdentifier,string()}</c> in the Certificate field.
+ If the two <c>strings()</c> are equal (case insensitive), there is a match.
+ The same applies for any <c>{dns_id,string()}</c> in the call which is compared
+ with all <c>{dNSName,string()}</c> in the Certificate field.
+ </item>
+ <item>If there is NO <c>Subject Alternate Name</c> field, the <c>Subject</c> field will be
+ checked. All <c>CN</c> names will be compared to all hostnames <i>extracted</i> from
+ <c>{uri_id,string()}</c> and from <c>{dns_id,string()}</c>.
+ </item>
+ </list>
+ </section>
+ <section>
+ <title>Extending the search mechanism</title>
+ <p>The caller can use own extraction and matching rules. This is done with the two options
+ <c>fqdn_fun</c> and <c>match_fun</c>.
+ </p>
+ <section>
+ <title>Hostname extraction</title>
+ <p>The <c>fqdn_fun</c> extracts hostnames (Fully Qualified Domain Names) from uri_id
+ or other ReferenceIDs that are not pre-defined in the public_key function.
+ Suppose you have some URI with a very special protocol-part:
+ <c>myspecial://example.com"</c>. Since this a non-standard URI there will be no hostname
+ extracted for matching CN-names in the <c>Subject</c>.</p>
+ <p>To "teach" the function how to extract, you can give a fun which replaces the default
+ extraction function.
+ The <c>fqdn_fun</c> takes one argument and returns
+ either a <c>string()</c> to be matched to each CN-name or the atom <c>default</c> which will invoke
+ the default fqdn extraction function. The return value <c>undefined</c> removes the current
+ URI from the fqdn extraction.
+ </p>
+ <code>
+ ...
+ Extract = fun({uri_id, "myspecial://"++HostName}) -> HostName;
+ (_Else) -> default
+ end,
+ ...
+ public_key:pkix_verify_hostname(CertFromHost, RefIDs,
+ [{fqdn_fun, Extract}])
+ ...
+ </code>
+ </section>
+ <section>
+ <title>Re-defining the match operations</title>
+ <p>The default matching handles dns_id and uri_id. In an uri_id the value is tested for
+ equality with a value from the <c>Subject Alternate Name</c>. If som other kind of matching
+ is needed, use the <c>match_fun</c> option.
+ </p>
+ <p>The <c>match_fun</c> takes two arguments and returns either <c>true</c>,
+ <c>false</c> or <c>default</c>. The value <c>default</c> will invoke the default
+ match function.
+ </p>
+ <code>
+ ...
+ Match = fun({uri_id,"myspecial://"++A},
+ {uniformResourceIdentifier,"myspecial://"++B}) ->
+ my_match(A,B);
+ (_RefID, _PresentedID) ->
+ default
+ end,
+ ...
+ public_key:pkix_verify_hostname(CertFromHost, RefIDs,
+ [{match_fun, Match}]),
+ ...
+ </code>
+ <p>In case of a match operation between a ReferenceID and a CN value from the <c>Subject</c>
+ field, the first argument to the fun is the extracted hostname from the ReferenceID, and the
+ second argument is the tuple <c>{cn, string()}</c> taken from the <c>Subject</c> field. That
+ makes it possible to have separate matching rules for Presented IDs from the <c>Subject</c>
+ field and from the <c>Subject Alternate Name</c> field.
+ </p>
+ <p>The default matching transformes the ascii values in strings to lowercase before comparing.
+ The <c>match_fun</c> is however called without any transfomation applied to the strings. The
+ reason is to enable the user to do unforseen handling of the strings where the original format
+ is needed.
+ </p>
+ </section>
+ </section>
+ <section>
+ <title>"Pinning" a Certificate</title>
+ <p>The <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url> defines <i>pinning</i>
+ as:</p>
+ <quote>
+ <p>"The act of establishing a cached name association between
+ the application service's certificate and one of the client's
+ reference identifiers, despite the fact that none of the presented
+ identifiers matches the given reference identifier. ..."
+ </p>
+ </quote>
+ <p>The purpose is to have a mechanism for a human to accept an otherwise faulty Certificate.
+ In for example a web browser, you could get a question like </p>
+ <quote>
+ <p>Warning: you wanted to visit the site www.example.com,
+ but the certificate is for shop.example.com. Accept anyway (yes/no)?"
+ </p>
+ </quote>
+ <p>This could be accomplished with the option <c>fail_callback</c> which will
+ be called if the hostname verification fails:
+ </p>
+ <code>
+ -include_lib("public_key/include/public_key.hrl"). % Record def
+ ...
+ Fail = fun(#'OTPCertificate'{}=C) ->
+ case in_my_cache(C) orelse my_accept(C) of
+ true ->
+ enter_my_cache(C),
+ true;
+ false ->
+ false
+ end,
+ ...
+ public_key:pkix_verify_hostname(CertFromHost, RefIDs,
+ [{fail_callback, Fail}]),
+ ...
+ </code>
+ </section>
+ </section>
+
<section>
<title>SSH Files</title>
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index d23abfe256..730f90e745 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,7 +48,9 @@
pkix_issuer_id/2,
pkix_normalize_name/1,
pkix_path_validation/3,
+ pkix_verify_hostname/2, pkix_verify_hostname/3,
ssh_decode/2, ssh_encode/2,
+ ssh_hostkey_fingerprint/1, ssh_hostkey_fingerprint/2,
ssh_curvename2oid/1, oid2ssh_curvename/1,
pkix_crls_validate/3,
pkix_dist_point/1,
@@ -91,7 +93,8 @@
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility
--type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
+-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
+-type digest_type() :: rsa_digest_type() | dss_digest_type() | ecdsa_digest_type().
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
@@ -761,6 +764,76 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
pkix_crls_validate(OtpCert, DPAndCRLs, DPAndCRLs,
Options, pubkey_crl:init_revokation_state()).
+%--------------------------------------------------------------------
+-spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
+ ReferenceIDs :: [{uri_id | dns_id | oid(), string()}]) -> boolean().
+
+-spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
+ ReferenceIDs :: [{uri_id | dns_id | oid(), string()}],
+ Options :: proplists:proplist()) -> boolean().
+
+%% Description: Validates a hostname to RFC 6125
+%%--------------------------------------------------------------------
+pkix_verify_hostname(Cert, ReferenceIDs) ->
+ pkix_verify_hostname(Cert, ReferenceIDs, []).
+
+pkix_verify_hostname(BinCert, ReferenceIDs, Options) when is_binary(BinCert) ->
+ pkix_verify_hostname(pkix_decode_cert(BinCert,otp), ReferenceIDs, Options);
+
+pkix_verify_hostname(Cert = #'OTPCertificate'{tbsCertificate = TbsCert}, ReferenceIDs0, Opts) ->
+ MatchFun = proplists:get_value(match_fun, Opts, undefined),
+ FailCB = proplists:get_value(fail_callback, Opts, fun(_Cert) -> false end),
+ FqdnFun = proplists:get_value(fqdn_fun, Opts, fun verify_hostname_extract_fqdn_default/1),
+
+ ReferenceIDs = [{T,to_string(V)} || {T,V} <- ReferenceIDs0],
+ PresentedIDs =
+ try lists:keyfind(?'id-ce-subjectAltName',
+ #'Extension'.extnID,
+ TbsCert#'OTPTBSCertificate'.extensions)
+ of
+ #'Extension'{extnValue = ExtVals} ->
+ [{T,to_string(V)} || {T,V} <- ExtVals];
+ false ->
+ []
+ catch
+ _:_ -> []
+ end,
+ %% PresentedIDs example: [{dNSName,"ewstest.ericsson.com"}, {dNSName,"www.ericsson.com"}]}
+ case PresentedIDs of
+ [] ->
+ %% Fallback to CN-ids [rfc6125, ch6]
+ case TbsCert#'OTPTBSCertificate'.subject of
+ {rdnSequence,RDNseq} ->
+ PresentedCNs =
+ [{cn, to_string(V)}
+ || ATVs <- RDNseq, % RDNseq is list-of-lists
+ #'AttributeTypeAndValue'{type = ?'id-at-commonName',
+ value = {_T,V}} <- ATVs
+ % _T = kind of string (teletexString etc)
+ ],
+ %% Example of PresentedCNs: [{cn,"www.ericsson.se"}]
+ %% match ReferenceIDs to PresentedCNs
+ verify_hostname_match_loop(verify_hostname_fqnds(ReferenceIDs, FqdnFun),
+ PresentedCNs,
+ MatchFun, FailCB, Cert);
+
+ _ ->
+ false
+ end;
+ _ ->
+ %% match ReferenceIDs to PresentedIDs
+ case verify_hostname_match_loop(ReferenceIDs, PresentedIDs,
+ MatchFun, FailCB, Cert) of
+ false ->
+ %% Try to extract DNS-IDs from URIs etc
+ DNS_ReferenceIDs =
+ [{dns_is,X} || X <- verify_hostname_fqnds(ReferenceIDs, FqdnFun)],
+ verify_hostname_match_loop(DNS_ReferenceIDs, PresentedIDs,
+ MatchFun, FailCB, Cert);
+ true ->
+ true
+ end
+ end.
%%--------------------------------------------------------------------
-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]
@@ -819,6 +892,51 @@ oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>;
oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>.
%%--------------------------------------------------------------------
+-spec ssh_hostkey_fingerprint(public_key()) -> string().
+-spec ssh_hostkey_fingerprint( digest_type(), public_key()) -> string()
+ ; ([digest_type()], public_key()) -> [string()]
+ .
+
+ssh_hostkey_fingerprint(Key) ->
+ sshfp_string(md5, public_key:ssh_encode(Key,ssh2_pubkey) ).
+
+ssh_hostkey_fingerprint(HashAlgs, Key) when is_list(HashAlgs) ->
+ EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
+ [sshfp_full_string(HashAlg,EncKey) || HashAlg <- HashAlgs];
+ssh_hostkey_fingerprint(HashAlg, Key) when is_atom(HashAlg) ->
+ EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
+ sshfp_full_string(HashAlg, EncKey).
+
+
+sshfp_string(HashAlg, EncodedKey) ->
+ %% Other HashAlgs than md5 will be printed with
+ %% other formats than hextstr by
+ %% ssh-keygen -E <alg> -lf <file>
+ fp_fmt(sshfp_fmt(HashAlg), crypto:hash(HashAlg, EncodedKey)).
+
+sshfp_full_string(HashAlg, EncKey) ->
+ lists:concat([sshfp_alg_name(HashAlg),
+ [$: | sshfp_string(HashAlg, EncKey)]
+ ]).
+
+sshfp_alg_name(sha) -> "SHA1";
+sshfp_alg_name(Alg) -> string:to_upper(atom_to_list(Alg)).
+
+sshfp_fmt(md5) -> hexstr;
+sshfp_fmt(_) -> b64.
+
+fp_fmt(hexstr, Bin) ->
+ lists:flatten(string:join([io_lib:format("~2.16.0b",[C1]) || <<C1>> <= Bin], ":"));
+fp_fmt(b64, Bin) ->
+ %% This function clause *seems* to be
+ %% [C || C<-base64:encode_to_string(Bin), C =/= $=]
+ %% but I am not sure. Must be checked.
+ B64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+ BitsInLast = 8*size(Bin) rem 6,
+ Padding = (6-BitsInLast) rem 6, % Want BitsInLast = [1:5] to map to padding [5:1] and 0 -> 0
+ [lists:nth(C+1,B64Chars) || <<C:6>> <= <<Bin/binary,0:Padding>> ].
+
+%%--------------------------------------------------------------------
-spec short_name_hash({rdnSequence, [#'AttributeTypeAndValue'{}]}) ->
string().
@@ -1163,3 +1281,96 @@ ascii_to_lower(String) ->
end)>>
||
<<C>> <= iolist_to_binary(String) >>.
+
+%%%----------------------------------------------------------------
+%%% pkix_verify_hostname help functions
+verify_hostname_extract_fqdn_default({dns_id,S}) ->
+ S;
+verify_hostname_extract_fqdn_default({uri_id,URI}) ->
+ {ok,{https,_,Host,_,_,_}} = http_uri:parse(URI),
+ Host.
+
+
+verify_hostname_fqnds(L, FqdnFun) ->
+ [E || E0 <- L,
+ E <- [try case FqdnFun(E0) of
+ default -> verify_hostname_extract_fqdn_default(E0);
+ undefined -> undefined; % will make the "is_list(E)" test fail
+ Other -> Other
+ end
+ catch _:_-> undefined % will make the "is_list(E)" test fail
+ end],
+ is_list(E),
+ E =/= "",
+ {error,einval} == inet:parse_address(E)
+ ].
+
+
+-define(srvName_OID, {1,3,6,1,4,1,434,2,2,1,37,0}).
+
+verify_hostname_match_default(Ref, Pres) ->
+ verify_hostname_match_default0(to_lower_ascii(Ref), to_lower_ascii(Pres)).
+
+verify_hostname_match_default0(FQDN=[_|_], {cn,FQDN}) ->
+ not lists:member($*, FQDN);
+verify_hostname_match_default0(FQDN=[_|_], {cn,Name=[_|_]}) ->
+ [F1|Fs] = string:tokens(FQDN, "."),
+ [N1|Ns] = string:tokens(Name, "."),
+ match_wild(F1,N1) andalso Fs==Ns;
+verify_hostname_match_default0({dns_id,R}, {dNSName,P}) ->
+ R==P;
+verify_hostname_match_default0({uri_id,R}, {uniformResourceIdentifier,P}) ->
+ R==P;
+verify_hostname_match_default0({srv_id,R}, {T,P}) when T == srvName ;
+ T == ?srvName_OID ->
+ R==P;
+verify_hostname_match_default0(_, _) ->
+ false.
+
+
+match_wild(A, [$*|B]) -> match_wild_suffixes(A, B);
+match_wild([C|A], [ C|B]) -> match_wild(A, B);
+match_wild([], []) -> true;
+match_wild(_, _) -> false.
+
+%% Match the parts after the only wildcard by comparing them from the end
+match_wild_suffixes(A, B) -> match_wild_sfx(lists:reverse(A), lists:reverse(B)).
+
+match_wild_sfx([$*|_], _) -> false; % Bad name (no wildcards alowed)
+match_wild_sfx(_, [$*|_]) -> false; % Bad pattern (no more wildcards alowed)
+match_wild_sfx([A|Ar], [A|Br]) -> match_wild_sfx(Ar, Br);
+match_wild_sfx(Ar, []) -> not lists:member($*, Ar); % Chk for bad name (= wildcards)
+match_wild_sfx(_, _) -> false.
+
+
+verify_hostname_match_loop(Refs0, Pres0, undefined, FailCB, Cert) ->
+ Pres = lists:map(fun to_lower_ascii/1, Pres0),
+ Refs = lists:map(fun to_lower_ascii/1, Refs0),
+ lists:any(
+ fun(R) ->
+ lists:any(fun(P) ->
+ verify_hostname_match_default(R,P) orelse FailCB(Cert)
+ end, Pres)
+ end, Refs);
+verify_hostname_match_loop(Refs, Pres, MatchFun, FailCB, Cert) ->
+ lists:any(
+ fun(R) ->
+ lists:any(fun(P) ->
+ (case MatchFun(R,P) of
+ default -> verify_hostname_match_default(R,P);
+ Bool -> Bool
+ end) orelse FailCB(Cert)
+ end,
+ Pres)
+ end,
+ Refs).
+
+
+to_lower_ascii(S) when is_list(S) -> lists:map(fun to_lower_ascii/1, S);
+to_lower_ascii({T,S}) -> {T, to_lower_ascii(S)};
+to_lower_ascii(C) when $A =< C,C =< $Z -> C + ($a-$A);
+to_lower_ascii(C) -> C.
+
+to_string(S) when is_list(S) -> S;
+to_string(B) when is_binary(B) -> binary_to_list(B).
+
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 004eaefc27..44caf479e5 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -219,7 +219,12 @@ pbes2() ->
pbes2(Config) when is_list(Config) ->
decode_encode_key_file("pbes2_des_cbc_enc_key.pem", "password", "DES-CBC", Config),
decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config),
- decode_encode_key_file("pbes2_rc2_cbc_enc_key.pem", "password", "RC2-CBC", Config).
+ case lists:member(rc2_cbc, proplists:get_value(ciphers, crypto:supports())) of
+ true ->
+ decode_encode_key_file("pbes2_rc2_cbc_enc_key.pem", "password", "RC2-CBC", Config);
+ false ->
+ ok
+ end.
check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
diff --git a/lib/public_key/test/public_key.cover b/lib/public_key/test/public_key.cover
index ec00814578..6c46492bec 100644
--- a/lib/public_key/test/public_key.cover
+++ b/lib/public_key/test/public_key.cover
@@ -1,4 +1,4 @@
{incl_app,public_key,details}.
-{excl_mods, public_key, ['OTP-PUB-KEY']}.
+{excl_mods, public_key, ['OTP-PUB-KEY', 'PKCS-FRAME']}.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index b22b69a0f2..80895ce97c 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,7 +45,18 @@ all() ->
{group, sign_verify},
pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name,
- short_cert_issuer_hash, short_crl_issuer_hash].
+ pkix_verify_hostname_cn,
+ pkix_verify_hostname_subjAltName,
+ pkix_verify_hostname_options,
+ short_cert_issuer_hash, short_crl_issuer_hash,
+ ssh_hostkey_fingerprint_md5_implicit,
+ ssh_hostkey_fingerprint_md5,
+ ssh_hostkey_fingerprint_sha,
+ ssh_hostkey_fingerprint_sha256,
+ ssh_hostkey_fingerprint_sha384,
+ ssh_hostkey_fingerprint_sha512,
+ ssh_hostkey_fingerprint_list
+ ].
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem,
@@ -81,7 +92,26 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
%%-------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
+init_per_testcase(TestCase, Config) ->
+ case TestCase of
+ ssh_hostkey_fingerprint_md5_implicit -> init_fingerprint_testcase([md5], Config);
+ ssh_hostkey_fingerprint_md5 -> init_fingerprint_testcase([md5], Config);
+ ssh_hostkey_fingerprint_sha -> init_fingerprint_testcase([sha], Config);
+ ssh_hostkey_fingerprint_sha256 -> init_fingerprint_testcase([sha256], Config);
+ ssh_hostkey_fingerprint_sha384 -> init_fingerprint_testcase([sha384], Config);
+ ssh_hostkey_fingerprint_sha512 -> init_fingerprint_testcase([sha512], Config);
+ ssh_hostkey_fingerprint_list -> init_fingerprint_testcase([sha,md5], Config);
+ _ -> init_common_per_testcase(Config)
+ end.
+
+init_fingerprint_testcase(Algs, Config) ->
+ Hashs = proplists:get_value(hashs, crypto:supports(), []),
+ case Algs -- Hashs of
+ [] -> init_common_per_testcase(Config);
+ UnsupportedAlgs -> {skip,{UnsupportedAlgs,not_supported}}
+ end.
+
+init_common_per_testcase(Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -89,6 +119,7 @@ init_per_testcase(_TestCase, Config0) ->
end_per_testcase(_TestCase, _Config) ->
ok.
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -529,6 +560,56 @@ ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
%%--------------------------------------------------------------------
+%% Check of different host keys left to later
+ssh_hostkey_fingerprint_md5_implicit(_Config) ->
+ Expected = "4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
+ Expected = public_key:ssh_hostkey_fingerprint(ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Check of different host keys left to later
+ssh_hostkey_fingerprint_md5(_Config) ->
+ Expected = "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
+ Expected = public_key:ssh_hostkey_fingerprint(md5, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead. The Expected is generated with:
+%% $ openssh-7.3p1/ssh-keygen -E sha1 -lf <file>
+%% 2048 SHA1:Soammnaqg06jrm2jivMSnzQGlmk [email protected] (RSA)
+ssh_hostkey_fingerprint_sha(_Config) ->
+ Expected = "SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
+ Expected = public_key:ssh_hostkey_fingerprint(sha, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha256(_Config) ->
+ Expected = "SHA256:T7F1BahkJWR7iJO8+rpzWOPbp7LZP4MlNrDExdNYOvY",
+ Expected = public_key:ssh_hostkey_fingerprint(sha256, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha384(_Config) ->
+ Expected = "SHA384:QhkLoGNI4KXdPvC//HxxSCP3uTQVADqxdajbgm+Gkx9zqz8N94HyP1JmH8C4/aEl",
+ Expected = public_key:ssh_hostkey_fingerprint(sha384, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha512(_Config) ->
+ Expected = "SHA512:ezUismvm3ADQQb6Nm0c1DwQ6ydInlJNfsnSQejFkXNmABg1Aenk9oi45CXeBOoTnlfTsGG8nFDm0smP10PBEeA",
+ Expected = public_key:ssh_hostkey_fingerprint(sha512, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_list(_Config) ->
+ Expected = ["SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
+ "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a"],
+ Expected = public_key:ssh_hostkey_fingerprint([sha,md5], ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
encrypt_decrypt() ->
[{doc, "Test public_key:encrypt_private and public_key:decrypt_public"}].
encrypt_decrypt(Config) when is_list(Config) ->
@@ -746,6 +827,114 @@ pkix_path_validation(Config) when is_list(Config) ->
ok.
%%--------------------------------------------------------------------
+%% To generate the PEM file contents:
+%%
+%% openssl req -x509 -nodes -newkey rsa:1024 -keyout /dev/null -subj '/C=SE/CN=example.com/CN=*.foo.example.com/CN=a*b.bar.example.com/O=erlang.org' > public_key_SUITE_data/pkix_verify_hostname_cn.pem
+%%
+%% Note that the same pem-file is used in pkix_verify_hostname_options/1
+%%
+%% Subject: C=SE, CN=example.com, CN=*.foo.example.com, CN=a*b.bar.example.com, O=erlang.org
+%% extensions = no subjAltName
+
+pkix_verify_hostname_cn(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ {ok,Bin} = file:read_file(filename:join(DataDir,"pkix_verify_hostname_cn.pem")),
+ Cert = public_key:pkix_decode_cert(element(2,hd(public_key:pem_decode(Bin))), otp),
+
+ %% Check that 1) only CNs are checked,
+ %% 2) an empty label does not match a wildcard and
+ %% 3) a wildcard does not match more than one label
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"erlang.org"},
+ {dns_id,"foo.EXAMPLE.com"},
+ {dns_id,"b.a.foo.EXAMPLE.com"}]),
+
+ %% Check that a hostname is extracted from a https-uri and used for checking:
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"HTTPS://EXAMPLE.com"}]),
+
+ %% Check wildcard matching one label:
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"a.foo.EXAMPLE.com"}]),
+
+ %% Check wildcard with surrounding chars matches one label:
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"accb.bar.EXAMPLE.com"}]),
+
+ %% Check that a wildcard with surrounding chars matches an empty string:
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://ab.bar.EXAMPLE.com"}]).
+
+%%--------------------------------------------------------------------
+%% To generate the PEM file contents:
+%%
+%% openssl req -x509 -nodes -newkey rsa:1024 -keyout /dev/null -extensions SAN -config public_key_SUITE_data/verify_hostname.conf 2>/dev/null > public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
+%%
+%% Subject: C=SE, CN=example.com
+%% Subject Alternative Name: DNS:kb.example.org, URI:http://www.example.org, URI:https://wws.example.org
+
+pkix_verify_hostname_subjAltName(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ {ok,Bin} = file:read_file(filename:join(DataDir,"pkix_verify_hostname_subjAltName.pem")),
+ Cert = public_key:pkix_decode_cert(element(2,hd(public_key:pem_decode(Bin))), otp),
+
+ %% Check that neither a uri nor dns hostname matches a CN if subjAltName is present:
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://example.com"},
+ {dns_id,"example.com"}]),
+
+ %% Check that a uri_id matches a URI subjAltName:
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://wws.example.org"}]),
+
+ %% Check that a dns_id does not match a URI subjAltName:
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"www.example.org"},
+ {dns_id,"wws.example.org"}]),
+
+ %% Check that a dns_id matches a DNS subjAltName:
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"kb.example.org"}]).
+
+%%--------------------------------------------------------------------
+%% Uses the pem-file for pkix_verify_hostname_cn
+%% Subject: C=SE, CN=example.com, CN=*.foo.example.com, CN=a*b.bar.example.com, O=erlang.org
+pkix_verify_hostname_options(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ {ok,Bin} = file:read_file(filename:join(DataDir,"pkix_verify_hostname_cn.pem")),
+ Cert = public_key:pkix_decode_cert(element(2,hd(public_key:pem_decode(Bin))), otp),
+
+ %% Check that the fail_callback is called and is presented the correct certificate:
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"erlang.org"}],
+ [{fail_callback,
+ fun(#'OTPCertificate'{}=C) when C==Cert ->
+ true; % To test the return value matters
+ (#'OTPCertificate'{}=C) ->
+ ct:log("~p:~p: Wrong cert:~n~p~nExpect~n~p",
+ [?MODULE, ?LINE, C, Cert]),
+ ct:fail("Wrong cert, see log");
+ (C) ->
+ ct:log("~p:~p: Bad cert: ~p",[?MODULE,?LINE,C]),
+ ct:fail("Bad cert, see log")
+ end}]),
+
+ %% Check the callback for user-provided match functions:
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"very.wrong.domain"}],
+ [{match_fun,
+ fun("very.wrong.domain", {cn,"example.com"}) ->
+ true;
+ (_, _) ->
+ false
+ end}]),
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"not.example.com"}],
+ [{match_fun, fun(_, _) -> default end}]),
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"example.com"}],
+ [{match_fun, fun(_, _) -> default end}]),
+
+ %% Check the callback for user-provided fqdn extraction:
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}],
+ [{fqdn_fun,
+ fun({uri_id, "some://very.wrong.domain"}) ->
+ "example.com";
+ (_) ->
+ ""
+ end}]),
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://example.com"}],
+ [{fqdn_fun, fun(_) -> default end}]),
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}]).
+
+%%--------------------------------------------------------------------
pkix_iso_rsa_oid() ->
[{doc, "Test workaround for supporting certs that use ISO oids"
" 1.3.14.3.2.29 instead of PKIX/PKCS oid"}].
@@ -929,3 +1118,13 @@ incorrect_countryname_pkix_cert() ->
incorrect_emailaddress_pkix_cert() ->
<<48,130,3,74,48,130,2,50,2,9,0,133,49,203,25,198,156,252,230,48,13,6,9,42,134, 72,134,247,13,1,1,5,5,0,48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17, 6,3,85,4,8,12,10,83,111,109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10, 12,24,73,110,116,101,114,110,101,116,32,87,105,100,103,105,116,115,32,80,116, 121,32,76,116,100,49,32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110, 118,97,108,105,100,64,101,109,97,105,108,46,99,111,109,48,30,23,13,49,51,49, 49,48,55,50,48,53,54,49,56,90,23,13,49,52,49,49,48,55,50,48,53,54,49,56,90, 48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17,6,3,85,4,8,12,10,83,111, 109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10,12,24,73,110,116,101, 114,110,101,116,32,87,105,100,103,105,116,115,32,80,116,121,32,76,116,100,49, 32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110,118,97,108,105,100,64, 101,109,97,105,108,46,99,111,109,48,130,1,34,48,13,6,9,42,134,72,134,247,13, 1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,190,243,49,213,219,60,232,105, 1,127,126,9,130,15,60,190,78,100,148,235,246,223,21,91,238,200,251,84,55,212, 78,32,120,61,85,172,0,144,248,5,165,29,143,79,64,178,51,153,203,76,115,238, 192,49,173,37,121,203,89,62,157,13,181,166,30,112,154,40,202,140,104,211,157, 73,244,9,78,236,70,153,195,158,233,141,42,238,2,143,160,225,249,27,30,140, 151,176,43,211,87,114,164,108,69,47,39,195,123,185,179,219,28,218,122,53,83, 77,48,81,184,14,91,243,12,62,146,86,210,248,228,171,146,225,87,51,146,155, 116,112,238,212,36,111,58,41,67,27,6,61,61,3,84,150,126,214,121,57,38,12,87, 121,67,244,37,45,145,234,131,115,134,58,194,5,36,166,52,59,229,32,47,152,80, 237,190,58,182,248,98,7,165,198,211,5,31,231,152,116,31,108,71,218,64,188, 178,143,27,167,79,15,112,196,103,116,212,65,197,94,37,4,132,103,91,217,73, 223,207,185,7,153,221,240,232,31,44,102,108,82,83,56,242,210,214,74,71,246, 177,217,148,227,220,230,4,176,226,74,194,37,2,3,1,0,1,48,13,6,9,42,134,72, 134,247,13,1,1,5,5,0,3,130,1,1,0,89,247,141,154,173,123,123,203,143,85,28,79, 73,37,164,6,17,89,171,224,149,22,134,17,198,146,158,192,241,41,253,58,230, 133,71,189,43,66,123,88,15,242,119,227,249,99,137,61,200,54,161,0,177,167, 169,114,80,148,90,22,97,78,162,181,75,93,209,116,245,46,81,232,64,157,93,136, 52,57,229,113,197,218,113,93,42,161,213,104,205,137,30,144,183,58,10,98,47, 227,177,96,40,233,98,150,209,217,68,22,221,133,27,161,152,237,46,36,179,59, 172,97,134,194,205,101,137,71,192,57,153,20,114,27,173,233,166,45,56,0,61, 205,45,202,139,7,132,103,248,193,157,184,123,43,62,172,236,110,49,62,209,78, 249,83,219,133,1,213,143,73,174,16,113,143,189,41,84,60,128,222,30,177,104, 134,220,52,239,171,76,59,176,36,113,176,214,118,16,44,235,21,167,199,216,200, 76,219,142,248,13,70,145,205,216,230,226,148,97,223,216,179,68,209,222,63, 140,137,24,164,192,149,194,79,119,247,75,159,49,116,70,241,70,116,11,40,119, 176,157,36,160,102,140,255,34,248,25,231,136,59>>.
+
+
+
+ssh_hostkey(rsa) ->
+ [{PKdecoded,_}] =
+ public_key:ssh_decode(
+ <<"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYXcYmsyJBstl4EfFYzfQJmSiUE162zvSGSoMYybShYOI6rnnyvvihfw8Aml+2gZ716F2tqG48FQ/yPZEGWNPMrCejPpJctaPWhpNdNMJ8KFXSEgr5bY2mEpa19DHmuDeXKzeJJ+X7s3fVdYc4FMk5731KIW6Huf019ZnTxbx0VKG6b1KAJBg3vpNsDxEMwQ4LFMB0JHVklOTzbxmpaeULuIxvl65A+eGeFVeo2Q+YI9UnwY1vSgmc9Azwy8Ie9Z0HpQBN5I7Uc5xnknT8V6xDhgNfXEfzsgsRdDfZLECt1WO/1gP9wkosvAGZWt5oG8pbNQWiQdFq536ck8WQD9WD [email protected]">>,
+ public_key),
+ PKdecoded.
+
diff --git a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_cn.pem b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_cn.pem
new file mode 100644
index 0000000000..9f7b428f9a
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_cn.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsjCCAhugAwIBAgIJAMCGx1ezaJFRMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNV
+BAYTAlNFMRQwEgYDVQQDDAtleGFtcGxlLmNvbTEaMBgGA1UEAwwRKi5mb28uZXhh
+bXBsZS5jb20xHDAaBgNVBAMME2EqYi5iYXIuZXhhbXBsZS5jb20xEzARBgNVBAoM
+CmVybGFuZy5vcmcwHhcNMTYxMjIwMTUwNDUyWhcNMTcwMTE5MTUwNDUyWjByMQsw
+CQYDVQQGEwJTRTEUMBIGA1UEAwwLZXhhbXBsZS5jb20xGjAYBgNVBAMMESouZm9v
+LmV4YW1wbGUuY29tMRwwGgYDVQQDDBNhKmIuYmFyLmV4YW1wbGUuY29tMRMwEQYD
+VQQKDAplcmxhbmcub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGJgZ
+defGucvMXf0RrEm6Hb18IfVUo9IV6swSP/kwAu/608ZIZdzlfp2pxC0e72a4E3WN
+4vrGxAr2wMMQOiyoy4qlAeLX27THJ6Q4Vl82fc6QuOJbScKIydSZ4KoB+luGlBu5
+b6xYh2pBbneKFpsecmK5rsWtTactjD4n1tKjUwIDAQABo1AwTjAdBgNVHQ4EFgQU
+OCtzidUeaDva7qp12T0CQrgfLW4wHwYDVR0jBBgwFoAUOCtzidUeaDva7qp12T0C
+QrgfLW4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCAz+ComCMo9Qbu
+PHxG7pv3mQvoxrMFva/Asg4o9mW2mDyrk0DwI4zU8vMHbSRKSBYGm4TATXsQkDQT
+gJw/bxhISnhZZtPC7Yup8kJCkJ6S6EDLYrlzgsRqfeU6jWim3nbfaLyMi9dHFDMk
+HULnyNNW3qxTEKi8Wo2sCMej4l7KFg==
+-----END CERTIFICATE-----
diff --git a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
new file mode 100644
index 0000000000..83e1ad37b3
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICEjCCAXugAwIBAgIJANwliLph5EiAMA0GCSqGSIb3DQEBCwUAMCMxCzAJBgNV
+BAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNjEyMjAxNTEyMjRaFw0x
+NzAxMTkxNTEyMjRaMCMxCzAJBgNVBAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAydstIN157w8QxkVaOl3wm81j
+fgZ8gqO3BXkECPF6bw5ewLlmePL6Qs4RypsaRe7cKJ9rHFlwhpdcYkxWSWEt2N7Z
+Ry3N4SjuU04ohWbYgy3ijTt7bJg7jOV1Dh56BnI4hwhQj0oNFizNZOeRRfEzdMnS
++uk03t/Qre2NS7KbwnUCAwEAAaNOMEwwSgYDVR0RBEMwQYIOa2IuZXhhbXBsZS5v
+cmeGFmh0dHA6Ly93d3cuZXhhbXBsZS5vcmeGF2h0dHBzOi8vd3dzLmV4YW1wbGUu
+b3JnMA0GCSqGSIb3DQEBCwUAA4GBAKqFqW5gCso422bXriCBJoygokOTTOw1Rzpq
+K8Mm0B8W9rrW9OTkoLEcjekllZcUCZFin2HovHC5HlHZz+mQvBI1M6sN2HVQbSzS
+EgL66U9gwJVnn9/U1hXhJ0LO28aGbyE29DxnewNR741dWN3oFxCdlNaO6eMWaEsO
+gduJ5sDl
+-----END CERTIFICATE-----
diff --git a/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf b/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
new file mode 100644
index 0000000000..a28864dc78
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
@@ -0,0 +1,16 @@
+[req]
+prompt = no
+distinguished_name = DN
+
+[DN]
+C=SE
+CN=example.com
+
+[SAN]
+subjectAltName = @alt_names
+
+[alt_names]
+DNS = kb.example.org
+URI.1 = http://www.example.org
+URI.2 = https://wws.example.org
+
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 84f6a659b5..b94768ae77 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.2
+PUBLIC_KEY_VSN = 1.4
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index 6df4924d0a..b47d451055 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -38,7 +38,53 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
- <section><title>Reltool 0.7.1</title>
+ <section><title>Reltool 0.7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Dependencies specified in .app files would earlier only
+ be followed for applications that are included in a 'rel'
+ spec in the reltool config. For other applications, only
+ xref would decide the dependencies.</p>
+ <p>
+ Some dependency chains would even be missed for
+ applications that are included in a 'rel' spec in the
+ reltool config. E.g.</p>
+
+ <list> <item>Application x has y as included application,
+ and y in turn has z as included application. Then z is
+ not included. </item> <item>Application x has y in its
+ 'applications' tag in the .app file, and y in turn has z
+ as included application. Then z is not included.</item>
+ </list>
+ <p>
+ These bugs are now corrected.</p>
+ <p>
+ Own Id: OTP-11993</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.1</title>
<section><title>Improvements and New Features</title>
<list>
@@ -546,8 +592,8 @@
<p>The handling of applications included in releases has
been improved. Applications that are required to be
started before other applications in a release are now
- automatically included in the release. The <c>kernel</c>
- and <c>stdlib</c> applications are always included as
+ automatically included in the release. The Kernel
+ and STDLIB applications are always included as
they are mandatory.</p>
<p>Applications that are (explicitly or implicitly)
included in a release are now automatically included as
diff --git a/lib/reltool/doc/src/part.xml b/lib/reltool/doc/src/part.xml
index 5904084879..e608d548ea 100644
--- a/lib/reltool/doc/src/part.xml
+++ b/lib/reltool/doc/src/part.xml
@@ -31,7 +31,7 @@
<rev>%VSN%</rev>
</header>
<description>
- <p><c>Reltool</c> is a release management tool. It analyses a given
+ <p>Reltool is a release management tool. It analyses a given
Erlang/OTP installation and determines various dependencies
between applications. The <c>graphical</c> frontend depicts the
dependencies and enables interactive customization of a
diff --git a/lib/reltool/doc/src/ref_man.xml b/lib/reltool/doc/src/ref_man.xml
index 38f270b79a..1684f075ff 100644
--- a/lib/reltool/doc/src/ref_man.xml
+++ b/lib/reltool/doc/src/ref_man.xml
@@ -31,7 +31,7 @@
<rev>%VSN%</rev>
</header>
<description>
- <p><c>Reltool</c> is a release management tool. It analyses a given
+ <p>Reltool is a release management tool. It analyses a given
Erlang/OTP installation and determines various dependencies
between applications. The <c>graphical</c> frontend depicts the
dependencies and enables interactive customization of a
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 38448e7961..5bfbee966b 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -47,7 +47,7 @@
<p>The tool uses an installed Erlang/OTP system as input.
<c>root_dir</c> is the root directory of the analysed system and
- it defaults to the system executing <c>reltool</c>. Applications
+ it defaults to the system executing Reltool. Applications
may also be located outside <c>root_dir</c>. <c>lib_dirs</c>
defines library directories where additional applications
may reside and it defaults to the directories
@@ -56,7 +56,7 @@
<p>An application directory <c>AppDir</c> under a library
directory is recognized by the existence of an <c>AppDir/ebin</c>
- directory. If this does not exist, <c>reltool</c> will not
+ directory. If this does not exist, Reltool will not
consider <c>AppDir</c> at all when looking for applications.</p>
<p>It is recommended that application directories are named as the
@@ -81,14 +81,14 @@
<tag><c>config</c></tag>
<item>
<p>This is the main option and it controls the configuration
- of <c>reltool</c>. It can either be a <c>sys</c> tuple or
+ of Reltool. It can either be a <c>sys</c> tuple or
a name of a <c>file</c> containing a sys tuple.</p>
</item>
<tag><c>trap_exit</c></tag>
<item>
<p>This option controls the error handling behavior of
- <c>reltool</c>. By default the window processes traps
+ Reltool. By default the window processes traps
exit, but this behavior can altered by setting
<c>trap_exit</c> to <c>false</c>.</p>
</item>
diff --git a/lib/reltool/doc/src/reltool_intro.xml b/lib/reltool/doc/src/reltool_intro.xml
index 8e232b8838..2980ad7977 100644
--- a/lib/reltool/doc/src/reltool_intro.xml
+++ b/lib/reltool/doc/src/reltool_intro.xml
@@ -34,7 +34,7 @@
<rev>%VSN%</rev>
<file>reltool_intro.xml</file>
</header>
- <p><c>Reltool</c> is a release management tool. It analyses a given
+ <p>Reltool is a release management tool. It analyses a given
Erlang/OTP installation and determines various dependencies between
applications. The <c>graphical</c> frontend depicts the dependencies and
enables interactive customization of a target system. The backend provides a
@@ -82,7 +82,7 @@
and about the Erlang/OTP development system:</p>
<list type="bulleted">
<item>
- <p>the Reference Manual of <c>Reltool</c></p>
+ <p>the Reference Manual of Reltool</p>
</item>
<item>
<p>the Erlang/OTP <c>System Principles</c></p>
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 9ac22b9450..3b1e868757 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -154,19 +154,19 @@
-record(app_info,
{
- description = "" :: string(),
- id = "" :: string(),
- vsn = "" :: app_vsn(),
- modules = [] :: [mod_name()],
- maxP = infinity :: integer() | infinity,
- maxT = infinity :: integer() | infinity,
- registered = [] :: [atom()],
- incl_apps = [] :: [app_name()],
- applications = [] :: [app_name()],
- env = [] :: [{atom(), term()}],
- mod = undefined :: {mod_name(), [term()]} | undefined,
- start_phases = undefined :: [{atom(), term()}] | undefined,
- runtime_dependencies = [] :: [string()]
+ description = "" :: '_' | string(),
+ id = "" :: '_' | string(),
+ vsn = "" :: '_' | app_vsn(),
+ modules = [] :: '_' | [mod_name()],
+ maxP = infinity :: '_' | integer() | infinity,
+ maxT = infinity :: '_' | integer() | infinity,
+ registered = [] :: '_' | [atom()],
+ incl_apps = [] :: '_' | '$3' | [app_name()],
+ applications = [] :: '_' | '$2' | [app_name()],
+ env = [] :: '_' | [{atom(), term()}],
+ mod = undefined :: '_' | {mod_name(), [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 21a4485f94..89e90670cf 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -530,9 +530,14 @@ analyse(#state{sys=Sys} = S, Apps, Status) ->
%% Write all #app to app_tab and all #mod to mod_tab.
Status2 = apps_init_is_included(S, Apps, RelApps, Status),
+ %% For each application that is not (directly or indirectly) part
+ %% of a release, but still has #app.is_included==true, propagate
+ %% is_included to the dependencies specified in the .app files.
+ app_propagate_is_included(S),
+
%% For each module that has #mod.is_included==true, propagate
%% is_included to the modules it uses.
- propagate_is_included(S),
+ mod_propagate_is_included(S),
%% Insert reverse dependencies - i.e. for each
%% #mod{name=Mod, uses_mods=[UsedMod]},
@@ -565,31 +570,34 @@ apps_in_rels(Rels, Apps) ->
apps_in_rel(#rel{name = RelName, rel_apps = RelApps}, Apps) ->
Mandatory = [{RelName, kernel}, {RelName, stdlib}],
- Other =
+ Explicit0 = [{RelName, AppName} || #rel_app{name=AppName} <- RelApps],
+ Explicit = Mandatory ++ Explicit0,
+ Deps =
[{RelName, AppName} ||
RA <- RelApps,
- AppName <- [RA#rel_app.name |
+ AppName <-
+ case lists:keyfind(RA#rel_app.name,
+ #app.name,
+ Apps) of
+ App=#app{info = #app_info{applications = AA}} ->
%% Included applications in rel shall overwrite included
%% applications in .app. I.e. included applications in
%% .app shall only be used if it is not defined in rel.
- case RA#rel_app.incl_apps of
- undefined ->
- case lists:keyfind(RA#rel_app.name,
- #app.name,
- Apps) of
- #app{info = #app_info{incl_apps = IA}} ->
- IA;
- false ->
- reltool_utils:throw_error(
- "Release ~tp uses non existing "
- "application ~w",
- [RelName,RA#rel_app.name])
- end;
- IA ->
- IA
- end],
- not lists:keymember(AppName, 2, Mandatory)],
- more_apps_in_rels(Mandatory ++ Other, Apps, []).
+ IA = case RA#rel_app.incl_apps of
+ undefined ->
+ (App#app.info)#app_info.incl_apps;
+ RelIA ->
+ RelIA
+ end,
+ AA ++ IA;
+ false ->
+ reltool_utils:throw_error(
+ "Release ~tp uses non existing "
+ "application ~w",
+ [RelName,RA#rel_app.name])
+ end,
+ not lists:keymember(AppName, 2, Explicit)],
+ more_apps_in_rels(Deps, Apps, Explicit).
more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) ->
case lists:member(RA, Acc) of
@@ -597,8 +605,8 @@ more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) ->
more_apps_in_rels(RelApps, Apps, Acc);
false ->
case lists:keyfind(AppName, #app.name, Apps) of
- #app{info = #app_info{applications = InfoApps}} ->
- Extra = [{RelName, N} || N <- InfoApps],
+ #app{info = #app_info{applications = AA, incl_apps=IA}} ->
+ Extra = [{RelName, N} || N <- AA++IA],
Acc2 = more_apps_in_rels(Extra, Apps, [RA | Acc]),
more_apps_in_rels(RelApps, Apps, Acc2);
false ->
@@ -610,7 +618,6 @@ more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc) ->
more_apps_in_rels([], _Apps, Acc) ->
Acc.
-
apps_init_is_included(S, Apps, RelApps, Status) ->
lists:foldl(fun(App, AccStatus) ->
app_init_is_included(S, App, RelApps, AccStatus)
@@ -745,6 +752,100 @@ false_to_undefined(Bool) ->
_ -> Bool
end.
+get_no_rel_apps_and_dependencies(S) ->
+ ets:select(S#state.app_tab, [{#app{name='$1',
+ is_included=true,
+ info=#app_info{applications='$2',
+ incl_apps='$3',
+ _='_'},
+ rels=[],
+ _='_'},
+ [],
+ [{{'$1','$2','$3'}}]}]).
+
+app_propagate_is_included(S) ->
+ lists:foreach(
+ fun({AppName,DepNames1,DepNames2}) ->
+ app_mark_is_included(S,AppName,DepNames1++DepNames2)
+ end,
+ get_no_rel_apps_and_dependencies(S)).
+
+app_mark_is_included(#state{app_tab=AppTab, mod_tab=ModTab, sys=Sys}=S,UsedByName,[AppName|AppNames]) ->
+ case ets:lookup(AppTab, AppName) of
+ [A] ->
+ case A#app.is_included of
+ undefined ->
+ %% Not yet marked => mark and propagate
+ A2 =
+ case A#app.incl_cond of
+ include ->
+ A#app{is_pre_included = true,
+ is_included = true};
+ exclude ->
+ A#app{is_pre_included = false,
+ is_included = false};
+ AppInclCond when AppInclCond==undefined;
+ AppInclCond==derived ->
+ A#app{is_included = true}
+ end,
+ ets:insert(AppTab, A2),
+
+ ModCond =
+ case A#app.mod_cond of
+ undefined -> Sys#sys.mod_cond;
+ _ -> A#app.mod_cond
+ end,
+ Filter =
+ fun(M) ->
+ case ModCond of
+ all -> true;
+ app -> M#mod.is_app_mod;
+ ebin -> M#mod.is_ebin_mod;
+ derived -> false;
+ none -> false
+ end
+ end,
+ Mods = lists:filter(Filter, A#app.mods),
+ %% Mark the modules of this app, but no need to go
+ %% recursive on modules since this is done in
+ %% mod_mark_is_included.
+ [case M#mod.is_included of
+ undefined ->
+ M2 =
+ case M#mod.incl_cond of
+ include ->
+ M#mod{is_pre_included = true,
+ is_included = true};
+ exclude ->
+ M#mod{is_pre_included = false,
+ is_included = false};
+ ModInclCond when ModInclCond==undefined;
+ ModInclCond==derived ->
+ M#mod{is_included = true}
+ end,
+ ets:insert(ModTab, M2);
+ _ ->
+ ok
+ end || M <- Mods],
+
+ %% Go recursive on dependencies
+ #app{info=#app_info{applications=DepNames1,
+ incl_apps=DepNames2}} = A,
+ app_mark_is_included(S,AppName,DepNames1++DepNames2);
+ _ ->
+ %% Already marked
+ ok
+ end;
+ [] ->
+ %% Missing app
+ reltool_utils:throw_error(
+ "Application ~tp uses non existing application ~w",
+ [UsedByName,AppName])
+ end,
+ app_mark_is_included(S, UsedByName, AppNames);
+app_mark_is_included(_S, _UsedByName, []) ->
+ ok.
+
%% Return the list for {ModName, UsesModNames} for all modules where
%% #mod.is_included==true.
get_all_mods_and_dependencies(S) ->
@@ -755,7 +856,7 @@ get_all_mods_and_dependencies(S) ->
[],
[{{'$1','$2'}}]}]).
-propagate_is_included(S) ->
+mod_propagate_is_included(S) ->
case lists:flatmap(
fun({ModName,UsesModNames}) ->
mod_mark_is_included(S,ModName,UsesModNames,[])
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index e9bd46fb27..e8dfea94da 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -142,6 +142,7 @@ all() ->
save_config,
dependencies,
mod_incl_cond_derived,
+ dep_in_app_not_xref,
use_selected_vsn,
use_selected_vsn_relative_path,
non_standard_vsn_id,
@@ -408,7 +409,6 @@ create_release_sort(Config) ->
{app,tools,[{mod_cond,app},{incl_cond,include}]}
]},
%% Generate release
-
?msym({ok, {release, {RelName1, RelVsn},
{erts, _},
[{kernel, _},
@@ -2304,6 +2304,7 @@ dependencies(Config) ->
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test that incl_cond on mod level overwrites mod_cond on app level
%% Uses same test applications as dependencies/1 above
mod_incl_cond_derived(Config) ->
@@ -2346,6 +2347,40 @@ mod_incl_cond_derived(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ERL-167, OTP-11993: For applications that are not included in a
+%% release spec ('rel'), dependencies in the .app files are not
+%% considered - only those found with xref.
+dep_in_app_not_xref(Config) ->
+ RelName = "Just testing...",
+ RelVsn = "1.0",
+ Sys =
+ {sys,
+ [
+ {lib_dirs,[filename:join(datadir(Config),"dep_in_app_not_xref")]},
+ {incl_cond,exclude},
+ {incl_archive_filters,[]},
+ {erts,[{incl_cond,exclude}]},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [kernel, stdlib]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,x,[{incl_cond,include}]},
+ {app,y,[{incl_cond,derived}]},
+ {app,z,[{incl_cond,derived}]}
+ ]},
+
+ TargetDir = filename:join([?WORK_DIR, "target_dep_in_app_not_xref"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
+ ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
+ ?log("~p~n",[file:list_dir(filename:join([TargetDir,"lib"]))]),
+
+ ?m(true, filelib:is_dir(filename:join([TargetDir,"lib","y-1.0"]))),
+ ?m(true, filelib:is_dir(filename:join([TargetDir,"lib","z-1.0"]))),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
use_selected_vsn(Config) ->
LibDir1 = filename:join(datadir(Config),"use_selected_vsn"),
B1Dir = filename:join(LibDir1,"b-1.0"),
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app
new file mode 100644
index 0000000000..fe922e3a41
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/ebin/x.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, x,
+ [{description, "Main application in reltool dependency test"},
+ {vsn, "1.0"},
+ {modules, [x1]},
+ {registered, []},
+ {applications, [kernel, stdlib, y]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl
new file mode 100644
index 0000000000..bf1e7f9279
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/x-1.0/src/x1.erl
@@ -0,0 +1,5 @@
+-module(x1).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app
new file mode 100644
index 0000000000..a21cfe6c21
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/ebin/y.app
@@ -0,0 +1,8 @@
+% -*-erlang-*-
+{application, y,
+ [{description, "Library application in reltool dependency test"},
+ {vsn, "1.0"},
+ {modules, [y1]},
+ {registered, []},
+ {applications, [kernel, stdlib]},
+ {included_applications, [z]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl
new file mode 100644
index 0000000000..902a7e21f3
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/y-1.0/src/y1.erl
@@ -0,0 +1,5 @@
+-module(y1).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app
new file mode 100644
index 0000000000..437a0968e9
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/ebin/z.app
@@ -0,0 +1,7 @@
+% -*-erlang-*-
+{application, z,
+ [{description, "Library application in reltool dependency test"},
+ {vsn, "1.0"},
+ {modules, [z1]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl
new file mode 100644
index 0000000000..97ef90b87f
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE_data/dep_in_app_not_xref/z-1.0/src/z1.erl
@@ -0,0 +1,5 @@
+-module(z1).
+-compile(export_all).
+
+f() ->
+ ok.
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 76f69fd294..2d07eeb8f0 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.7.1
+RELTOOL_VSN = 0.7.3
diff --git a/lib/runtime_tools/doc/src/LTTng.xml b/lib/runtime_tools/doc/src/LTTng.xml
index 82a4c79379..392d54857c 100644
--- a/lib/runtime_tools/doc/src/LTTng.xml
+++ b/lib/runtime_tools/doc/src/LTTng.xml
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="utf8" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2016</year><year>2016</year>
+ <year>2016</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index 14a81b2293..95f74d4607 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -78,7 +78,7 @@
<p>Pseudo function that by means of a <c>parse_transform</c>
translates the <em>literal</em><c>fun()</c> typed as parameter in
the function call to a match specification as described in
- the <c>match_spec</c> manual of <c>ERTS</c> users guide.
+ the <c>match_spec</c> manual of ERTS users guide.
(with literal I mean that the <c>fun()</c> needs to
textually be written as the parameter of the function, it
cannot be held in a variable which in turn is passed to the
@@ -954,7 +954,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
as the tuple <c>{drop, N}</c> where <c>N</c> is the number of consecutive messages
dropped. In case of heavy tracing, drop's are likely to occur,
and they surely occur if no client is reading the trace
- messages.</p>
+ messages. The default value of <c>QueSize</c> is 200.</p>
</desc>
</func>
<func>
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 6bec7cb9ca..0eafc437cc 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -32,6 +32,65 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.11.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ etop erroneously reported the average scheduler
+ utilization since the tool was first started instead of
+ the scheduler utilization since last update. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-14090 Aux Id: seq13232 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Runtime_Tools 1.11</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add option <c>queue_size</c> to ttb:tracer/2. This sets
+ the maximum queue size for the IP trace driver which is
+ used when tracing to shell and/or <c>{local,File}</c>.</p>
+ <p>
+ The default value for <c>queue_size</c> is specified by
+ <c>dbg</c>, and it is now changed from 50 to 200.</p>
+ <p>
+ Own Id: OTP-13829 Aux Id: seq13171 </p>
+ </item>
+ <item>
+ <p>
+ The port information page is updated to show more
+ information per port.</p>
+ <p>
+ Own Id: OTP-13948 Aux Id: ERL-272 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Runtime_Tools 1.10.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Correct some minor documentation issues. </p>
+ <p>
+ Own Id: OTP-13891</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -668,7 +727,7 @@
also been extended. </item><item> The <c>configure</c>
scripts of <c>erl_interface</c> and <c>odbc</c> now
search for thread libraries and thread library quirks the
- same way as <c>erts</c> do. </item><item> The
+ same way as ERTS do. </item><item> The
<c>configure</c> script of the <c>odbc</c> application
now also looks for odbc libraries in <c>lib64</c> and
<c>lib/64</c> directories when building on a 64-bit
diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl
index c0d4665bda..f17aa528ed 100644
--- a/lib/runtime_tools/src/dbg.erl
+++ b/lib/runtime_tools/src/dbg.erl
@@ -427,7 +427,7 @@ trace_port(file, Filename) ->
trace_port1(file, Filename, nowrap);
trace_port(ip, Portno) when is_integer(Portno) ->
- trace_port(ip,{Portno,50});
+ trace_port(ip,{Portno,200});
trace_port(ip, {Portno, Qsiz}) when is_integer(Portno), is_integer(Qsiz) ->
fun() ->
diff --git a/lib/runtime_tools/src/msacc.erl b/lib/runtime_tools/src/msacc.erl
index 4db5dbec91..0d9b2690e5 100644
--- a/lib/runtime_tools/src/msacc.erl
+++ b/lib/runtime_tools/src/msacc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index cedb677178..b27bc63d15 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -141,14 +141,59 @@ get_mnesia_loop(Parent, {Match, Cont}) ->
get_mnesia_loop(Parent, mnesia:select(Cont)).
get_port_list() ->
+ ExtraItems = [monitors,monitored_by,parallelism,locking,queue_size,memory],
[begin
[{port_id,P}|erlang:port_info(P)] ++
- case erlang:port_info(P,monitors) of
- undefined -> [];
- Monitors -> [Monitors]
- end
+ port_info(P,ExtraItems) ++
+ inet_port_extra(erlang:port_info(P, name), P)
end || P <- erlang:ports()].
+port_info(P,[Item|Items]) ->
+ case erlang:port_info(P,Item) of
+ undefined -> port_info(P,Items);
+ Value -> [Value|port_info(P,Items)]
+ end;
+port_info(_,[]) ->
+ [].
+
+inet_port_extra({_,Type},Port) when Type =:= "udp_inet";
+ Type =:= "tcp_inet";
+ Type =:= "sctp_inet" ->
+ Data =
+ case inet:getstat(Port) of
+ {ok, Stats} -> [{statistics, Stats}];
+ _ -> []
+ end ++
+ case inet:peername(Port) of
+ {ok, {RAddr,RPort}} when is_tuple(RAddr), is_integer(RPort) ->
+ [{remote_address,RAddr},{remote_port,RPort}];
+ {ok, RAddr} ->
+ [{remote_address,RAddr}];
+ {error, _} -> []
+ end ++
+ case inet:sockname(Port) of
+ {ok, {LAddr,LPort}} when is_tuple(LAddr), is_integer(LPort) ->
+ [{local_address,LAddr},{local_port,LPort}];
+ {ok, LAddr} ->
+ [{local_address,LAddr}];
+ {error, _} -> []
+ end ++
+ case inet:getopts(Port,
+ [active, broadcast, buffer, delay_send,
+ deliver, dontroute, exit_on_close,
+ header, high_msgq_watermark, high_watermark,
+ ipv6_v6only, keepalive, linger, low_msgq_watermark,
+ low_watermark, mode, netns, nodelay, packet,
+ packet_size, priority, read_packets, recbuf,
+ reuseaddr, send_timeout, send_timeout_close,
+ show_econnreset, sndbuf, tos, tclass]) of
+ {ok, Opts} -> [{options, Opts}];
+ {error, _} -> []
+ end,
+ [{inet,Data}];
+inet_port_extra(_,_) ->
+ [].
+
get_table_list(ets, Opts) ->
HideUnread = proplists:get_value(unread_hidden, Opts, true),
HideSys = proplists:get_value(sys_hidden, Opts, true),
@@ -269,13 +314,12 @@ etop_collect(Collector) ->
case SchedulerWallTime of
undefined ->
- spawn(fun() -> flag_holder_proc(Collector) end),
+ erlang:system_flag(scheduler_wall_time,true),
+ spawn(fun() -> flag_holder_proc(Collector) end),
ok;
_ ->
ok
- end,
-
- erlang:system_flag(scheduler_wall_time,true).
+ end.
flag_holder_proc(Collector) ->
Ref = erlang:monitor(process,Collector),
diff --git a/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c b/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c
index ecdee7e3a2..ec00c68049 100644
--- a/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c
+++ b/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index b33f6f4721..8ec532de76 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.10
+RUNTIME_TOOLS_VSN = 1.11.1
diff --git a/lib/sasl/doc/src/alarm_handler.xml b/lib/sasl/doc/src/alarm_handler.xml
index 8550a88b28..4160757164 100644
--- a/lib/sasl/doc/src/alarm_handler.xml
+++ b/lib/sasl/doc/src/alarm_handler.xml
@@ -54,7 +54,7 @@
format is defined by the user. For example, an event handler
for SNMP can be defined, together with an alarm Management
Information Base (MIB).</p>
- <p>The alarm handler is part of the <c>SASL</c> application.</p>
+ <p>The alarm handler is part of the SASL application.</p>
<p>When writing new event handlers for the alarm handler, the
following events must be handled:</p>
<taglist>
@@ -76,7 +76,7 @@
{NewHandler, Args})</c>. <c>NewHandler:init({Args, {alarm_handler,
Alarms}})</c> is called. For more details, see
<seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>
- in <c>STDLIB</c>.</p>
+ in STDLIB.</p>
</description>
<funcs>
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index 6fbdcb9f5b..a43a966dcb 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -362,12 +362,12 @@ point_of_no_return</pre>
system is restarted.</p>
<pre>
restart_new_emulator</pre>
- <p>This instruction is used when the application <c>ERTS</c>,
- <c>Kernel</c>, <c>STDLIB</c>, or <c>SASL</c> is
+ <p>This instruction is used when the application ERTS,
+ Kernel, STDLIB, or SASL is
upgraded. It shuts down the current emulator and starts a new
one. All processes are terminated gracefully, and the new
- version of <c>ERTS</c>, <c>Kernel</c>, <c>STDLIB</c>, and
- <c>SASL</c> are used when the emulator restarts.
+ version of ERTS, Kernel, STDLIB, and
+ SASL are used when the emulator restarts.
Only one <c>restart_new_emulator</c> instruction is allowed
in the <c>relup</c> file, and it must be placed first.
<seealso marker="systools#make_relup/3"><c>systools:make_relup/3,4</c></seealso>
@@ -385,7 +385,7 @@ restart_new_emulator</pre>
<warning>
<p>As stated earlier, instruction <c>restart_new_emulator</c>
causes the emulator to be restarted with new versions of
- <c>ERTS</c>, <c>Kernel</c>, <c>STDLIB</c>, and <c>SASL</c>.
+ ERTS>, Kernel, STDLIB, and SASL.
However, all other applications do at startup run their old
versions in this new emulator. This is usually no problem,
but every now and then incompatible changes occur to the
diff --git a/lib/sasl/doc/src/error_logging.xml b/lib/sasl/doc/src/error_logging.xml
index 8464a41ff9..4b2c960bbb 100644
--- a/lib/sasl/doc/src/error_logging.xml
+++ b/lib/sasl/doc/src/error_logging.xml
@@ -32,20 +32,20 @@
<rev>B</rev>
<file>error_logging.xml</file>
</header>
- <p>The <c>SASL</c> application introduces three types of reports:</p>
+ <p>The SASL application introduces three types of reports:</p>
<list type="bulleted">
<item>Supervisor report</item>
<item>Progress report</item>
<item>Crash report</item>
</list>
- <p>When the <c>SASL</c> application is started, it adds a handler that
+ <p>When the SASL application is started, it adds a handler that
formats and writes these reports, as specified in the configuration
- parameters for <c>SASL</c>, that is, the environment variables
- in the <c>SASL</c> application specification, which is found in the
- <c>.app</c> file of <c>SASL</c>. For details, see the
+ parameters for SASL, that is, the environment variables
+ in the SASL application specification, which is found in the
+ <c>.app</c> file of SASL. For details, see the
<seealso marker="sasl_app"><c>sasl(6)</c></seealso> application in the
Reference Manual and the <seealso marker="kernel:app"><c>app(4)</c></seealso>
- file in the <c>Kernel</c> Reference Manual.</p>
+ file in the Kernel Reference Manual.</p>
<section>
<title>Supervisor Report</title>
@@ -180,14 +180,14 @@
<p>The report browser is used to browse and format error reports
written by the error logger handler
<seealso marker="stdlib:log_mf_h"><c>log_mf_h</c></seealso>
- defined in <c>STDLIB</c>.</p>
+ defined in STDLIB.</p>
<p>The <c>log_mf_h</c> handler writes all reports to a
report logging directory, which is specified when
- configuring the <c>SASL</c> application.</p>
+ configuring the SASL application.</p>
<p>If the report browser is
used offline, the reports can be copied to another directory
specified when starting the browser. If no such directory
- is specified, the browser reads reports from the <c>SASL</c>
+ is specified, the browser reads reports from the SASL
<c>error_logger_mf_dir</c>.</p>
<section>
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index dae73f8b23..cd3f0e1864 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -31,6 +31,99 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 3.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When both options 'warnings_as_errors' and 'silent' were
+ given to systools:make_script or systools:make_relup, no
+ error reason would be returned if warnings occurred.
+ Instead only the atom 'error' was returned. This is now
+ corrected.</p>
+ <p>
+ Options 'warnings_as_errors' and 'no_warn_sasl' are now
+ also allowed for systools:make_tar.</p>
+ <p>
+ Own Id: OTP-14170</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SASL 3.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>code:add_pathsa/1</c> and command line option
+ <c>-pa</c> both revert the given list of directories when
+ adding it at the beginning of the code path. This is now
+ documented.</p>
+ <p>
+ Own Id: OTP-13920 Aux Id: ERL-267 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SASL 3.0.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved dirty scheduler support. A purge of a module can
+ now be performed without having to wait for completion of
+ all ongoing dirty NIF calls.</p>
+ <p>
+ Note that when enabling support for dirty schedulers, a
+ new purge strategy will as of ERTS version 8.1 be
+ enabled. This new strategy is not fully backwards
+ compatible with the strategy used by default. For more
+ information see the documentation of <seealso
+ marker="erts:erlang#check_process_code/3"><c>erlang:check_process_code/3</c></seealso>.</p>
+ <p>
+ Own Id: OTP-13808 Aux Id: OTP-13833 </p>
+ </item>
+ <item>
+ <p>
+ A new purge strategy has been introduced. The new
+ strategy will by default be disabled during the OTP 19
+ release, but will be the only strategy available as of
+ the OTP 20 release.</p>
+ <p>
+ The new strategy is slightly incompatible with the
+ strategy being used by default in OTP 19. Using the
+ default strategy, processes holding <c>fun</c>s that
+ refer to the module being purged either fail a soft
+ purge, or will be killed during a hard purge. The new
+ strategy completely ignores <c>fun</c>s. If <c>fun</c>s
+ referring to the code being purged exist, and are used
+ after a purge, an exception will be raised upon usage.
+ That is, the behavior will be exactly the same as the
+ case when a <c>fun</c> is received by a process after the
+ purge.</p>
+ <p>
+ The new strategy can optionally be enabled when building
+ OTP during OTP 19, and will automatically be enabled if
+ the runtime system is built with support for dirty
+ schedulers.</p>
+ <p>
+ For more information see the documentation of <seealso
+ marker="erts:erlang#check_process_code/3"><c>erlang:check_process_code/3</c></seealso>.</p>
+ <p>
+ Own Id: OTP-13833</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 3.0</title>
<section><title>Improvements and New Features</title>
@@ -824,7 +917,7 @@
<list>
<item>
<p>Use an infinity timeout in all calls to
- <c>gen_server:call()</c> in the <c>sasl</c>
+ <c>gen_server:call()</c> in the SASL
application.</p>
<p>
Own Id: OTP-8506 Aux Id: seq11509 </p>
diff --git a/lib/sasl/doc/src/part.xml b/lib/sasl/doc/src/part.xml
index f531ed2dea..659710487e 100644
--- a/lib/sasl/doc/src/part.xml
+++ b/lib/sasl/doc/src/part.xml
@@ -30,7 +30,7 @@
<file>part.xml</file>
</header>
<description>
- <p>The System Architecture Support Libraries <c>SASL</c> application
+ <p>The System Architecture Support Libraries SASL application
provides support for alarm handling, release handling, and
related functions.</p>
</description>
diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml
index 1ce19046eb..d5df4fd345 100644
--- a/lib/sasl/doc/src/rb.xml
+++ b/lib/sasl/doc/src/rb.xml
@@ -38,7 +38,7 @@
<p>The Report Browser (RB) tool is used to browse and
format error reports written by the error logger handler
<seealso marker="stdlib:log_mf_h"><c>log_mf_h</c></seealso>
- in <c>STDLIB</c>.</p>
+ in STDLIB.</p>
</description>
<funcs>
@@ -62,7 +62,7 @@
reports that match that filter.</p>
<p>The reports are matched using the
<seealso marker="stdlib:proplists"><c>proplists</c></seealso>
- module in <c>STDLIB</c>. The report must be a proplist
+ module in STDLIB. The report must be a proplist
to be matched against any of the filters.</p>
<p>If the filter has the form <c>{Key, RegExp, re}</c>, the
report must contain an element with key equal to <c>Key</c> and
@@ -102,7 +102,7 @@
</list>
<p>For a definition of valid regular expressions and options, see
the <seealso marker="stdlib:re"><c>re</c></seealso> module in
- <c>STDLIB</c> and in particular function <c>re:run/3</c>.</p>
+ STDLIB and in particular function <c>re:run/3</c>.</p>
<p>For details about data type <c>mp()</c>, see
<seealso marker="stdlib:re#type-mp"><c>re:mp()</c></seealso>.</p>
</desc>
diff --git a/lib/sasl/doc/src/ref_man.xml b/lib/sasl/doc/src/ref_man.xml
index 42045df5ec..78cf1eb26e 100644
--- a/lib/sasl/doc/src/ref_man.xml
+++ b/lib/sasl/doc/src/ref_man.xml
@@ -30,7 +30,7 @@
<file>application.xml</file>
</header>
<description>
- <p>The <c>SASL</c> application provides support for alarm handling,
+ <p>The SASL application provides support for alarm handling,
release handling, and related functions.</p>
</description>
<xi:include href="sasl_app.xml"/>
diff --git a/lib/sasl/doc/src/rel.xml b/lib/sasl/doc/src/rel.xml
index d6558c06b4..9356b2cd47 100644
--- a/lib/sasl/doc/src/rel.xml
+++ b/lib/sasl/doc/src/rel.xml
@@ -59,7 +59,7 @@
<tag><c>Vsn = string()</c></tag>
<item><p>Release version.</p></item>
<tag><c>EVsn = string()</c></tag>
- <item><p><c>ERTS</c> version the release is intended for.</p></item>
+ <item><p>ERTS version the release is intended for.</p></item>
<tag><c>Application = atom()</c></tag>
<item><p>Name of an application included in the release.</p></item>
<tag><c>AppVsn = string()</c></tag>
@@ -82,8 +82,8 @@
to the same value as in the application resource file.</p></item>
</taglist>
<note>
- <p>The list of applications must contain the <c>Kernel</c> and
- <c>STDLIB</c> applications.</p>
+ <p>The list of applications must contain the Kernel and
+ STDLIB applications.</p>
</note>
</section>
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index bcbc5f5339..8f073807fb 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -31,7 +31,7 @@
<module>release_handler</module>
<modulesummary>Unpacking and Installation of Release Packages</modulesummary>
<description>
- <p>The <em>release handler</em> process belongs to the <c>SASL</c>
+ <p>The <em>release handler</em> process belongs to the SASL
application, which is responsible for <em>release handling</em>,
that is, unpacking, installation, and removal of release packages.</p>
<p>An introduction to release handling and an example is provided in
@@ -44,7 +44,7 @@
directory of the previous version of the release, where
<c>$ROOT</c> is the installation root directory,
<seealso marker="kernel:code#root_dir/0"><c>code:root_dir()</c></seealso>.
- Another <c>releases</c> directory can be specified using the <c>SASL</c>
+ Another <c>releases</c> directory can be specified using the SASL
configuration parameter <c>releases_dir</c> or the OS environment
variable <c>RELDIR</c>. The release handler must have write access
to this directory to install the new release.
@@ -56,7 +56,7 @@
<item>A boot script, <c>Name.boot</c></item>
</list>
<p>The <c>.rel</c> file contains information about the release: its name,
- version, and which <c>ERTS</c> and application versions it uses.</p>
+ version, and which ERTS and application versions it uses.</p>
<p>A release package can also contain:</p>
<list type="bulleted">
<item>A release upgrade file, <c>relup</c></item>
@@ -115,7 +115,7 @@
<em>System Documentation</em>. In this case, the system
configuration file <c>sys.config</c> is mandatory.</p>
<p>The installation of a new release can restart the system. Which
- program to use is specified by the <c>SASL</c> configuration
+ program to use is specified by the SASL configuration
parameter <c>start_prg</c>, which defaults
to <c>$ROOT/bin/start</c>.</p>
<p>The emulator restart on Windows NT expects that the system is
@@ -132,7 +132,7 @@
is made permanent.</p>
<p>The release handler at a node running on a diskless machine,
or with a read-only file system, must be configured accordingly
- using the following <c>SASL</c> configuration parameters (for
+ using the following SASL configuration parameters (for
details, see <seealso marker="sasl_app">sasl(6)</seealso>):</p>
<taglist>
<tag><c>masters</c></tag>
@@ -287,7 +287,7 @@
returned, the emulator is restarted
before the upgrade instructions are executed. This
occurs if the emulator or any of the applications
- <c>Kernel</c>, <c>STDLIB</c>, or <c>SASL</c>
+ Kernel, STDLIB, or SASL
are updated. The new emulator version
and these core applications execute after the restart.
For all other applications the old versions are
@@ -310,13 +310,13 @@
<tag><c>code_change_timeout</c></tag>
<item><p>Defines the time-out
for all calls to
- <seealso marker="stdlib:sys#change_code/4"><c>stdlib:sys:change_code</c></seealso>.
+ <seealso marker="stdlib:sys#change_code/4"><c>sys:change_code</c></seealso>.
If no value is specified or <c>default</c> is specified, the
default value defined in <c>sys</c> is used.</p></item>
<tag><c>suspend_timeout</c></tag>
<item><p>Defines the time-out for
all calls to
- <seealso marker="stdlib:sys#suspend/1"><c>stdlib:sys:suspend</c></seealso>.
+ <seealso marker="stdlib:sys#suspend/1"><c>sys:suspend</c></seealso>.
If no value is specified, the values defined by the <c>Timeout</c>
parameter of the <c>upgrade</c> or <c>suspend</c> instructions are used.
If <c>default</c> is specified, the default value defined in
@@ -342,7 +342,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
=> {ok,NewVsn}</code>
<p>If <c>NewVsn</c> is installed with option
<c>{update_paths,true}</c>, then
- <seealso marker="kernel:code#lib_dir/1"><c>kernel:code:lib_dir(myapp)</c></seealso>
+ <seealso marker="kernel:code#lib_dir/1"><c>code:lib_dir(myapp)</c></seealso>
returns <c>/home/user/myapp-1.0</c>.</p></item>
</taglist>
<note>
@@ -801,7 +801,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
is an atom named from the Posix error codes, such as
<c>enoent</c>, <c>eacces</c>, or <c>eisdir</c>. See
<seealso marker="kernel:file"><c>file(3)</c></seealso>
- in <c>Kernel</c>.</p></item>
+ in Kernel.</p></item>
<tag><c>Posix</c></tag>
<item><p>Some file operation failed, as for the previous item in
the list.</p></item>
diff --git a/lib/sasl/doc/src/sasl_app.xml b/lib/sasl/doc/src/sasl_app.xml
index 52f449c2a8..0576397f9b 100644
--- a/lib/sasl/doc/src/sasl_app.xml
+++ b/lib/sasl/doc/src/sasl_app.xml
@@ -31,17 +31,17 @@
<app>sasl</app>
<appsummary>The SASL application</appsummary>
<description>
- <p>The <c>SASL</c> application provides the following services:</p>
+ <p>The SASL application provides the following services:</p>
<list type="bulleted">
<item><c>alarm_handler</c></item>
<item><c>rb</c></item>
<item><c>release_handler</c></item>
<item><c>systools</c></item>
</list>
- <p>The <c>SASL</c> application also includes <c>error_logger</c> event
- handlers for formatting <c>SASL</c> error and crash reports.</p>
+ <p>The SASL application also includes <c>error_logger</c> event
+ handlers for formatting SASL error and crash reports.</p>
<note>
- <p>The <c>SASL</c> application in OTP has nothing to do with
+ <p>The SASL application in OTP has nothing to do with
"Simple Authentication and Security Layer" (RFC 4422).</p>
</note>
</description>
@@ -49,7 +49,7 @@
<section>
<title>Error Logger Event Handlers</title>
<p>The following error logger event handlers are used by
- the <c>SASL</c> application.</p>
+ the SASL application.</p>
<taglist>
<tag><c>sasl_report_tty_h</c></tag>
<item>
@@ -57,7 +57,7 @@
reports</em>, and <em>progress reports</em> to <c>stdio</c>.
This error logger event handler uses
<seealso marker="kernel:kernel_app#error_logger_format_depth">error_logger_format_depth</seealso>
- in the <c>Kernel</c> application to limit how much detail is
+ in the Kernel application to limit how much detail is
printed in crash and supervisor reports.</p>
</item>
<tag><c>sasl_report_file_h</c></tag>
@@ -66,7 +66,7 @@
report</em>, and <em>progress report</em> to a single file.
This error logger event handler uses
<seealso marker="kernel:kernel_app#error_logger_format_depth">error_logger_format_depth</seealso>
- in the <c>Kernel</c> application to limit the details
+ in the Kernel application to limit the details
printed in crash and supervisor reports.</p>
</item>
<tag><c>log_mf_h</c></tag>
@@ -75,9 +75,9 @@
error logger to disk. Multiple files and log rotation are
used. For efficiency reasons, each event is written as a
binary. For more information about this handler,
- see <seealso marker="stdlib:log_mf_h">the <c>STDLIB</c> Reference
+ see <seealso marker="stdlib:log_mf_h">the STDLIB Reference
Manual</seealso>.</p>
- <p>To activate this event handler, three <c>SASL</c>
+ <p>To activate this event handler, three SASL
configuration parameters must be set,
<c>error_logger_mf_dir</c>, <c>error_logger_mf_maxbytes</c>,
and <c>error_logger_mf_maxfiles</c>. The next section provides
@@ -88,9 +88,9 @@
<section>
<title>Configuration</title>
- <p>The following configuration parameters are defined for the <c>SASL</c>
+ <p>The following configuration parameters are defined for the SASL
application. For more information about configuration parameters, see
- <seealso marker="kernel:app"><c>app(4)</c></seealso> in <c>Kernel</c>.</p>
+ <seealso marker="kernel:app"><c>app(4)</c></seealso> in Kernel.</p>
<p>All configuration parameters are optional.</p>
<taglist>
<tag><c><![CDATA[sasl_error_logger = Value ]]></c></tag>
@@ -112,7 +112,7 @@
Use <c>[append]</c> to have the <c>FileName</c> open in append mode.
<c>FileName</c> is a string.</p></item>
<tag><c>false</c></tag>
- <item><p>No <c>SASL</c> error logger handler is installed.</p></item>
+ <item><p>No SASL error logger handler is installed.</p></item>
</taglist>
</item>
<tag><c><![CDATA[errlog_type = error | progress | all ]]></c></tag>
diff --git a/lib/sasl/doc/src/sasl_intro.xml b/lib/sasl/doc/src/sasl_intro.xml
index b71dafb192..f74a7c1db8 100644
--- a/lib/sasl/doc/src/sasl_intro.xml
+++ b/lib/sasl/doc/src/sasl_intro.xml
@@ -32,7 +32,7 @@
<section>
<title>Scope</title>
- <p>The <c>SASL</c> application provides support for:</p>
+ <p>The SASL application provides support for:</p>
<list type="bulleted">
<item>Error logging</item>
<item>Alarm handling</item>
diff --git a/lib/sasl/doc/src/script.xml b/lib/sasl/doc/src/script.xml
index 8ed132354d..b40ff28179 100644
--- a/lib/sasl/doc/src/script.xml
+++ b/lib/sasl/doc/src/script.xml
@@ -88,7 +88,7 @@
follows:</p>
<list type="bulleted">
<item><c>-pa Dir1 Dir2 ... DirN</c> adds the directories
- <c>Dir1, Dir2, ..., DirN</c> to the front of the initial
+ <c>DirN, DirN-1, ..., Dir2, Dir1</c> to the front of the initial
load path.</item>
<item><c>-pz Dir1 Dir2 ... DirN</c> adds the directories
<c>Dir1, Dir2, ..., DirN</c> to the end of the initial
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index 7446762de4..e7c3c499da 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2016</year>
+ <year>2017</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -85,7 +85,7 @@
</item>
<item>
<p>If the emulator needs to be restarted after upgrading or
- downgrading, that is, if the <c>ERTS</c> version differs
+ downgrading, that is, if the ERTS version differs
between <c>Name.rel</c> and <c>Name2.rel</c></p>
</item>
</list>
@@ -201,10 +201,10 @@
between the applications. Where there are no dependencies,
the order in the <c>.rel</c> file is kept.</p>
<p>The function fails if the mandatory
- applications <c>Kernel</c> and <c>STDLIB</c> are not
+ applications Kernel and STDLIB are not
included in the <c>.rel</c> file and have start
type <c>permanent</c> (which is default).</p>
- <p>If <c>SASL</c> is not included as an application in
+ <p>If SASL is not included as an application in
the <c>.rel</c> file, a warning is issued because such a
release cannot be used in an upgrade. To turn off this
warning, add option <c>no_warn_sasl</c>.</p>
@@ -268,7 +268,7 @@
<fsummary>Creates a release package.</fsummary>
<type>
<v>Name = string()</v>
- <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | src_tests | exref | {exref,[App]} | silent | {outdir,Dir}</v>
+ <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | src_tests | exref | {exref,[App]} | silent | {outdir,Dir} | | no_warn_sasl | warnings_as_errors</v>
<v>&nbsp;Dir = string()</v>
<v>&nbsp;IncDir = src | include | atom()</v>
<v>&nbsp;Var = {VarName,PreFix}</v>
@@ -297,6 +297,10 @@
directory unless <c>Name</c> contains a path. If option
<c>{outdir,Dir}</c> is specified, it is located in <c>Dir</c>
instead.</p>
+ <p>If SASL is not included as an application in
+ the <c>.rel</c> file, a warning is issued because such a
+ release cannot be used in an upgrade. To turn off this
+ warning, add option <c>no_warn_sasl</c>.</p>
<p>By default, the release package contains the directories
<c>lib/App-Vsn/ebin</c> and <c>lib/App-Vsn/priv</c> for each
included application. If more directories are to be included,
diff --git a/lib/sasl/src/sasl.app.src b/lib/sasl/src/sasl.app.src
index 4ee8a7d6c8..633cdfa070 100644
--- a/lib/sasl/src/sasl.app.src
+++ b/lib/sasl/src/sasl.app.src
@@ -46,5 +46,5 @@
{errlog_type, all}]},
{mod, {sasl, []}},
{runtime_dependencies, ["tools-2.6.14","stdlib-3.0","kernel-5.0",
- "erts-8.0"]}]}.
+ "erts-8.1"]}]}.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 352e4984df..3f8c8bc6d8 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -94,7 +94,11 @@ make_script(RelName, Output, Flags) when is_list(RelName),
Warnings = wsasl(Flags, Warnings0),
case systools_lib:werror(Flags, Warnings) of
true ->
- return(ok,Warnings,Flags);
+ Warnings1 = [W || {warning,W}<-Warnings],
+ return({error,?MODULE,
+ {warnings_treated_as_errors,Warnings1}},
+ Warnings,
+ Flags);
false ->
case generate_script(Output,Release,Appls,Flags) of
ok ->
@@ -115,7 +119,6 @@ make_script(RelName, _Output, Flags) when is_list(Flags) ->
make_script(RelName, _Output, Flags) ->
badarg(Flags,[RelName, Flags]).
-
wsasl(Options, Warnings) ->
case lists:member(no_warn_sasl,Options) of
true -> lists:delete({warning,missing_sasl},Warnings);
@@ -148,21 +151,10 @@ get_outdir(Flags) ->
return(ok,Warnings,Flags) ->
case member(silent,Flags) of
true ->
- case systools_lib:werror(Flags, Warnings) of
- true ->
- error;
- false ->
- {ok,?MODULE,Warnings}
- end;
+ {ok,?MODULE,Warnings};
_ ->
- case member(warnings_as_errors,Flags) of
- true ->
- io:format("~ts",[format_warning(Warnings, true)]),
- error;
- false ->
- io:format("~ts",[format_warning(Warnings)]),
- ok
- end
+ io:format("~ts",[format_warning(Warnings)]),
+ ok
end;
return({error,Mod,Error},_,Flags) ->
case member(silent,Flags) of
@@ -300,6 +292,8 @@ add_apply_upgrade(Script,Args) ->
%% {variables,[{Name,AbsString}]}
%% {machine, jam | beam | vee}
%% {var_tar, include | ownfile | omit}
+%% no_warn_sasl
+%% warnings_as_errors
%%
%% The tar file contains:
%% lib/App-Vsn/ebin
@@ -332,13 +326,23 @@ make_tar(RelName, Flags) when is_list(RelName), is_list(Flags) ->
Path = make_set(Path1 ++ code:get_path()),
ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
- {ok, Release, Appls, Warnings} ->
- case catch mk_tar(RelName, Release, Appls, Flags, Path1) of
- ok ->
- return(ok,Warnings,Flags);
- Error ->
- return(Error,Warnings,Flags)
- end;
+ {ok, Release, Appls, Warnings0} ->
+ Warnings = wsasl(Flags, Warnings0),
+ case systools_lib:werror(Flags, Warnings) of
+ true ->
+ Warnings1 = [W || {warning,W}<-Warnings],
+ return({error,?MODULE,
+ {warnings_treated_as_errors,Warnings1}},
+ Warnings,
+ Flags);
+ false ->
+ case catch mk_tar(RelName, Release, Appls, Flags, Path1) of
+ ok ->
+ return(ok,Warnings,Flags);
+ Error ->
+ return(Error,Warnings,Flags)
+ end
+ end;
Error ->
return(Error,[],Flags)
end;
@@ -1491,8 +1495,9 @@ mandatory_modules() ->
preloaded() ->
%% Sorted
[erl_prim_loader,erl_tracer,erlang,
- erts_code_purger,
- erts_internal,init,otp_ring0,prim_eval,prim_file,
+ erts_code_purger,erts_dirty_process_code_checker,
+ erts_internal,erts_literal_area_collector,
+ init,otp_ring0,prim_eval,prim_file,
prim_inet,prim_zip,zlib].
%%______________________________________________________________________
@@ -2108,90 +2113,80 @@ cas([Y | Args], X) ->
%% Check Options for make_tar
check_args_tar(Args) ->
- cat(Args, {undef, undef, undef, undef, undef, undef, undef, undef, undef, undef, []}).
+ cat(Args, []).
-cat([], {_Path,_Sil,_Dirs,_Erts,_Test,_Var,_VarTar,_Mach,_Xref,_XrefApps, X}) ->
+cat([], X) ->
X;
%%% path ---------------------------------------------------------------
-cat([{path, P} | Args], {Path, Sil, Dirs, Erts, Test,
- Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(P) ->
+cat([{path, P} | Args], X) when is_list(P) ->
case check_path(P) of
ok ->
- cat(Args, {P, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+ cat(Args, X);
error ->
- cat(Args, {Path, Sil, Dirs, Erts, Test,
- Var, VarTar, Mach, Xref, XrefApps, X++[{path,P}]})
+ cat(Args, X++[{path,P}])
end;
%%% silent -------------------------------------------------------------
-cat([silent | Args], {Path, _Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, silent, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+cat([silent | Args], X) ->
+ cat(Args, X);
%%% dirs ---------------------------------------------------------------
-cat([{dirs, D} | Args], {Path, Sil, Dirs, Erts, Test,
- Var, VarTar, Mach, Xref, XrefApps, X}) ->
+cat([{dirs, D} | Args], X) ->
case check_dirs(D) of
ok ->
- cat(Args, {Path, Sil, D, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+ cat(Args, X);
error ->
- cat(Args, {Path, Sil, Dirs, Erts, Test,
- Var, VarTar, Mach, Xref, XrefApps, X++[{dirs, D}]})
+ cat(Args, X++[{dirs, D}])
end;
%%% erts ---------------------------------------------------------------
-cat([{erts, E} | Args], {Path, Sil, Dirs, _Erts, Test,
- Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(E)->
- cat(Args, {Path, Sil, Dirs, E, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+cat([{erts, E} | Args], X) when is_list(E)->
+ cat(Args, X);
%%% src_tests ----------------------------------------------------
-cat([src_tests | Args], {Path, Sil, Dirs, Erts, _Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, src_tests, Var, VarTar, Mach,
- Xref, XrefApps, X});
+cat([src_tests | Args], X) ->
+ cat(Args, X);
%%% variables ----------------------------------------------------------
-cat([{variables, V} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(V) ->
+cat([{variables, V} | Args], X) when is_list(V) ->
case check_vars(V) of
ok ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, V, VarTar, Mach, Xref, XrefApps, X});
+ cat(Args, X);
error ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach,
- Xref, XrefApps, X++[{variables, V}]})
+ cat(Args, X++[{variables, V}])
end;
%%% var_tar ------------------------------------------------------------
-cat([{var_tar, VT} | Args], {Path, Sil, Dirs, Erts, Test,
- Var, _VarTar, Mach, Xref, XrefApps, X}) when VT == include ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, include, Mach, Xref, XrefApps, X});
-cat([{var_tar, VT} | Args], {Path, Sil, Dirs, Erts, Test,
- Var, _VarTar, Mach, Xref, XrefApps, X}) when VT == ownfile ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, ownfile, Mach, Xref, XrefApps, X});
-cat([{var_tar, VT} | Args], {Path, Sil, Dirs, Erts, Test,
- Var, _VarTar, Mach, Xref, XrefApps, X}) when VT == omit ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, omit, Mach, Xref, XrefApps, X});
+cat([{var_tar, VT} | Args], X) when VT == include;
+ VT == ownfile;
+ VT == omit ->
+ cat(Args, X);
%%% machine ------------------------------------------------------------
-cat([{machine, M} | Args], {Path, Sil, Dirs, Erts, Test,
- Var, VarTar, Mach, Xref, XrefApps, X}) when is_atom(M) ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+cat([{machine, M} | Args], X) when is_atom(M) ->
+ cat(Args, X);
%%% exref --------------------------------------------------------------
-cat([exref | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, _Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, exref, XrefApps, X});
+cat([exref | Args], X) ->
+ cat(Args, X);
%%% exref Apps ---------------------------------------------------------
-cat([{exref, Apps} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(Apps) ->
+cat([{exref, Apps} | Args], X) when is_list(Apps) ->
case check_apps(Apps) of
ok ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach,
- Xref, Apps, X});
+ cat(Args, X);
error ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach,
- Xref, XrefApps, X++[{exref, Apps}]})
+ cat(Args, X++[{exref, Apps}])
end;
%%% outdir Dir ---------------------------------------------------------
-cat([{outdir, Dir} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(Dir) ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach,
- Xref, XrefApps, X});
+cat([{outdir, Dir} | Args], X) when is_list(Dir) ->
+ cat(Args, X);
%%% otp_build (secret, not documented) ---------------------------------
-cat([otp_build | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+cat([otp_build | Args], X) ->
+ cat(Args, X);
+%%% warnings_as_errors ----
+cat([warnings_as_errors | Args], X) ->
+ cat(Args, X);
+%%% no_warn_sasl ----
+cat([no_warn_sasl | Args], X) ->
+ cat(Args, X);
%%% no_module_tests (kept for backwards compatibility, but ignored) ----
-cat([no_module_tests | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+cat([no_module_tests | Args], X) ->
+ cat(Args, X);
%%% ERROR --------------------------------------------------------------
-cat([Y | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X++[Y]}).
+cat([Y | Args], X) ->
+ cat(Args, X++[Y]).
check_path([]) ->
ok;
@@ -2291,6 +2286,9 @@ format_error({delete,File,Error}) ->
[File,file:format_error(Error)]);
format_error({tar_error,What}) ->
form_tar_err(What);
+format_error({warnings_treated_as_errors,Warnings}) ->
+ io_lib:format("Warnings being treated as errors:~n~ts",
+ [map(fun(W) -> form_warn("",W) end, Warnings)]);
format_error(ListOfErrors) when is_list(ListOfErrors) ->
format_errors(ListOfErrors);
format_error(E) -> io_lib:format("~p~n",[E]).
@@ -2347,24 +2345,15 @@ form_tar_err({add, File, Error}) ->
%% Format warning
format_warning(Warnings) ->
- format_warning(Warnings, false).
-
-format_warning(Warnings, Werror) ->
- Prefix = case Werror of
- true ->
- "";
- false ->
- "*WARNING* "
- end,
- map(fun({warning,W}) -> form_warn(Prefix, W) end, Warnings).
-
-form_warn(Prefix, {source_not_found,{Mod,_,App,_,_}}) ->
+ map(fun({warning,W}) -> form_warn("*WARNING* ", W) end, Warnings).
+
+form_warn(Prefix, {source_not_found,{Mod,App,_}}) ->
io_lib:format("~ts~w: Source code not found: ~w.erl~n",
[Prefix,App,Mod]);
form_warn(Prefix, {{parse_error, File},{_,_,App,_,_}}) ->
io_lib:format("~ts~w: Parse error: ~p~n",
[Prefix,App,File]);
-form_warn(Prefix, {obj_out_of_date,{Mod,_,App,_,_}}) ->
+form_warn(Prefix, {obj_out_of_date,{Mod,App,_}}) ->
io_lib:format("~ts~w: Object code (~w) out of date~n",
[Prefix,App,Mod]);
form_warn(Prefix, {exref_undef, Undef}) ->
@@ -2374,8 +2363,8 @@ form_warn(Prefix, {exref_undef, Undef}) ->
end,
map(F, Undef);
form_warn(Prefix, missing_sasl) ->
- io_lib:format("~ts: Missing application sasl. "
+ io_lib:format("~tsMissing application sasl. "
"Can not upgrade with this release~n",
[Prefix]);
form_warn(Prefix, What) ->
- io_lib:format("~ts ~p~n", [Prefix,What]).
+ io_lib:format("~ts~p~n", [Prefix,What]).
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index 28534dc0c8..6bc26c8cc9 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -155,36 +155,12 @@ mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) ->
mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) ->
case check_opts(Opts) of
[] ->
- R = (catch do_mk_relup(TopRelFile,BaseUpRelDcs,BaseDnRelDcs,
- add_code_path(Opts), Opts)),
- case {get_opt(silent, Opts), get_opt(noexec, Opts)} of
- {false, false} ->
- case R of
- {ok, _Res, _Mod, Ws} ->
- print_warnings(Ws, Opts),
- case systools_lib:werror(Opts, Ws) of
- true ->
- error;
- false ->
- ok
- end;
- Other ->
- print_error(Other),
- error
- end;
- _ ->
- case R of
- {ok, _Res, _Mod, Ws} ->
- case systools_lib:werror(Opts, Ws) of
- true ->
- error;
- false ->
- R
- end;
- R ->
- R
- end
- end;
+ R = try do_mk_relup(TopRelFile,BaseUpRelDcs,BaseDnRelDcs,
+ add_code_path(Opts), Opts)
+ catch throw:Error ->
+ Error
+ end,
+ done_mk_relup(Opts, R);
BadArg ->
erlang:error({badarg, BadArg})
end.
@@ -224,17 +200,45 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) ->
{Dn, Ws2} = foreach_baserel_dn(TopRel, TopApps, BaseDnRelDcs,
Path, Opts, Ws1),
Relup = {TopRel#release.vsn, Up, Dn},
- case systools_lib:werror(Opts, Ws2) of
- true ->
- ok;
- false ->
- write_relup_file(Relup, Opts)
- end,
- {ok, Relup, ?MODULE, Ws2};
+
+ {ok, Relup, Ws2};
Other ->
- throw(Other)
+ Other
end.
+done_mk_relup(Opts, {ok,Relup,Ws}) ->
+ WAE = get_opt(warnings_as_errors,Opts),
+ Silent = get_opt(silent,Opts),
+ Noexec = get_opt(noexec,Opts),
+
+ if WAE andalso Ws=/=[] ->
+ return_error(Silent,
+ {error,?MODULE,{warnings_treated_as_errors, Ws}});
+ not Noexec ->
+ case write_relup_file(Relup,Opts) of
+ ok ->
+ return_ok(Silent,Relup,Ws);
+ Error ->
+ return_error(Silent,Error)
+ end;
+ true -> % noexec
+ return_ok(true,Relup,Ws)
+ end;
+done_mk_relup(Opts, Error) ->
+ return_error(get_opt(silent,Opts) orelse get_opt(noexec,Opts), Error).
+
+return_error(true, Error) ->
+ Error;
+return_error(false, Error) ->
+ print_error(Error),
+ error.
+
+return_ok(true,Relup,Ws) ->
+ {ok,Relup,?MODULE,Ws};
+return_ok(false,_Relup,Ws) ->
+ print_warnings(Ws),
+ ok.
+
%%-----------------------------------------------------------------
%% foreach_baserel_up(Rel, TopApps, BaseRelDcs, Path, Opts, Ws) -> Ret
%% foreach_baserel_dn(Rel, TopApps, BaseRelDcs, Path, Opts, Ws) -> Ret
@@ -529,33 +533,18 @@ to_list(X) when is_list(X) -> X.
%% Writes a relup file.
%%
write_relup_file(Relup, Opts) ->
- case get_opt(noexec, Opts) of
- true ->
- ok;
- _ ->
- Filename = case get_opt(outdir, Opts) of
- OutDir when is_list(OutDir) ->
- filename:join(filename:absname(OutDir),
- "relup");
- false ->
- "relup";
- Badarg ->
- throw({error, ?MODULE, {badarg, {outdir,Badarg}}})
- end,
-
- case file:open(Filename, [write]) of
- {ok, Fd} ->
- io:format(Fd, "~p.~n", [Relup]),
- case file:close(Fd) of
- ok -> ok;
- {error,Reason} ->
- throw({error, ?MODULE,
- {file_problem, {"relup", {close,Reason}}}})
- end;
- {error, Reason} ->
- throw({error, ?MODULE,
- {file_problem, {"relup", {open, Reason}}}})
- end
+ Filename = filename:join(filename:absname(get_opt(outdir,Opts)),
+ "relup"),
+ case file:open(Filename, [write]) of
+ {ok, Fd} ->
+ io:format(Fd, "~p.~n", [Relup]),
+ case file:close(Fd) of
+ ok -> ok;
+ {error,Reason} ->
+ {error, ?MODULE, {file_problem, {"relup", {close,Reason}}}}
+ end;
+ {error, Reason} ->
+ {error, ?MODULE, {file_problem, {"relup", {open, Reason}}}}
end.
add_code_path(Opts) ->
@@ -593,10 +582,9 @@ default(path) -> false;
default(noexec) -> false;
default(silent) -> false;
default(restart_emulator) -> false;
-default(outdir) -> false.
+default(outdir) -> ".";
+default(warnings_as_errors) -> false.
-print_error({'EXIT', Err}) ->
- print_error(Err);
print_error({error, Mod, Error}) ->
S = apply(Mod, format_error, [Error]),
io:format(S, []);
@@ -614,24 +602,20 @@ format_error({missing_sasl,Release}) ->
io_lib:format("No sasl application in release ~ts, ~ts. "
"Can not be upgraded.",
[Release#release.name, Release#release.vsn]);
+format_error({warnings_treated_as_errors, Warnings}) ->
+ io_lib:format("Warnings being treated as errors:~n~ts",
+ [[format_warning("",W) || W <- Warnings]]);
format_error(Error) ->
- io:format("~p~n", [Error]).
+ io_lib:format("~p~n", [Error]).
-print_warnings(Ws, Opts) when is_list(Ws) ->
- lists:foreach(fun(W) -> print_warning(W, Opts) end, Ws);
-print_warnings(W, Opts) ->
- print_warning(W, Opts).
+print_warnings(Ws) when is_list(Ws) ->
+ lists:foreach(fun(W) -> print_warning(W) end, Ws);
+print_warnings(W) ->
+ print_warning(W).
-print_warning(W, Opts) ->
- Prefix = case lists:member(warnings_as_errors, Opts) of
- true ->
- "";
- false ->
- "*WARNING* "
- end,
- S = format_warning(Prefix, W),
- io:format("~ts", [S]).
+print_warning(W) ->
+ io:format("~ts", [format_warning(W)]).
format_warning(W) ->
format_warning("*WARNING* ", W).
@@ -639,6 +623,8 @@ format_warning(W) ->
format_warning(Prefix, {erts_vsn_changed, {Rel1, Rel2}}) ->
io_lib:format("~tsThe ERTS version changed between ~p and ~p~n",
[Prefix, Rel1, Rel2]);
+format_warning(Prefix, pre_R15_emulator_upgrade) ->
+ io_lib:format("~tsUpgrade from an OTP version earlier than R15. New code should be compiled with the old emulator.~n",[Prefix]);
format_warning(Prefix, What) ->
io_lib:format("~ts~p~n",[Prefix, What]).
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index ad58bb6b7b..7093158502 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1063,6 +1063,12 @@ otp_9395_check_and_purge(cleanup,_Conf) ->
%% OTP-9395 - performance problems when there are MANY processes
%% Upgrade which updates many modules (brutal_purge)
otp_9395_update_many_mods(Conf) when is_list(Conf) ->
+
+ %% "nain" is very slow - it fails this test quite often due to a
+ %% long sys call
+ %% /proc/cpuinfo: "clock: 1249MHz"
+ inet:gethostname() == {ok,"nain"} andalso throw({skip,"slow test host"}),
+
%% Set some paths
PrivDir = priv_dir(Conf),
Dir = filename:join(PrivDir,"otp_9395_update_many_mods"),
@@ -1162,6 +1168,12 @@ otp_9395_update_many_mods(cleanup,_Conf) ->
%% OTP-9395 - performance problems when there are MANY processes
%% Upgrade which removes many modules (brutal_purge)
otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
+
+ %% "nain" is very slow - it fails this test quite often due to a
+ %% long sys call
+ %% /proc/cpuinfo: "clock: 1249MHz"
+ inet:gethostname() == {ok,"nain"} andalso throw({skip,"slow test host"}),
+
%% Set some paths
PrivDir = priv_dir(Conf),
Dir = filename:join(PrivDir,"otp_9395_rm_many_mods"),
@@ -1920,7 +1932,7 @@ wait_nodes_up(Nodes, Tag) ->
wait_nodes_up(Nodes0, Tag, Apps) ->
?t:format("wait_nodes_up(~p, ~p, ~p):",[Nodes0, Tag, Apps]),
Nodes = fix_nodes(Nodes0),
- wait_nodes_up(Nodes, Tag, lists:umerge(Apps,[kernel,stdlib,sasl]), 30).
+ wait_nodes_up(Nodes, Tag, lists:umerge(Apps,[kernel,stdlib,sasl]), 60).
fix_nodes([{Node,InitPid}|Nodes]) ->
[{Node,InitPid} | fix_nodes(Nodes)];
@@ -1962,7 +1974,7 @@ wait_nodes_up(Nodes, Tag, Apps, N) ->
?t:format("",[]),
ok;
_ ->
- timer:sleep(1000),
+ timer:sleep(2000),
wait_nodes_up(Pang, Tag, Apps, N-1)
end.
diff --git a/lib/sasl/test/release_handler_SUITE_data/start b/lib/sasl/test/release_handler_SUITE_data/start
index 87275045b1..eab2b77aed 100755
--- a/lib/sasl/test/release_handler_SUITE_data/start
+++ b/lib/sasl/test/release_handler_SUITE_data/start
@@ -21,8 +21,7 @@ then
fi
HEART_COMMAND=$ROOTDIR/bin/start
-HW_WD_DISABLE=true
-export HW_WD_DISABLE HEART_COMMAND
+export HEART_COMMAND
START_ERL_DATA=${1:-$RELDIR/start_erl.data}
diff --git a/lib/sasl/test/release_handler_SUITE_data/start_client b/lib/sasl/test/release_handler_SUITE_data/start_client
index 5ea94d6f7c..05d744f06e 100755
--- a/lib/sasl/test/release_handler_SUITE_data/start_client
+++ b/lib/sasl/test/release_handler_SUITE_data/start_client
@@ -24,8 +24,7 @@ RELDIR=$CLIENTDIR/releases
# Note that this scripts is modified an copied to $CLIENTDIR/bin/start
# in release_handler_SUITE:copy_client - therefore HEART_COMMAND is as follows:
HEART_COMMAND=$CLIENTDIR/bin/start
-HW_WD_DISABLE=true
-export HW_WD_DISABLE HEART_COMMAND
+export HEART_COMMAND
START_ERL_DATA=${1:-$RELDIR/start_erl.data}
diff --git a/lib/sasl/test/rh_test_lib.erl b/lib/sasl/test/rh_test_lib.erl
index 11935496d8..dacd8b6b9f 100644
--- a/lib/sasl/test/rh_test_lib.erl
+++ b/lib/sasl/test/rh_test_lib.erl
@@ -18,7 +18,7 @@ cmd(Cmd,Args,Env) ->
case open_port({spawn_executable, Cmd}, [{args,Args},{env,Env}]) of
Port when is_port(Port) ->
unlink(Port),
- erlang:port_close(Port),
+ catch erlang:port_close(Port), % migth already be closed, so catching
ok;
Error ->
Error
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index bf95ceb70c..5e546d16a8 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,8 @@
-module(systools_SUITE).
+-compile(export_all).
+
%%-define(debug, true).
-include_lib("common_test/include/ct.hrl").
@@ -39,31 +41,6 @@
-include_lib("kernel/include/file.hrl").
--export([all/0,suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
--export([script_options/1, normal_script/1, unicode_script/1,
- unicode_script/2, no_mod_vsn_script/1,
- wildcard_script/1, variable_script/1, no_sasl_script/1,
- no_dot_erlang_script/1,
- 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,
- invalid_system_files_tar/2, variable_tar/1,
- src_tests_tar/1, var_tar/1, exref_tar/1, link_tar/1,
- otp_9507_path_ebin/1]).
--export([normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1,
- no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1,
- regexp_relup/1]).
--export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]).
--export([otp_6226_outdir/1]).
--export([init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2]).
--export([delete_tree/1]).
-
-import(lists, [foldl/3]).
-define(default_timeout, ?t:minutes(20)).
@@ -91,7 +68,8 @@ groups() ->
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
invalid_system_files_tar, variable_tar,
- src_tests_tar, var_tar, exref_tar, link_tar, otp_9507_path_ebin]},
+ src_tests_tar, var_tar, exref_tar, link_tar, no_sasl_tar,
+ otp_9507_path_ebin]},
{relup, [],
[normal_relup, restart_relup, abnormal_relup, no_sasl_relup,
no_appup_relup, bad_appup_relup, app_start_type_relup, regexp_relup
@@ -238,6 +216,7 @@ normal_script(Config) when is_list(Config) ->
%% Check the same but w. silent flag
{ok, _, []} = systools:make_script(LatestName, [silent]),
+ {ok, _, []} = systools:make_script(LatestName, [silent,warnings_as_errors]),
%% Use the local option
ok = systools:make_script(LatestName, [local]),
@@ -456,9 +435,16 @@ no_sasl_script(Config) when is_list(Config) ->
{ok, _ , [{warning,missing_sasl}]} =
systools:make_script(LatestName,[{path, P},silent]),
+ {error, systools_make, {warnings_treated_as_errors,[missing_sasl]}} =
+ systools:make_script(LatestName,[{path, P},silent,warnings_as_errors]),
+
{ok, _ , []} =
systools:make_script(LatestName,[{path, P},silent, no_warn_sasl]),
+ {ok, _ , []} =
+ systools:make_script(LatestName,[{path, P},silent, no_warn_sasl,
+ warnings_as_errors]),
+
ok = file:set_cwd(OldDir),
ok.
@@ -525,7 +511,9 @@ src_tests_script(Config) when is_list(Config) ->
ok = file:delete(BootFile),
false = filelib:is_regular(BootFile),
%% With warnings_as_errors and src_tests option, an error should be issued
- error =
+ {error, systools_make,
+ {warnings_treated_as_errors, [{obj_out_of_date,_},
+ {source_not_found,_}]}} =
systools:make_script(LatestName, [silent, {path, N}, src_tests,
warnings_as_errors]),
error =
@@ -745,7 +733,7 @@ exref_script(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName, [{path,P}, silent]),
+ {ok, _, []} = systools:make_script(LatestName, [{path,P}, silent]),
%% Complete exref
{ok, _, W1} =
@@ -894,10 +882,10 @@ normal_tar(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ {ok, _, []} = systools:make_script(LatestName, [silent, {path, P}]),
ok = systools:make_tar(LatestName, [{path, P}]),
ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName),
- {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]),
+ {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent]),
ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName),
ok = file:set_cwd(OldDir),
@@ -918,10 +906,10 @@ no_mod_vsn_tar(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ {ok, _, []} = systools:make_script(LatestName, [silent, {path, P}]),
ok = systools:make_tar(LatestName, [{path, P}]),
ok = check_tar(fname([lib,'db-3.1',ebin,'db.app']), LatestName),
- {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]),
+ {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent]),
ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName),
ok = file:set_cwd(OldDir),
@@ -945,11 +933,11 @@ system_files_tar(Config) ->
ok = file:write_file("sys.config","[].\n"),
ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"),
- {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ {ok, _, []} = systools:make_script(LatestName, [silent, {path, P}]),
ok = systools:make_tar(LatestName, [{path, P}]),
ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
ok = check_tar(fname(["releases","LATEST","relup"]), LatestName),
- {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]),
+ {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent]),
ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
ok = check_tar(fname(["releases","LATEST","relup"]), LatestName),
@@ -978,7 +966,7 @@ invalid_system_files_tar(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ {ok, _, []} = systools:make_script(LatestName, [silent, {path, P}]),
%% Add dummy relup and sys.config - faulty sys.config
ok = file:write_file("sys.config","[]\n"), %!!! syntax error - missing '.'
@@ -1036,7 +1024,7 @@ variable_tar(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName,
+ {ok, _, []} = systools:make_script(LatestName,
[silent,
{path, P},
{variables,[{"TEST", LibDir}]}]),
@@ -1045,7 +1033,7 @@ variable_tar(Config) when is_list(Config) ->
{variables,[{"TEST", LibDir}]}]),
ok = check_var_tar("TEST", LatestName),
- {ok, _, _} = systools:make_tar(LatestName,
+ {ok, _, []} = systools:make_tar(LatestName,
[{path, P}, silent,
{variables,[{"TEST", LibDir}]}]),
ok = check_var_tar("TEST", LatestName),
@@ -1174,7 +1162,7 @@ var_tar(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName,
+ {ok, _, []} = systools:make_script(LatestName,
[silent,
{path, P},
{variables,[{"TEST", LibDir}]}]),
@@ -1218,7 +1206,7 @@ exref_tar(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir),
- {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ {ok, _, []} = systools:make_script(LatestName, [silent, {path, P}]),
%% Complete exref
{ok, _, W1} =
@@ -1248,7 +1236,41 @@ exref_tar(Config) when is_list(Config) ->
ok = file:set_cwd(OldDir),
ok.
+%% make_tar: Create tar without sasl appl. Check warning.
+no_sasl_tar(Config) when is_list(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+ {LatestDir, LatestName} = create_script(latest1_no_sasl,Config),
+
+ DataDir = filename:absname(?copydir),
+ LibDir = fname([DataDir, d_normal, lib]),
+ P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ok = file:set_cwd(LatestDir),
+
+ {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ ok = systools:make_tar(LatestName, [{path, P}]),
+ {ok, _, [{warning,missing_sasl}]} =
+ systools:make_tar(LatestName, [{path, P}, silent]),
+ {ok, _, []} =
+ systools:make_tar(LatestName, [{path, P}, silent, no_warn_sasl]),
+ {ok, _, []} =
+ systools:make_tar(LatestName, [{path, P}, silent, no_warn_sasl,
+ warnings_as_errors]),
+ TarFile = LatestName ++ ".tar.gz",
+ true = filelib:is_regular(TarFile),
+ ok = file:delete(TarFile),
+ {error, systools_make, {warnings_treated_as_errors,[missing_sasl]}} =
+ systools:make_tar(LatestName, [{path, P}, silent, warnings_as_errors]),
+ error =
+ systools:make_tar(LatestName, [{path, P}, warnings_as_errors]),
+ false = filelib:is_regular(TarFile),
+
+ ok = file:set_cwd(OldDir),
+ ok.
%% make_tar: OTP-9507 - make_tar failed when path given as just 'ebin'.
otp_9507_path_ebin(Config) when is_list(Config) ->
@@ -1268,7 +1290,7 @@ otp_9507_path_ebin(Config) when is_list(Config) ->
fname([DataDir, lib, kernel, ebin]),
fname([DataDir, lib, stdlib, ebin]),
fname([DataDir, lib, sasl, ebin])],
- {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]),
+ {ok, _, []} = systools:make_script(RelName, [silent, {path, P1}]),
ok = systools:make_tar(RelName, [{path, P1}]),
Content1 = tar_contents(RelName),
@@ -1309,7 +1331,7 @@ normal_relup(Config) when is_list(Config) ->
ok = systools:make_relup(LatestName, [LatestName1], [LatestName1],
[{path, P}]),
ok = check_relup([{db, "2.1"}], [{db, "1.0"}]),
- {ok, _, _, []} =
+ {ok, Relup, _, []} =
systools:make_relup(LatestName, [LatestName1], [LatestName1],
[{path, P}, silent]),
ok = check_relup([{db, "2.1"}], [{db, "1.0"}]),
@@ -1322,7 +1344,9 @@ normal_relup(Config) when is_list(Config) ->
error =
systools:make_relup(LatestName, [LatestName2], [LatestName1],
[{path, P}, warnings_as_errors]),
- error =
+ {error, systools_relup,
+ {warnings_treated_as_errors,[pre_R15_emulator_upgrade,
+ {erts_vsn_changed, _}]}} =
systools:make_relup(LatestName, [LatestName2], [LatestName1],
[{path, P}, silent, warnings_as_errors]),
@@ -1341,6 +1365,14 @@ normal_relup(Config) when is_list(Config) ->
%% relup file should exist now
true = filelib:is_regular("relup"),
+ %% file should not be written if noexec option is used.
+ %% delete before running tests.
+ ok = file:delete("relup"),
+ {ok,Relup,_,[]} =
+ systools:make_relup(LatestName, [LatestName1], [LatestName1],
+ [{path, P}, noexec]),
+ false = filelib:is_regular("relup"),
+
ok = file:set_cwd(OldDir),
ok.
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index fd0fc9b8b5..6aa662a743 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 3.0
+SASL_VSN = 3.0.3
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 0f5c35b300..f1919a6bb1 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,7 +34,55 @@
</header>
- <section><title>SNMP 5.2.3</title>
+ <section><title>SNMP 5.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The SNMP MIB compiler has been fixed to compile MIBS with
+ refinements on user types such as in RFC 4669
+ RADIUS-AUTH-SERVER-MIB.mib. Problem reported and
+ researched by Kenneth Lakin and Daniel Goertzen.</p>
+ <p>
+ See also: https://bugs.erlang.org/browse/ERL-325</p>
+ <p>
+ Own Id: OTP-14145 Aux Id: ERL-325 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Correct bugs when path to mib or idl spec files
+ contains UTF-8 characters. </p>
+ <p>
+ Own Id: OTP-13718 Aux Id: ERL-179 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Solves snmp config string handling as reported by ERL-164
+ and solved by PR-1100</p>
+ <p>
+ Own Id: OTP-13706</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.3</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl
index 94325a8ed6..fc5116dac9 100644
--- a/lib/snmp/src/agent/snmpa_conf.erl
+++ b/lib/snmp/src/agent/snmpa_conf.erl
@@ -154,7 +154,7 @@ do_write_agent_conf(Fd, {intAgentMaxPacketSize = Tag, Val} ) ->
do_write_agent_conf(Fd, {snmpEngineMaxMessageSize = Tag, Val} ) ->
io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
do_write_agent_conf(Fd, {snmpEngineID = Tag, Val} ) ->
- io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+ io:format(Fd, "{~w, ~p}.~n", [Tag, Val]);
do_write_agent_conf(_Fd, Crap) ->
error({bad_agent_config, Crap}).
@@ -758,9 +758,9 @@ do_write_usm_conf(
PrivP, PrivKeyC, OwnPrivKeyC,
Public, AuthKey, PrivKey}) ->
io:format(Fd, "{", []),
- io:format(Fd, "\"~s\", ", [EngineID]),
- io:format(Fd, "\"~s\", ", [UserName]),
- io:format(Fd, "\"~s\", ", [SecName]),
+ io:format(Fd, "~p, ", [EngineID]),
+ io:format(Fd, "~p, ", [UserName]),
+ io:format(Fd, "~p, ", [SecName]),
io:format(Fd, "~w, ", [Clone]),
io:format(Fd, "~w, ", [AuthP]),
do_write_usm2(Fd, AuthKeyC, ", "),
@@ -859,15 +859,15 @@ do_write_vacm_conf(
{vacmSecurityToGroup,
SecModel, SecName, GroupName}) ->
io:format(
- Fd, "{vacmSecurityToGroup, ~w, \"~s\", \"~s\"}.~n",
+ Fd, "{vacmSecurityToGroup, ~w, ~p, ~p}.~n",
[SecModel, SecName, GroupName]);
do_write_vacm_conf(
Fd,
{vacmAccess,
GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) ->
io:format(
- Fd, "{vacmAccess, \"~s\", \"~s\", ~w, ~w, ~w, "
- "\"~s\", \"~s\", \"~s\"}.~n",
+ Fd, "{vacmAccess, ~p, ~p, ~w, ~w, ~w, "
+ "~p, ~p, ~p}.~n",
[GroupName, Prefix, SecModel, SecLevel,
Match, RV, WV, NV]);
do_write_vacm_conf(
@@ -875,7 +875,7 @@ do_write_vacm_conf(
{vacmViewTreeFamily,
ViewIndex, ViewSubtree, ViewStatus, ViewMask}) ->
io:format(
- Fd, "{vacmViewTreeFamily, \"~s\", ~w, ~w, ~w}.~n",
+ Fd, "{vacmViewTreeFamily, ~p, ~w, ~w, ~w}.~n",
[ViewIndex, ViewSubtree, ViewStatus, ViewMask]);
do_write_vacm_conf(_Fd, Crap) ->
error({bad_vacm_config, Crap}).
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index b593e9ea84..d4bf0de61a 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@
{vsn, "%VSN%"},
{modules, [
%% Compiler modules (not in the runtime part of the app)
-% snmpc,
-% snmpc_lib,
-% snmpc_mib_gram,
-% snmpc_mib_to_hrl,
-% snmpc_misc,
-% snmpc_tok,
+ snmpc,
+ snmpc_lib,
+ snmpc_mib_gram,
+ snmpc_mib_to_hrl,
+ snmpc_misc,
+ snmpc_tok,
%% Application modules
snmp,
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index ca61782639..db09ec3dc5 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -8,6 +8,10 @@
%% {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
%% {add_module, snmpm_net_if_mt}
[
+ {<<"5\\.2\\.4">>,
+ [{load_module, snmp, soft_purge, soft_purge, []},
+ {load_module, snmpc_lib, soft_purge, soft_purge, []},
+ {load_module, snmpc_mib_gram, soft_purge, soft_purge, []}]},
{<<"5\\..*">>, [{restart_application, snmp}]},
{<<"4\\..*">>, [{restart_application, snmp}]}
],
@@ -17,6 +21,10 @@
%% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
[
+ {<<"5\\.2\\.4">>,
+ [{load_module, snmp, soft_purge, soft_purge, []},
+ {load_module, snmpc_lib, soft_purge, soft_purge, []},
+ {load_module, snmpc_mib_gram, soft_purge, soft_purge, []}]},
{<<"5\\..*">>, [{restart_application, snmp}]},
{<<"4\\..*">>, [{restart_application, snmp}]}
]
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index df3933ea01..8a736f688b 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -573,9 +573,16 @@ print_mod_info(Prefix, {Module, Info}) ->
CompDate =
case key1search(compile_time, Info) of
{value, {Year, Month, Day, Hour, Min, Sec}} ->
- lists:flatten(
- io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
- [Year, Month, Day, Hour, Min, Sec]));
+ io_lib:format(
+ "~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
+ [Year, Month, Day, Hour, Min, Sec]);
+ _ ->
+ "Not found"
+ end,
+ Digest =
+ case key1search(md5, Info) of
+ {value, MD5} when is_binary(MD5) ->
+ [io_lib:format("~2.16.0b", [Byte]) || <<Byte>> <= MD5];
_ ->
"Not found"
end,
@@ -583,12 +590,14 @@ print_mod_info(Prefix, {Module, Info}) ->
"~s Vsn: ~s~n"
"~s App vsn: ~s~n"
"~s Compiler ver: ~s~n"
- "~s Compile time: ~s~n",
+ "~s Compile time: ~s~n"
+ "~s MD5 digest: ~s~n",
[Prefix, Module,
Prefix, Vsn,
Prefix, AppVsn,
- Prefix, CompVer,
- Prefix, CompDate]),
+ Prefix, CompVer,
+ Prefix, CompDate,
+ Prefix, Digest]),
ok.
key1search(Key, Vals) ->
@@ -617,7 +626,7 @@ versions1() ->
Error ->
Error
end.
-
+
versions2() ->
case ms2() of
{ok, Mods} ->
@@ -625,25 +634,56 @@ versions2() ->
Error ->
Error
end.
-
+
version_info(Mods) ->
SysInfo = sys_info(),
OsInfo = os_info(),
ModInfo = [mod_version_info(Mod) || Mod <- Mods],
[{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}].
-
+
mod_version_info(Mod) ->
Info = Mod:module_info(),
- {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info),
- {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr),
- {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr),
- {value, {compile, Comp}} = lists:keysearch(compile, 1, Info),
- {value, {version, Ver}} = lists:keysearch(version, 1, Comp),
- {value, {time, Time}} = lists:keysearch(time, 1, Comp),
- {Mod, [{vsn, Vsn},
- {app_vsn, AppVsn},
- {compiler_version, Ver},
- {compile_time, Time}]}.
+ {Mod,
+ case key1search(attributes, Info) of
+ {value, Attr} ->
+ case key1search(vsn, Attr) of
+ {value, [Vsn]} ->
+ [{vsn, Vsn}];
+ not_found ->
+ []
+ end ++
+ case key1search(app_vsn, Attr) of
+ {value, AppVsn} ->
+ [{app_vsn, AppVsn}];
+ not_found ->
+ []
+ end;
+ not_found ->
+ []
+ end ++
+ case key1search(compile, Info) of
+ {value, Comp} ->
+ case key1search(version, Comp) of
+ {value, Ver} ->
+ [{compiler_version, Ver}];
+ not_found ->
+ []
+ end ++
+ case key1search(time, Comp) of
+ {value, Ver} ->
+ [{compile_time, Ver}];
+ not_found ->
+ []
+ end;
+ not_found ->
+ []
+ end ++
+ case key1search(md5, Info) of
+ {value, Bin} ->
+ [{md5, Bin}];
+ not_found ->
+ []
+ end}.
sys_info() ->
SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index db1f9ee61b..416353508e 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,7 +64,7 @@ compile(Input, _Output, Options) ->
{ok, _} ->
ok;
{error, Reason} ->
- io:format("~p", [Reason]),
+ io:format("~tp", [Reason]),
error
end.
@@ -126,7 +126,14 @@ compile(FileName) ->
%%----------------------------------------------------------------------
compile(FileName, Options) when is_list(FileName) ->
- true = snmpc_misc:is_string(FileName),
+ case snmpc_misc:check_file(FileName) of
+ true ->
+ compile_1(FileName, Options);
+ false ->
+ {error, {invalid_file, FileName}}
+ end.
+
+compile_1(FileName, Options) ->
DefOpts = [{deprecated, true},
{group_check, true},
{i, ["./"]},
diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl
index 51690b6e7e..33ddd78308 100644
--- a/lib/snmp/src/compile/snmpc_lib.erl
+++ b/lib/snmp/src/compile/snmpc_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@ make_ASN1type({{type_with_size,Type,{range,Lo,Hi}},Line}) ->
print_error("Undefined type '~w'",[Type],Line),
guess_string_type()
end;
-make_ASN1type({{integer_with_enum,Type,Enums},Line}) ->
+make_ASN1type({{type_with_enum,Type,Enums},Line}) ->
case lookup_vartype(Type) of
{value,ASN1type} -> ASN1type#asn1_type{assocList = [{enums, Enums}]};
false ->
diff --git a/lib/snmp/src/compile/snmpc_mib_gram.yrl b/lib/snmp/src/compile/snmpc_mib_gram.yrl
index 743c3a6550..14a668127e 100644
--- a/lib/snmp/src/compile/snmpc_mib_gram.yrl
+++ b/lib/snmp/src/compile/snmpc_mib_gram.yrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -387,10 +387,12 @@ syntax -> type : {{type, cat('$1')},line_of('$1')}.
syntax -> type size : {{type_with_size, cat('$1'), '$2'},line_of('$1')}.
syntax -> usertype size : {{type_with_size,val('$1'), '$2'},line_of('$1')}.
syntax -> 'INTEGER' '{' namedbits '}' :
- {{integer_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
+ {{type_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
syntax -> 'BITS' '{' namedbits '}' :
ensure_ver(2,'$1'),
{{bits, '$3'}, line_of('$1')}.
+syntax -> usertype '{' namedbits '}' :
+ {{type_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
syntax -> 'SEQUENCE' 'OF' usertype :
{{sequence_of,val('$3')},line_of('$1')}.
diff --git a/lib/snmp/src/compile/snmpc_misc.erl b/lib/snmp/src/compile/snmpc_misc.erl
index 933d629746..312074f2e7 100644
--- a/lib/snmp/src/compile/snmpc_misc.erl
+++ b/lib/snmp/src/compile/snmpc_misc.erl
@@ -29,7 +29,7 @@
bits_to_int/2,
ensure_trailing_dir_delimiter/1,
foreach/3,
- is_string/1,
+ check_file/1,
read_mib/1,
read_noexit/2,
strip_extension_from_filename/2,
@@ -86,21 +86,21 @@ to_upper([C|Cs]) -> [C|to_upper(Cs)];
to_upper([]) -> [].
-is_string([]) -> true;
-is_string([Tkn | Str])
- when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) ->
- is_string(Str);
-is_string(_) -> false.
-
-
+check_file(FileName) ->
+ case filename:extension(FileName) of
+ ".mib" ->
+ filelib:is_regular(FileName);
+ _ ->
+ filelib:is_regular(FileName ++ ".mib")
+ end.
+
+
foreach(Function, ExtraArgs, [H | T]) ->
apply(Function, [H | ExtraArgs]),
foreach(Function, ExtraArgs, T);
foreach(_Function, _ExtraArgs, []) ->
true.
-
-
%%----------------------------------------------------------------------
%% Returns: {ok, Mib}|{error, Reason}
%% The reason for having the function if this module is:
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 87539f88f7..0f54e67c65 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -31,6 +31,7 @@ SUITE_MODULES = \
snmp_agent_mibs_test \
snmp_agent_nfilter_test \
snmp_agent_test \
+ snmp_agent_conf_test \
snmp_agent_test_lib \
snmp_manager_config_test \
snmp_manager_user \
diff --git a/lib/snmp/test/snmp_SUITE.erl b/lib/snmp/test/snmp_SUITE.erl
index 3b9219739b..05bd86253b 100644
--- a/lib/snmp/test/snmp_SUITE.erl
+++ b/lib/snmp/test/snmp_SUITE.erl
@@ -81,7 +81,8 @@ groups() ->
{group, note_store_test}]},
{agent, [], [{group, mibs_test},
{group, nfilter_test},
- {group, agent_test},
+ {group, agent_test},
+ {group, agent_conf_test},
{group, snmpnet_test}]},
{manager, [], [{group, manager_config_test},
{group, manager_user_test},
@@ -97,6 +98,7 @@ groups() ->
{mibs_test, [], [{snmp_agent_mibs_test, all}]},
{nfilter_test, [], [{snmp_agent_nfilter_test, all}]},
{agent_test, [], [{snmp_agent_test, all}]},
+ {agent_conf_test, [], [{snmp_agent_conf_test, all}]},
{snmpnet_test, [], [{snmp_to_snmpnet_SUITE, all}]},
{manager_config_test, [], [{snmp_manager_config_test, all}]},
{manager_user_test, [], [{snmp_manager_user_test, all}]},
diff --git a/lib/snmp/test/snmp_agent_conf_test.erl b/lib/snmp/test/snmp_agent_conf_test.erl
new file mode 100644
index 0000000000..0a22bd47d1
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_conf_test.erl
@@ -0,0 +1,210 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_agent_conf_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+%-include_lib("test_server/include/test_server.hrl").
+%-include("snmp_test_lib.hrl").
+-include_lib("common_test/include/ct.hrl").
+
+-export([
+ all/0,
+ groups/0,
+ init_per_suite/1,
+ end_per_suite/1,
+
+ check_agent/1,
+ check_usm/1,
+ check_vacm/1
+ ]).
+
+
+all() -> [
+ check_agent,
+ check_usm,
+ check_vacm
+ ].
+
+
+groups() ->
+ [].
+
+
+init_per_suite(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ PrivSubdir = filename:join(PrivDir, "snmp_agent_conf_test"),
+ ok = filelib:ensure_dir(filename:join(PrivSubdir, "dummy")),
+ [{priv_subdir, PrivSubdir} | Config].
+
+end_per_suite(_Config) ->
+ ok.
+
+%%======================================================================
+%% Test data
+%%======================================================================
+
+engine_ids() -> [
+ "plain eid",
+ "here\"eid",
+ "comes\neid",
+ "trouble\0eid",
+ binary_to_list(<<"中国引擎标识符"/utf8>>)
+].
+
+snmp_admin_strings() -> [
+ "plain string",
+ "heres\"eid",
+ "trouble\neid",
+ binary_to_list(<<"中国引擎标识符"/utf8>>)
+].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+
+check_agent(Config) ->
+ Dir = ?config(priv_subdir, Config),
+ lists:foreach(
+ fun(EngineId) -> check_agent_by_engineid(Dir, EngineId) end,
+ engine_ids()
+ ),
+ ok.
+
+check_agent_by_engineid(Dir, EngineId) ->
+ WEntries = [
+ snmpa_conf:agent_entry(intAgentIpAddress, {0,0,0,0}),
+ snmpa_conf:agent_entry(intAgentUDPPort, 161),
+ snmpa_conf:agent_entry(snmpEngineMaxMessageSize, 484),
+ snmpa_conf:agent_entry(snmpEngineID, EngineId)
+ ],
+
+ ok = snmpa_conf:write_agent_config(Dir, WEntries),
+ {ok, REntries} = snmpa_conf:read_agent_config(Dir),
+
+ true = is_subset(WEntries, REntries),
+ ok.
+
+%%======================================================================
+
+check_usm(Config) ->
+ Dir = ?config(priv_subdir, Config),
+ EngineId = hd(engine_ids()),
+ UserName = hd(snmp_admin_strings()),
+ SecName = hd(snmp_admin_strings()),
+
+ %% vary engine id
+ lists:foreach(
+ fun(EngineId_) -> check_usm_by_params(Dir, EngineId_, UserName, SecName) end,
+ engine_ids()
+ ),
+
+ %% vary user name
+ lists:foreach(
+ fun(UserName_) -> check_usm_by_params(Dir, EngineId, UserName_, SecName) end,
+ snmp_admin_strings()
+ ),
+
+ %% vary sec name
+ lists:foreach(
+ fun(SecName_) -> check_usm_by_params(Dir, EngineId, UserName, SecName_) end,
+ snmp_admin_strings()
+ ),
+
+ ok.
+
+check_usm_by_params(Dir, EngineId, UserName, SecName) ->
+ WEntries = [
+ snmpa_conf:usm_entry(
+ EngineId,
+ UserName,
+ SecName,
+ zeroDotZero,
+ usmNoAuthProtocol, % authproto
+ "", "",
+ usmNoPrivProtocol, % privproto
+ "", "", "",
+ [], %AuthKey
+ []) %PrivKey
+ ],
+
+ ok = snmpa_conf:write_usm_config(Dir, WEntries),
+ {ok, REntries} = snmpa_conf:read_usm_config(Dir),
+
+ true = is_subset(WEntries, REntries),
+ ok.
+
+%%======================================================================
+
+check_vacm(Config) ->
+ Dir = ?config(priv_subdir, Config),
+
+ %% vary sec name
+ lists:foreach(
+ fun(SecName_) -> check_vacm_by_params(Dir, SecName_) end,
+ snmp_admin_strings()
+ ),
+
+ ok.
+
+
+check_vacm_by_params(Dir, SecName) ->
+ WEntries = [
+ %% SecModel, SecName, GroupName
+ snmpa_conf:vacm_s2g_entry(usm, SecName, SecName),
+ %% GroupName,Prefix,SecModel,SecLevel,Match,ReadView,WriteView,NotifyView
+ snmpa_conf:vacm_acc_entry(SecName, "", any, noAuthNoPriv, exact, "all", "all", "all")
+ ],
+
+ ok = snmpa_conf:write_vacm_config(Dir, WEntries),
+ {ok, REntries} = snmpa_conf:read_vacm_config(Dir),
+
+ true = is_subset(WEntries, REntries),
+ ok.
+
+
+
+%%======================================================================
+
+
+%% additional tests needed:
+% check_context()
+% check_community()
+% check_standard()
+% check_target_addr()
+% check_target_params()
+% check_notify()
+
+
+%%======================================================================
+%% Local utility functions
+%%======================================================================
+
+is_subset(List1, List2) ->
+ io:format("Check ~p is subset of ~p\n", [List1, List2]),
+ sets:is_subset(
+ sets:from_list(List1),
+ sets:from_list(List2)
+ ).
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 8ae495bb1b..3c1a6f2afd 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -647,22 +647,22 @@ init_per_group(GroupName, Config) ->
snmp_test_lib:init_group_top_dir(GroupName, Config).
init_per_group_ipv6(GroupName, Config, Init) ->
+ {ok, Hostname0} = inet:gethostname(),
case ct:require(ipv6_hosts) of
ok ->
- case gen_udp:open(0, [inet6]) of
- {ok, S} ->
- ok = gen_udp:close(S),
- Init(
- snmp_test_lib:init_group_top_dir(
- GroupName,
- [{ipfamily, inet6},
- {ip, ?LOCALHOST(inet6)}
- | lists:keydelete(ip, 1, Config)]));
- {error, _} ->
- {skip, "Host seems to not support IPv6"}
- end;
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
+ Init(
+ snmp_test_lib:init_group_top_dir(
+ GroupName,
+ [{ipfamily, inet6},
+ {ip, ?LOCALHOST(inet6)}
+ | lists:keydelete(ip, 1, Config)]));
+ false ->
+ {skip, "Host does not support IPV6"}
+ end;
_ ->
- {skip, "Host does not support IPV6"}
+ {skip, "Test config ipv6_hosts is missing"}
end.
end_per_group(all_tcs, Config) ->
diff --git a/lib/snmp/test/snmp_app_test.erl b/lib/snmp/test/snmp_app_test.erl
index 6e7e85d3b4..5e69866f9a 100644
--- a/lib/snmp/test/snmp_app_test.erl
+++ b/lib/snmp/test/snmp_app_test.erl
@@ -23,366 +23,29 @@
%%----------------------------------------------------------------------
-module(snmp_app_test).
--export([
- all/0, groups/0,
- init_per_group/2, end_per_group/2,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
- fields/1,
- modules/1,
- exportall/1,
- app_depend/1,
-
- start_and_stop_empty/1,
- start_and_stop_with_agent/1,
- start_and_stop_with_manager/1,
- start_and_stop_with_agent_and_manager/1,
- start_epmty_and_then_agent_and_manager_and_stop/1,
- start_with_agent_and_then_manager_and_stop/1,
- start_with_manager_and_then_agent_and_stop/1
- ]).
-
-
--include_lib("kernel/include/file.hrl").
-include_lib("common_test/include/ct.hrl").
--include("snmp_test_lib.hrl").
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
all() ->
- Cases =
- [
- fields,
- modules,
- exportall,
- app_depend,
- {group, start_and_stop}
- ],
- Cases.
-
-groups() ->
- [{start_and_stop, [],
- [start_and_stop_empty,
- start_and_stop_with_agent,
- start_and_stop_with_manager,
- start_and_stop_with_agent_and_manager,
- start_epmty_and_then_agent_and_manager_and_stop,
- start_with_agent_and_then_manager_and_stop,
- start_with_manager_and_then_agent_and_stop]}].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(Config) when is_list(Config) ->
- ?DISPLAY_SUITE_INFO(),
-
- %% Note that part of this stuff (the suite top dir creation)
- %% may already be done (if we run the entire snmp suite).
-
- PrivDir = ?config(priv_dir, Config),
- TopDir = filename:join(PrivDir, app),
- case file:make_dir(TopDir) of
- ok ->
- ok;
- {error, eexist} ->
- ok;
- Error ->
- fail({failed_creating_subsuite_top_dir, Error})
- end,
- AppFile =
- case is_app() of
- {ok, File} ->
- io:format("File: ~n~p~n", [File]),
- snmp:print_version_info(),
- File;
- {error, Reason} ->
- fail(Reason)
- end,
- [{app_topdir, TopDir}, {app_file, AppFile} | Config].
-
-
-is_app() ->
- is_app(?APPLICATION).
-
-is_app(App) ->
- LibDir = code:lib_dir(App),
- File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
- case file:consult(File) of
- {ok, [{application, App, AppFile}]} ->
- {ok, AppFile};
- Error ->
- {error, {invalid_format, Error}}
- end.
-
-end_per_suite(suite) -> [];
-end_per_suite(doc) -> [];
-end_per_suite(Config) when is_list(Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% Test server callbacks
-init_per_testcase(_Case, Config) ->
- Config.
-
-end_per_testcase(_Case, Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fields(suite) ->
- [];
-fields(doc) ->
- [];
-fields(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Fields = [vsn, description, modules, registered, applications],
- case check_fields(Fields, AppFile, []) of
- [] ->
- ok;
- Missing ->
- fail({missing_fields, Missing})
- end.
-
-check_fields([], _AppFile, Missing) ->
- Missing;
-check_fields([Field|Fields], AppFile, Missing) ->
- check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
-
-check_field(Name, AppFile, Missing) ->
- io:format("checking field: ~p~n", [Name]),
- case lists:keymember(Name, 1, AppFile) of
- true ->
- Missing;
- false ->
- [Name|Missing]
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-modules(suite) ->
- [];
-modules(doc) ->
- [];
-modules(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- EbinList = get_ebin_mods(snmp),
- case missing_modules(Mods, EbinList, []) of
- [] ->
- ok;
- Missing ->
- fail({missing_modules, Missing})
- end,
- Allowed = [snmpc,
- snmpc_lib,
- snmpc_misc,
- snmpc_mib_gram,
- snmpc_mib_to_hrl,
- snmpc_tok],
- case extra_modules(Mods, EbinList, Allowed, []) of
- [] ->
- ok;
- Extra ->
- fail({extra_modules, Extra})
- end,
- {ok, Mods}.
-
-get_ebin_mods(App) ->
- LibDir = code:lib_dir(App),
- EbinDir = filename:join([LibDir,"ebin"]),
- {ok, Files0} = file:list_dir(EbinDir),
- Files1 = [lists:reverse(File) || File <- Files0],
- [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
-
-
-missing_modules([], _Ebins, Missing) ->
- Missing;
-missing_modules([Mod|Mods], Ebins, Missing) ->
- case lists:member(Mod, Ebins) of
- true ->
- missing_modules(Mods, Ebins, Missing);
- false ->
- io:format("missing module: ~p~n", [Mod]),
- missing_modules(Mods, Ebins, [Mod|Missing])
- end.
-
-
-extra_modules(_Mods, [], Allowed, Extra) ->
- Extra--Allowed;
-extra_modules(Mods, [Mod|Ebins], Allowed, Extra) ->
- case lists:member(Mod, Mods) of
- true ->
- extra_modules(Mods, Ebins, Allowed, Extra);
- false ->
- io:format("superfluous module: ~p~n", [Mod]),
- extra_modules(Mods, Ebins, Allowed, [Mod|Extra])
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-exportall(suite) ->
- [];
-exportall(doc) ->
- [];
-exportall(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- check_export_all(Mods).
-
-
-check_export_all([]) ->
- ok;
-check_export_all([Mod|Mods]) ->
- case (catch apply(Mod, module_info, [compile])) of
- {'EXIT', {undef, _}} ->
- check_export_all(Mods);
- O ->
- case lists:keysearch(options, 1, O) of
- false ->
- check_export_all(Mods);
- {value, {options, List}} ->
- case lists:member(export_all, List) of
- true ->
- fail({export_all, Mod});
- false ->
- check_export_all(Mods)
- end
- end
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-app_depend(suite) ->
- [];
-app_depend(doc) ->
- [];
-app_depend(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Apps = key1search(applications, AppFile),
- check_apps(Apps).
-
-
-check_apps([]) ->
- ok;
-check_apps([App|Apps]) ->
- case is_app(App) of
- {ok, _} ->
- check_apps(Apps);
- Error ->
- throw({error, {missing_app, {App, Error}}})
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_and_stop_empty(suite) ->
- [];
-start_and_stop_empty(doc) ->
- ["Start and stop the application empty (no configured components)"];
-start_and_stop_empty(Config) when is_list(Config) ->
- ?line false = ?IS_SNMP_RUNNING(),
-
- ?line ok = snmp:start(),
-
- ?line true = ?IS_SNMP_RUNNING(),
-
- ?line ok = snmp:stop(),
-
- ?line false = ?IS_SNMP_RUNNING(),
-
- ok.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_and_stop_with_agent(suite) ->
- [];
-start_and_stop_with_agent(doc) ->
- ["Start and stop the application with the agent pre-configured"];
-start_and_stop_with_agent(Config) when is_list(Config) ->
- ?SKIP(not_implemented_yet).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_and_stop_with_manager(suite) ->
- [];
-start_and_stop_with_manager(doc) ->
- ["Start and stop the application with the manager pre-configured"];
-start_and_stop_with_manager(Config) when is_list(Config) ->
- ?SKIP(not_implemented_yet).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_and_stop_with_agent_and_manager(suite) ->
- [];
-start_and_stop_with_agent_and_manager(doc) ->
- ["Start and stop the application with both the agent "
- "and the manager pre-configured"];
-start_and_stop_with_agent_and_manager(Config) when is_list(Config) ->
- ?SKIP(not_implemented_yet).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_epmty_and_then_agent_and_manager_and_stop(suite) ->
- [];
-start_epmty_and_then_agent_and_manager_and_stop(doc) ->
- ["Start the application empty, then start the agent and then "
- "the manager and then stop the application"];
-start_epmty_and_then_agent_and_manager_and_stop(Config) when is_list(Config) ->
- ?SKIP(not_implemented_yet).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_with_agent_and_then_manager_and_stop(suite) ->
- [];
-start_with_agent_and_then_manager_and_stop(doc) ->
- ["Start the application with the agent pre-configured, "
- "then start the manager and then stop the application"];
-start_with_agent_and_then_manager_and_stop(Config) when is_list(Config) ->
- ?SKIP(not_implemented_yet).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-start_with_manager_and_then_agent_and_stop(suite) ->
- [];
-start_with_manager_and_then_agent_and_stop(doc) ->
- ["Start the application with the manager pre-configured, "
- "then start the agent and then stop the application"];
-start_with_manager_and_then_agent_and_stop(Config) when is_list(Config) ->
- ?SKIP(not_implemented_yet).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-fail(Reason) ->
- exit({suite_failed, Reason}).
-
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- undefined ->
- fail({not_found, Key, L});
- {value, {Key, Value}} ->
- Value
- end.
+ [
+ app,
+ appup
+ ].
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the snmp app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = test_server:app_test(snmp).
+%%--------------------------------------------------------------------
+appup() ->
+ [{doc, "Test that the snmp appup file is ok"}].
+appup(Config) when is_list(Config) ->
+ ok = test_server:appup_test(snmp).
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index 2c8851c2a7..9b3c2bfd2c 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -56,7 +56,8 @@
otp_8574/1,
otp_8595/1,
otp_10799/1,
- otp_10808/1
+ otp_10808/1,
+ otp_14145/1
]).
@@ -135,7 +136,8 @@ all() ->
].
groups() ->
- [{tickets, [], [otp_6150, otp_8574, otp_8595, otp_10799, otp_10808]}].
+ [{tickets, [],
+ [otp_6150, otp_8574, otp_8595, otp_10799, otp_10808, otp_14145]}].
init_per_group(_GroupName, Config) ->
Config.
@@ -431,6 +433,30 @@ otp_10808(Config) when is_list(Config) ->
%%======================================================================
+otp_14145(suite) ->
+ [];
+otp_14145(Config) when is_list(Config) ->
+ put(tname, otp10808),
+ p("starting with Config: ~p~n", [Config]),
+
+ Dir = ?config(case_top_dir, Config),
+ MibDir = ?config(mib_dir, Config),
+ MibName = "OTP14145-MIB",
+ MibFile = join(MibDir, MibName++".mib"),
+ ?line {ok, MibBin} =
+ snmpc:compile(MibFile, [{outdir, Dir},
+ {verbosity, trace},
+ {group_check, false},
+ module_compliance]),
+ p("Mib: ~n~p~n", [MibBin]),
+ MIB = read_mib(MibBin),
+ Oid = [1,3,6,1,2,1,67,4],
+ check_mib(MIB#mib.mes, Oid, undefined),
+ ok.
+
+
+%%======================================================================
+
augments_extra_info(suite) ->
[];
augments_extra_info(Config) when is_list(Config) ->
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index d17882e765..71f4017d8b 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -583,38 +583,38 @@ init_per_group(event_tests_mt = GroupName, Config) ->
GroupName,
[{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(ipv6_mt = GroupName, Config) ->
+ {ok, Hostname0} = inet:gethostname(),
case ct:require(ipv6_hosts) of
ok ->
- case gen_udp:open(0, [inet6]) of
- {ok, S} ->
- ok = gen_udp:close(S),
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
ipv6_init(
snmp_test_lib:init_group_top_dir(
GroupName,
[{manager_net_if_module, snmpm_net_if_mt}
| Config]));
- {error, _} ->
- {skip, "Host seems to not support IPv6"}
+ false ->
+ {skip, "Host does not support IPv6"}
end;
_ ->
- {skip, "Host does not support IPV6"}
+ {skip, "Test config ipv6_hosts is missing"}
end;
init_per_group(ipv6 = GroupName, Config) ->
+ {ok, Hostname0} = inet:gethostname(),
case ct:require(ipv6_hosts) of
ok ->
- case gen_udp:open(0, [inet6]) of
- {ok, S} ->
- ok = gen_udp:close(S),
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
- {error, _} ->
- {skip, "Host seems to not support IPv6"}
+ false ->
+ {skip, "Host does not support IPv6"}
end;
_ ->
- {skip, "Host does not support IPV6"}
+ {skip, "Test config ipv6_hosts is missing"}
end;
init_per_group(GroupName, Config) ->
snmp_test_lib:init_group_top_dir(GroupName, Config).
-
+
end_per_group(_GroupName, Config) ->
%% Do we really need to do this?
lists:keydelete(snmp_group_top_dir, 1, Config).
diff --git a/lib/snmp/test/snmp_test_data/OTP14145-MIB.mib b/lib/snmp/test/snmp_test_data/OTP14145-MIB.mib
new file mode 100644
index 0000000000..f29c65c4c2
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/OTP14145-MIB.mib
@@ -0,0 +1,44 @@
+OTP14145-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE,
+ mib-2 FROM SNMPv2-SMI
+ InetAddressType, InetAddress FROM INET-ADDRESS-MIB
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
+
+testMibId MODULE-IDENTITY
+ LAST-UPDATED "200608210000Z" -- 21 August 2006
+ ORGANIZATION "a"
+ CONTACT-INFO "a"
+ DESCRIPTION "a"
+ REVISION "200608210000Z" -- 21 August 2006
+ DESCRIPTION "a"
+ ::= { mib-2 67 }
+
+testObj OBJECT-TYPE
+ SYNTAX InetAddressType
+ -- SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "a"
+ ::= { testMibId 2 }
+
+testObjId OBJECT IDENTIFIER ::= { testMibId 3 }
+
+testMibCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION "a"
+ MODULE
+ OBJECT testObj
+ SYNTAX InetAddressType { ipv4(1), ipv6(2) }
+ -- SYNTAX InetAddress ( SIZE(4|16) )
+ DESCRIPTION "a"
+ ::= { testMibId 4 }
+
+testObjGroup OBJECT-GROUP
+ OBJECTS { testObj }
+ STATUS current
+ DESCRIPTION "a"
+ ::= { testObjId 1 }
+
+END
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index ac9e37bc8b..24c14d86ea 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -121,14 +121,14 @@ init_per_group(_, Config) ->
Config.
init_per_group_ipv6(Families, Config) ->
+ {ok, Hostname0} = inet:gethostname(),
case ct:require(ipv6_hosts) of
ok ->
- case gen_udp:open(0, [inet6]) of
- {ok, S} ->
- ok = gen_udp:close(S),
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
init_per_group_ip(Families, Config);
- {error, _} ->
- {skip, "Host seems to not support IPv6"}
+ false ->
+ {skip, "Host does not support IPv6"}
end;
_ ->
{skip, "Test config ipv6_hosts is missing"}
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index f95b428290..30b8ee1124 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.2.3
+SNMP_VSN = 5.2.5
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml
index ca84528f3d..b7a73e2597 100644
--- a/lib/ssh/doc/src/introduction.xml
+++ b/lib/ssh/doc/src/introduction.xml
@@ -195,8 +195,6 @@
Transport Layer Protocol</item>
<item><url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url> -
Connection Protocol</item>
- <item><url href="http://www.ietf.org/rfc/rfc4255.txt">RFC 4255</url> -
- Key Fingerprints</item>
<item><url href="http://www.ietf.org/rfc/rfc4344.txt">RFC 4344</url> -
Transport Layer Encryption Modes</item>
<item><url href="http://www.ietf.org/rfc/rfc4716.txt">RFC 4716</url> -
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index fd15c334a3..6e98cab129 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,377 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.4.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix rare spurios shutdowns of ssh servers when receiveing
+ <c>{'EXIT',_,normal}</c> messages.</p>
+ <p>
+ Own Id: OTP-15018</p>
+ </item>
+ <item>
+ <p>
+ Host key hash erroneously calculated for clients
+ following draft-00 of RFC 4419, for example PuTTY</p>
+ <p>
+ Own Id: OTP-15064</p>
+ </item>
+ <item>
+ <p>
+ Renegotiation could fail in some states</p>
+ <p>
+ Own Id: OTP-15066</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An ssh_sftp server (running version 6) could fail if it
+ is told to remove a file which in fact is a directory.</p>
+ <p>
+ Own Id: OTP-15004</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4.2.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Default exec is disabled when a user-defined shell is
+ enabled.</p>
+ <p>
+ Own Id: OTP-14881</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Trailing white space was removed at end of the
+ hello-string. This caused interoperability problems with
+ some other ssh-implementations (e.g OpenSSH 7.3p1 on
+ Solaris 11)</p>
+ <p>
+ Own Id: OTP-14763 Aux Id: ERIERL-74 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ssh:daemon_info/1 crashed if the listening IP was not
+ 'any'</p>
+ <p>
+ Own Id: OTP-14298 Aux Id: seq13294 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug when opening connections. If the tcp setup
+ failed, that would in some cases not result in an error
+ return value.</p>
+ <p>
+ Own Id: OTP-14108</p>
+ </item>
+ <item>
+ <p>
+ Reduce information leakage in case of decryption errors.</p>
+ <p>
+ Own Id: OTP-14109</p>
+ </item>
+ <item>
+ <p>
+ The key exchange algorithm
+ diffie-hellman-group-exchange-sha* has a server-option
+ <c>{dh_gex_limits,{Min,Max}}</c>. There was a hostkey
+ signature validation error on the client side if the
+ option was used and the <c>Min</c> or the <c>Max</c>
+ differed from the corresponding values obtained from the
+ client.</p>
+ <p>
+ This bug is now corrected.</p>
+ <p>
+ Own Id: OTP-14166</p>
+ </item>
+ <item>
+ <p>
+ The sftpd server now correctly uses <c>root_dir</c> and
+ <c>cwd</c> when resolving file paths if both are
+ provided. The <c>cwd</c> handling is also corrected.</p>
+ <p>
+ Thanks to kape1395!</p>
+ <p>
+ Own Id: OTP-14225 Aux Id: PR-1331, PR-1335 </p>
+ </item>
+ <item>
+ <p>
+ Ssh_cli used a function that does not handle non-utf8
+ unicode correctly.</p>
+ <p>
+ Own Id: OTP-14230 Aux Id: ERL-364 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The implementation of the key exchange algorithms
+ diffie-hellman-group-exchange-sha* are optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest)
+ group size.</p>
+ <p>
+ Own Id: OTP-14169 Aux Id: seq-13261 </p>
+ </item>
+ <item>
+ <p>
+ The ssh host key fingerprint generation now also takes a
+ list of algorithms and returns a list of corresponding
+ fingerprints. See
+ <c>public_key:ssh_hostkey_fingerprint/2</c> and the
+ option <c>silently_accept_hosts</c> in
+ <c>ssh:connect</c>.</p>
+ <p>
+ Own Id: OTP-14223</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A file read with an sftp client could loose data if the
+ packet_size is set to larger than 64k. This is corrected
+ now in such a way that the packet_size is silently
+ lowered if there is a risk for data loss.</p>
+ <p>
+ Own Id: OTP-13857 Aux Id: ERL-238, OTP-13858 </p>
+ </item>
+ <item>
+ <p>
+ When user defined SSH shell REPL process exits with
+ reason normal, the SSH channel callback module should
+ report successful exit status to the SSH client. This
+ provides simple way for SSH clients to check for
+ successful completion of executed commands. (Thanks to
+ isvilen)</p>
+ <p>
+ Own Id: OTP-13905 Aux Id: PR-1173 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Extended the option <c>silently_accept_hosts</c> for
+ <c>ssh:connect</c> to make it possible for the client to
+ check the SSH host key fingerprint string. Se the
+ reference manual for SSH.</p>
+ <p>
+ Own Id: OTP-13887 Aux Id: OTP-13888 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.3.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Re-negotiation problems with OpenSSH client solved.</p>
+ <p>
+ Own Id: OTP-13972</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If a client illegaly sends an info-line and then
+ immediatly closes the TCP-connection, a badmatch
+ exception was raised.</p>
+ <p>
+ Own Id: OTP-13966</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.3.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Intermittent ssh ERROR REPORT mentioning
+ nonblocking_sender</p>
+ <p>
+ Own Id: OTP-13953 Aux Id: seq13199 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Handle all possible exit values that should be
+ interpreted as {error, closed}. Failing to do so could
+ lead to unexpected crashes for users of the ssh
+ application.</p>
+ <p>
+ Own Id: OTP-13932 Aux Id: seq13189 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Upgrade of an established client connection could crash
+ because the ssh client supervisors children had wrong
+ type. This is fixed now.</p>
+ <p>
+ Own Id: OTP-13782 Aux Id: seq13158 </p>
+ </item>
+ <item>
+ <p>
+ Partly checks the public key early in public key
+ authorization</p>
+ <p>
+ Own Id: OTP-13847 Aux Id:
+ defensics-ssh3.1.0-190243,205277,219318 </p>
+ </item>
+ <item>
+ <p>
+ Corrected handling of SHA for ECDSA (Elliptic curve
+ public keys)</p>
+ <p>
+ Own Id: OTP-13850 Aux Id: defensics-ssh3.1.0-214168 </p>
+ </item>
+ <item>
+ <p>
+ Problems found by test suites as well as by
+ Codenomicon/Defensics fixed: - reduce max random padding
+ to 15 bytes (Codenomicon/Defensics) - inclomplete pdu
+ handling (Codenomicon/Defensics) - badmatch in test suite
+ - non-blocking send fixes deadlock in
+ ssh_connection_SUITE:interrupted_send</p>
+ <p>
+ Own Id: OTP-13854</p>
+ </item>
+ <item>
+ <p>
+ Caller is now notified when a tcp close is received.</p>
+ <p>
+ Own Id: OTP-13859 Aux Id: seq13177 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Use application:ensure_all_started/2 instead of
+ hard-coding deps</p>
+ <p>
+ Own Id: OTP-13843 Aux Id: PR-1147 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ SSH client does not any longer retry a bad password given
+ as option to ssh:connect et al.</p>
+ <p>
+ Own Id: OTP-13674 Aux Id: TR-HU92273 </p>
+ </item>
+ <item>
+ <p>
+ Removed possible hanging risk for a certain timing
+ sequence when communicating client and server executes on
+ the same node.</p>
+ <p>
+ Own Id: OTP-13715</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.3</title>
<section><title>Improvements and New Features</title>
@@ -108,6 +479,22 @@
</section>
+<section><title>Ssh 4.2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ SSH client does not any longer retry a bad password given
+ as option to ssh:connect et al.</p>
+ <p>
+ Own Id: OTP-13674 Aux Id: TR-HU92273 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index e6c54d27bf..604b9f5bbb 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2015</year>
+ <year>2004</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -153,7 +153,7 @@
<item>
<p>IP version to use.</p>
</item>
- <tag><c><![CDATA[{user_dir, string()}]]></c></tag>
+ <tag><marker id="opt_user_dir"></marker><c><![CDATA[{user_dir, string()}]]></c></tag>
<item>
<p>Sets the user directory, that is, the directory containing
<c>ssh</c> configuration files for the user, such as
@@ -175,12 +175,48 @@
supplied with this option.
</p>
</item>
- <tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag>
+ <tag>
+ <c><![CDATA[{silently_accept_hosts, boolean()}]]></c> <br/>
+ <c><![CDATA[{silently_accept_hosts, CallbackFun}]]></c> <br/>
+ <c><![CDATA[{silently_accept_hosts, {HashAlgoSpec, CallbackFun} }]]></c> <br/>
+ <br/>
+ <c><![CDATA[HashAlgoSpec = crypto:digest_type() | [ crypto:digest_type() ] ]]></c><br/>
+ <c><![CDATA[CallbackFun = fun(PeerName, FingerPrint) -> boolean()]]></c><br/>
+ <c><![CDATA[PeerName = string()]]></c><br/>
+ <c><![CDATA[FingerPrint = string() | [ string() ] ]]></c>
+ </tag>
<item>
- <p>When <c>true</c>, hosts are added to the
- file <c><![CDATA[known_hosts]]></c> without asking the user.
- Defaults to <c>false</c>.
- </p>
+ <p>This option guides the <c>connect</c> function how to act when the connected server presents a Host
+ Key that the client has not seen before. The default is to ask the user with a question on stdio of whether to
+ accept or reject the new Host Key.
+ See also the option <seealso marker="#opt_user_dir"><c>user_dir</c></seealso>
+ for the path to the file <c>known_hosts</c> where previously accepted Host Keys are recorded.
+ </p>
+ <p>The option can be given in three different forms as seen above:</p>
+ <list>
+ <item>The value is a <c>boolean()</c>. The value <c>true</c> will make the client accept any unknown
+ Host Key without any user interaction. The value <c>false</c> keeps the default behaviour of asking the
+ the user on stdio.
+ </item>
+ <item>A <c>CallbackFun</c> will be called and the boolean return value <c>true</c> will make the client
+ accept the Host Key. A return value of <c>false</c> will make the client to reject the Host Key and therefore
+ also the connection will be closed. The arguments to the fun are:
+ <list type="bulleted">
+ <item><c>PeerName</c> - a string with the name or address of the remote host.</item>
+ <item><c>FingerPrint</c> - the fingerprint of the Host Key as
+ <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-1">public_key:ssh_hostkey_fingerprint/1</seealso>
+ calculates it.
+ </item>
+ </list>
+ </item>
+ <item>A tuple <c>{HashAlgoSpec, CallbackFun}</c>. The <c>HashAlgoSpec</c> specifies which hash algorithm
+ shall be used to calculate the fingerprint used in the call of the <c>CallbackFun</c>. The <c>HashALgoSpec</c>
+ is either an atom or a list of atoms as the first argument in
+ <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-2">public_key:ssh_hostkey_fingerprint/2</seealso>.
+ If it is a list of hash algorithm names, the <c>FingerPrint</c> argument in the <c>CallbackFun</c> will be
+ a list of fingerprints in the same order as the corresponding name in the <c>HashAlgoSpec</c> list.
+ </item>
+ </list>
</item>
<tag><c><![CDATA[{user_interaction, boolean()}]]></c></tag>
<item>
@@ -190,7 +226,7 @@
supplying a password. Defaults to <c>true</c>.
Even if user interaction is allowed it can be
suppressed by other options, such as <c>silently_accept_hosts</c>
- and <c>password</c>. However, those optins are not always desirable
+ and <c>password</c>. However, those options are not always desirable
to use from a security point of view.</p>
</item>
@@ -756,7 +792,7 @@
<p>Utility function that starts the applications <c>crypto</c>, <c>public_key</c>,
and <c>ssh</c>. Default type is <c>temporary</c>.
For more information, see the <seealso marker="kernel:application">application(3)</seealso>
- manual page in <c>kernel</c>.</p>
+ manual page in Kernel.</p>
</desc>
</func>
@@ -769,7 +805,7 @@
<desc>
<p>Stops the <c>ssh</c> application.
For more information, see the <seealso marker="kernel:application">application(3)</seealso>
- manual page in <c>kernel</c>.</p>
+ manual page in Kernel.</p>
</desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index f6ce44c015..5cc4c24889 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>2012</year><year>2015</year>
+ <year>2012</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -203,7 +203,7 @@
<section>
<title>Unicode support</title>
<p>Unicode filenames are supported if the emulator and the underlaying OS support it. See section DESCRIPTION in the
- <seealso marker="kernel:file">file</seealso> manual page in <c>kernel</c> for information about this subject.
+ <seealso marker="kernel:file">file</seealso> manual page in Kernel for information about this subject.
</p>
<p>The shell and the cli both support unicode.
</p>
diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml
index 907b0b3bec..7b598494f7 100644
--- a/lib/ssh/doc/src/ssh_channel.xml
+++ b/lib/ssh/doc/src/ssh_channel.xml
@@ -139,7 +139,7 @@
enters the <c>ssh_channel</c> process receive loop and become an
<c>ssh_channel process</c>. The process must have been started using
one of the start functions in <c>proc_lib</c>, see the <seealso
- marker="stdlib:proc_lib">proc_lib(3)</seealso> manual page in <c>stdlib</c>.
+ marker="stdlib:proc_lib">proc_lib(3)</seealso> manual page in STDLIB.
The user is responsible for any initialization of the process
and must call <seealso marker = "#init-1">ssh_channel:init/1</seealso>.
</p>
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
index 7288266cf7..a0032ab449 100644
--- a/lib/ssh/doc/src/ssh_protocol.xml
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2013</year><year>2013</year>
+ <year>2013</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -138,8 +138,6 @@
Transport Layer Protocol.</item>
<item><url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url> -
Connection Protocol.</item>
- <item><url href="http://www.ietf.org/rfc/rfc4255.txt">RFC 4255</url> -
- Key Fingerprints.</item>
<item><url href="http://www.ietf.org/rfc/rfc4344.txt">RFC 4344</url> -
Transport Layer Encryption Modes.</item>
<item><url href="http://www.ietf.org/rfc/rfc4716.txt">RFC 4716</url> -
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index 0861c641c7..ab307624e6 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2016</year>
+ <year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -305,7 +305,7 @@ ok = erl_tar:close(HandleRead),
<code type="erl" >
-module(ssh_echo_server).
--behaviour(ssh_subsystem).
+-behaviour(ssh_daemon_channel).
-record(state, {
n,
id,
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 69d5a47f83..7ab6f22424 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -96,7 +96,7 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
+INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl ssh_dbg.hrl
# ----------------------------------------------------
# FLAGS
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 3245ba5197..7859ab4064 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -41,11 +41,10 @@
{env, []},
{mod, {ssh_app, []}},
{runtime_dependencies, [
- "crypto-3.3",
+ "crypto-3.7.3",
"erts-6.0",
"kernel-3.0",
- "public_key-1.1",
- "stdlib-3.0"
+ "public_key-1.4",
+ "stdlib-3.3"
]}]}.
-
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index e38cecf226..2540720c41 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,9 +20,13 @@
{"%VSN%",
[
+ {<<"4.3.2">>, [{load_module, ssh_channel, soft_purge, soft_purge, []}
+ ]},
{<<".*">>, [{restart_application, ssh}]}
],
[
+ {<<"4.3.2">>, [{load_module, ssh_channel, soft_purge, soft_purge, []}
+ ]},
{<<".*">>, [{restart_application, ssh}]}
]
}.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 0570853a9b..ecdb184db3 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,16 +52,15 @@
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
- application:start(crypto),
- application:start(asn1),
- application:start(public_key),
- application:start(ssh).
+ start(temporary).
start(Type) ->
- application:start(crypto, Type),
- application:start(asn1),
- application:start(public_key, Type),
- application:start(ssh, Type).
+ case application:ensure_all_started(ssh, Type) of
+ {ok, _} ->
+ ok;
+ Other ->
+ Other
+ end.
%%--------------------------------------------------------------------
-spec stop() -> ok | {error, term()}.
@@ -90,7 +89,7 @@ connect(Socket, Options, Timeout) when is_port(Socket) ->
{error, Error};
{_SocketOptions, SshOptions} ->
case valid_socket_to_use(Socket, Options) of
- ok ->
+ ok ->
{ok, {Host,_Port}} = inet:sockname(Socket),
Opts = [{user_pid,self()}, {host,fmt_host(Host)} | SshOptions],
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
@@ -128,23 +127,23 @@ connect(Host, Port, Options, Timeout) ->
-spec close(pid()) -> ok.
%%
%% Description: Closes an ssh connection.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
close(ConnectionRef) ->
ssh_connection_handler:stop(ConnectionRef).
%%--------------------------------------------------------------------
-spec connection_info(pid(), [atom()]) -> [{atom(), term()}].
%%
-%% Description: Retrieves information about a connection.
-%%--------------------------------------------------------------------
+%% Description: Retrieves information about a connection.
+%%--------------------------------------------------------------------
connection_info(ConnectionRef, Options) ->
ssh_connection_handler:connection_info(ConnectionRef, Options).
%%--------------------------------------------------------------------
-spec channel_info(pid(), channel_id(), [atom()]) -> [{atom(), term()}].
%%
-%% Description: Retrieves information about a connection.
-%%--------------------------------------------------------------------
+%% Description: Retrieves information about a connection.
+%%--------------------------------------------------------------------
channel_info(ConnectionRef, ChannelId, Options) ->
ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options).
@@ -153,9 +152,9 @@ channel_info(ConnectionRef, ChannelId, Options) ->
-spec daemon(integer()|port(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
-spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
-%% Description: Starts a server listening for SSH connections
+%% Description: Starts a server listening for SSH connections
%% on the given port.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
daemon(Port) ->
daemon(Port, []).
@@ -176,7 +175,7 @@ daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
[Port] =
- [Prt || {{ssh_acceptor_sup,any,Prt,default},
+ [Prt || {{ssh_acceptor_sup,_,Prt,_},
_WorkerPid,worker,[ssh_acceptor]} <- supervisor:which_children(AsupPid)],
{ok, [{port,Port}]};
@@ -188,9 +187,9 @@ daemon_info(Pid) ->
-spec stop_listener(pid()) -> ok.
-spec stop_listener(inet:ip_address(), integer()) -> ok.
%%
-%% Description: Stops the listener, but leaves
+%% Description: Stops the listener, but leaves
%% existing connections started by the listener up and running.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
stop_listener(SysSup) ->
ssh_system_sup:stop_listener(SysSup).
stop_listener(Address, Port) ->
@@ -202,9 +201,9 @@ stop_listener(Address, Port, Profile) ->
-spec stop_daemon(pid()) -> ok.
-spec stop_daemon(inet:ip_address(), integer()) -> ok.
%%
-%% Description: Stops the listener and all connections started by
+%% Description: Stops the listener and all connections started by
%% the listener.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
stop_daemon(SysSup) ->
ssh_system_sup:stop_system(SysSup).
stop_daemon(Address, Port) ->
@@ -243,7 +242,7 @@ start_shell({ok, ConnectionRef}) ->
case ssh_connection:session_channel(ConnectionRef, infinity) of
{ok,ChannelId} ->
success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId, []),
- Args = [{channel_cb, ssh_shell},
+ Args = [{channel_cb, ssh_shell},
{init_args,[ConnectionRef, ChannelId]},
{cm, ConnectionRef}, {channel_id, ChannelId}],
{ok, State} = ssh_channel:init([Args]),
@@ -256,7 +255,7 @@ start_shell(Error) ->
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
-default_algorithms() ->
+default_algorithms() ->
ssh_transport:default_algorithms().
%%--------------------------------------------------------------------
@@ -281,14 +280,16 @@ valid_socket_to_use(Socket, Options) ->
{error, {unsupported,L4}}
end.
-is_tcp_socket(Socket) -> {ok,[]} =/= inet:getopts(Socket, [delay_send]).
-
-
+is_tcp_socket(Socket) ->
+ case inet:getopts(Socket, [delay_send]) of
+ {ok,[_]} -> true;
+ _ -> false
+ end.
daemon_shell_opt(Options) ->
case proplists:get_value(shell, Options) of
undefined ->
- [{shell, {shell, start, []}} | Options];
+ [{shell, ?DEFAULT_SHELL} | Options];
_ ->
Options
end.
@@ -296,13 +297,13 @@ daemon_shell_opt(Options) ->
daemon_host_inet_opt(HostAddr, Options1) ->
case HostAddr of
any ->
- {ok, Host0} = inet:gethostname(),
+ {ok, Host0} = inet:gethostname(),
{Host0, proplists:get_value(inet, Options1, inet), Options1};
{_,_,_,_} ->
- {HostAddr, inet,
+ {HostAddr, inet,
[{ip, HostAddr} | Options1]};
{_,_,_,_,_,_,_,_} ->
- {HostAddr, inet6,
+ {HostAddr, inet6,
[{ip, HostAddr} | Options1]}
end.
@@ -313,11 +314,12 @@ start_daemon(Socket, Options) ->
{error, Error};
{SocketOptions, SshOptions} ->
case valid_socket_to_use(Socket, Options) of
- ok ->
- try
+ ok ->
+ try
do_start_daemon(Socket, [{role,server}|SshOptions], SocketOptions)
catch
throw:bad_fd -> {error,bad_fd};
+ throw:bad_socket -> {error,bad_socket};
_C:_E -> {error,{cannot_start_daemon,_C,_E}}
end;
{error,SockError} ->
@@ -330,16 +332,17 @@ start_daemon(Host, Port, Options, Inet) ->
{error, _Reason} = Error ->
Error;
{SocketOptions, SshOptions}->
- try
+ try
do_start_daemon(Host, Port, [{role,server}|SshOptions] , [Inet|SocketOptions])
catch
throw:bad_fd -> {error,bad_fd};
+ throw:bad_socket -> {error,bad_socket};
_C:_E -> {error,{cannot_start_daemon,_C,_E}}
end
end.
-
+
do_start_daemon(Socket, SshOptions, SocketOptions) ->
- {ok, {IP,Port}} =
+ {ok, {IP,Port}} =
try {ok,_} = inet:sockname(Socket)
catch
_:_ -> throw(bad_socket)
@@ -351,7 +354,7 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{address, Host},
{port, Port},
{role, server},
- {socket_opts, SocketOptions},
+ {socket_opts, SocketOptions},
{ssh_opts, SshOptions}],
{_, Callback, _} = proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
@@ -363,8 +366,7 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{error, {already_started, _}} ->
{error, eaddrinuse};
Result = {ok,_} ->
- ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket),
- Result;
+ call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, Result);
Result = {error, _} ->
Result
catch
@@ -377,15 +379,14 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{error, {already_started, _}} ->
{error, eaddrinuse};
{ok, _} ->
- ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket),
- {ok, Sup};
+ call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, {ok, Sup});
Other ->
Other
end
end.
do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
- {Host,Port1} =
+ {Host,Port1} =
try
case proplists:get_value(fd, SocketOptions) of
undefined ->
@@ -402,21 +403,21 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
{Port, WaitRequestControl, Opts0} =
case Port1 of
0 -> %% Allocate the socket here to get the port number...
- {_, Callback, _} =
+ {_, Callback, _} =
proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
{ok,LSock} = ssh_acceptor:callback_listen(Callback, 0, SocketOptions),
{ok,{_,LPort}} = inet:sockname(LSock),
- {LPort,
- {LSock,Callback},
+ {LPort,
+ {LSock,Callback},
[{lsocket,LSock},{lsock_owner,self()}]
};
_ ->
{Port1, false, []}
end,
- Opts = [{address, Host},
+ Opts = [{address, Host},
{port, Port},
{role, server},
- {socket_opts, SocketOptions},
+ {socket_opts, SocketOptions},
{ssh_opts, SshOptions} | Opts0],
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
@@ -448,6 +449,16 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
end
end.
+call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, DefaultResult) ->
+ try ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket)
+ of
+ {error,Error} -> {error,Error};
+ _ -> DefaultResult
+ catch
+ C:R -> {error,{could_not_start_connection,{C,R}}}
+ end.
+
+
sync_request_control(false) ->
ok;
sync_request_control({LSock,Callback}) ->
@@ -465,7 +476,7 @@ find_hostport(Fd) ->
{ok, HostPort} = inet:sockname(S),
ok = inet:close(S),
HostPort.
-
+
handle_options(Opts) ->
try handle_option(algs_compatibility(proplists:unfold(Opts)), [], []) of
@@ -480,9 +491,9 @@ handle_options(Opts) ->
algs_compatibility(Os0) ->
%% Take care of old options 'public_key_alg' and 'pref_public_key_algs'
case proplists:get_value(public_key_alg, Os0) of
- undefined ->
+ undefined ->
Os0;
- A when is_atom(A) ->
+ A when is_atom(A) ->
%% Skip public_key_alg if pref_public_key_algs is defined:
Os = lists:keydelete(public_key_alg, 1, Os0),
case proplists:get_value(pref_public_key_algs,Os) of
@@ -492,7 +503,7 @@ algs_compatibility(Os0) ->
[{pref_public_key_algs,['ssh-dss','ssh-rsa']} | Os];
undefined ->
throw({error, {eoptions, {public_key_alg,A} }});
- _ ->
+ _ ->
Os
end;
V ->
@@ -618,9 +629,29 @@ handle_ssh_option({user_dir_fun, Value} = Opt) when is_function(Value) ->
Opt;
handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) ->
Opt;
+handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_function(Value,2) ->
+ Opt;
+handle_ssh_option({silently_accept_hosts, {DigestAlg,Value}} = Opt) when is_function(Value,2) ->
+ Algs = if is_atom(DigestAlg) -> [DigestAlg];
+ is_list(DigestAlg) -> DigestAlg;
+ true -> throw({error, {eoptions, Opt}})
+ end,
+ case [A || A <- Algs,
+ not lists:member(A, [md5, sha, sha224, sha256, sha384, sha512])] of
+ [_|_] = UnSup1 ->
+ throw({error, {{eoptions, Opt}, {not_fingerprint_algos,UnSup1}}});
+ [] ->
+ CryptoHashAlgs = proplists:get_value(hashs, crypto:supports(), []),
+ case [A || A <- Algs,
+ not lists:member(A, CryptoHashAlgs)] of
+ [_|_] = UnSup2 ->
+ throw({error, {{eoptions, Opt}, {unsupported_algo,UnSup2}}});
+ [] -> Opt
+ end
+ end;
handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
-handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
+handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
handle_pref_algs(Opt);
handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
@@ -629,7 +660,7 @@ handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
lists:foldl(
fun({N,G,P}, Acc) when is_integer(N),N>0,
is_integer(G),G>0,
- is_integer(P),P>0 ->
+ is_integer(P),P>0 ->
[{N,{G,P}} | Acc];
({N,{G,P}}, Acc) when is_integer(N),N>0,
is_integer(G),G>0,
@@ -637,7 +668,7 @@ handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
[{N,{G,P}} | Acc];
({N,GPs}, Acc) when is_list(GPs) ->
lists:foldr(fun({Gi,Pi}, Acci) when is_integer(Gi),Gi>0,
- is_integer(Pi),Pi>0 ->
+ is_integer(Pi),Pi>0 ->
[{N,{Gi,Pi}} | Acci]
end, Acc, GPs)
end, [], L0))};
@@ -647,7 +678,7 @@ handle_ssh_option({dh_gex_groups,{Tag,File=[C|_]}}=Opt) when is_integer(C), C>0,
Tag == ssh_moduli_file ->
{ok,GroupDefs} =
case Tag of
- file ->
+ file ->
file:consult(File);
ssh_moduli_file ->
case file:open(File,[read]) of
@@ -672,14 +703,14 @@ handle_ssh_option({dh_gex_groups,{Tag,File=[C|_]}}=Opt) when is_integer(C), C>0,
catch
_:_ ->
throw({error, {{eoptions, Opt}, "Bad format in file: "++File}})
- end;
-
+ end;
+
-handle_ssh_option({dh_gex_limits,{Min,Max}} = Opt) when is_integer(Min), Min>0,
+handle_ssh_option({dh_gex_limits,{Min,Max}} = Opt) when is_integer(Min), Min>0,
is_integer(Max), Max>=Min ->
%% Server
Opt;
-handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0,
+handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0,
is_integer(I), I>=Min,
is_integer(Max), Max>=I ->
%% Client
@@ -724,7 +755,7 @@ handle_ssh_option({keyboard_interact_fun, Value} = Opt) when is_function(Value,3
Opt;
handle_ssh_option({compression, Value} = Opt) when is_atom(Value) ->
Opt;
-handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module),
+handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module),
is_atom(Function) ->
Opt;
handle_ssh_option({exec, Function} = Opt) when is_function(Function) ->
@@ -772,7 +803,7 @@ handle_ssh_option({quiet_mode, Value} = Opt) when is_boolean(Value) ->
Opt;
handle_ssh_option({idle_time, Value} = Opt) when is_integer(Value), Value > 0 ->
Opt;
-handle_ssh_option({rekey_limit, Value} = Opt) when is_integer(Value) ->
+handle_ssh_option({rekey_limit, Value} = Opt) when is_integer(Value) ->
Opt;
handle_ssh_option({id_string, random}) ->
{id_string, {random,2,5}}; %% 2 - 5 random characters
@@ -814,11 +845,11 @@ handle_pref_algs({preferred_algorithms,Algs}) ->
of
DefAlgs -> handle_pref_alg(Key,Vals,DefAlgs)
catch
- _:_ -> throw({error, {{eoptions, {preferred_algorithms,Key}},
+ _:_ -> throw({error, {{eoptions, {preferred_algorithms,Key}},
"Bad preferred_algorithms key"}})
end || {Key,Vals} <- Algs]
};
-
+
Dups ->
throw({error, {{eoptions, {preferred_algorithms,Dups}}, "Duplicates found"}})
catch
@@ -857,13 +888,13 @@ handle_pref_alg(Key,
) ->
handle_pref_alg(Key, lists:reverse(Vs), Sup);
-handle_pref_alg(Key,
+handle_pref_alg(Key,
Vs=[V|_],
Sup=[{client2server,_},{server2client,_}]
) when is_atom(V) ->
handle_pref_alg(Key, [{client2server,Vs},{server2client,Vs}], Sup);
-handle_pref_alg(Key,
+handle_pref_alg(Key,
Vs=[V|_],
Sup=[S|_]
) when is_atom(V), is_atom(S) ->
@@ -878,14 +909,14 @@ chk_alg_vs(OptKey, Values, SupportedValues) ->
[] -> Values;
Bad -> throw({error, {{eoptions, {OptKey,Bad}}, "Unsupported value(s) found"}})
end.
-
+
handle_ip(Inet) -> %% Default to ipv4
case lists:member(inet, Inet) of
true ->
Inet;
false ->
case lists:member(inet6, Inet) of
- true ->
+ true ->
Inet;
false ->
[inet | Inet]
@@ -916,8 +947,8 @@ directory_exist_readable(Dir) ->
{error, Error} ->
{error, Error}
end.
-
-
+
+
collect_per_size(L) ->
lists:foldr(
@@ -948,7 +979,7 @@ read_moduli_file(D, I, Acc) ->
read_moduli_file(D, I+1, Acc)
end
end.
-
+
handle_user_pref_pubkey_algs([], Acc) ->
{true, lists:reverse(Acc)};
handle_user_pref_pubkey_algs([H|T], Acc) ->
@@ -963,7 +994,7 @@ handle_user_pref_pubkey_algs([H|T], Acc) ->
false
end.
-fmt_host({A,B,C,D}) ->
+fmt_host({A,B,C,D}) ->
lists:concat([A,".",B,".",C,".",D]);
-fmt_host(T={_,_,_,_,_,_,_,_}) ->
+fmt_host(T={_,_,_,_,_,_,_,_}) ->
lists:flatten(string:join([io_lib:format("~.16B",[A]) || A <- tuple_to_list(T)], ":")).
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 868f3a9181..9d119f4f42 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -33,6 +33,12 @@
-define(REKEY_DATA_TIMOUT, 60000).
-define(DEFAULT_PROFILE, default).
+-define(DEFAULT_TRANSPORT, {tcp, gen_tcp, tcp_closed} ).
+
+-define(DEFAULT_SHELL, {shell, start, []} ).
+
+-define(MAX_RND_PADDING_LEN, 15).
+
-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
-define(SUPPORTED_USER_KEYS, ['ssh-rsa','ssh-dss','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521']).
@@ -127,7 +133,7 @@
recv_sequence = 0,
keyex_key,
keyex_info,
- random_length_padding = 255, % From RFC 4253 section 6.
+ random_length_padding = 15, % From RFC 4253 section 6.
%% User auth
user,
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 9f3e60bd62..13c9d9af4a 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 49eec8072f..9b54ecb2dd 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -31,24 +31,123 @@
-export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
service_request_msg/1, init_userauth_request_msg/1,
userauth_request_msg/1, handle_userauth_request/3,
- handle_userauth_info_request/3, handle_userauth_info_response/2
+ handle_userauth_info_request/2, handle_userauth_info_response/2
]).
%%--------------------------------------------------------------------
%%% Internal application API
%%--------------------------------------------------------------------
+%%%----------------------------------------------------------------
+userauth_request_msg(#ssh{userauth_methods = ServerMethods,
+ userauth_supported_methods = UserPrefMethods, % Note: this is not documented as supported for clients
+ userauth_preference = ClientMethods0
+ } = Ssh0) ->
+ case sort_select_mthds(ClientMethods0, UserPrefMethods, ServerMethods) of
+ [] ->
+ Msg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
+ description = "Unable to connect using the available authentication methods",
+ language = "en"},
+ {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh0)};
+
+ [{Pref,Module,Function,Args} | Prefs] ->
+ Ssh = case Pref of
+ "keyboard-interactive" -> Ssh0;
+ _ -> Ssh0#ssh{userauth_preference = Prefs}
+ end,
+ case Module:Function(Args ++ [Ssh]) of
+ {not_ok, Ssh1} ->
+ userauth_request_msg(Ssh1#ssh{userauth_preference = Prefs});
+ Result ->
+ {Pref,Result}
+ end
+ end.
+
+
+
+sort_select_mthds(Clients, undefined, Servers) ->
+ %% User has not expressed an opinion via option "auth_methods", use the server's prefs
+ sort_select_mthds1(Clients, Servers, string:tokens(?SUPPORTED_AUTH_METHODS,","));
+
+sort_select_mthds(Clients, Users0, Servers0) ->
+ %% The User has an opinion, use the intersection of that and the Servers whishes but
+ %% in the Users order
+ sort_select_mthds1(Clients, string:tokens(Users0,","), Servers0).
+
+
+sort_select_mthds1(Clients, Users0, Servers0) ->
+ Servers = unique(Servers0),
+ Users = unique(Users0),
+ [C || Key <- Users,
+ lists:member(Key, Servers),
+ C <- Clients,
+ element(1,C) == Key].
+
+unique(L) ->
+ lists:reverse(
+ lists:foldl(fun(E,Acc) ->
+ case lists:member(E,Acc) of
+ true -> Acc;
+ false -> [E|Acc]
+ end
+ end, [], L)).
+
+
+%%%---- userauth_request_msg "callbacks"
+password_msg([#ssh{opts = Opts, io_cb = IoCb,
+ user = User, service = Service} = Ssh0]) ->
+ {Password,Ssh} =
+ case proplists:get_value(password, Opts) of
+ undefined when IoCb == ssh_no_io ->
+ {not_ok, Ssh0};
+ undefined ->
+ {IoCb:read_password("ssh password: ",Ssh0), Ssh0};
+ PW ->
+ %% If "password" option is given it should not be tried again
+ {PW, Ssh0#ssh{opts = lists:keyreplace(password,1,Opts,{password,not_ok})}}
+ end,
+ case Password of
+ not_ok ->
+ {not_ok, Ssh};
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "password",
+ data =
+ <<?BOOLEAN(?FALSE),
+ ?STRING(unicode:characters_to_binary(Password))>>},
+ Ssh)
+ end.
+
+%% See RFC 4256 for info on keyboard-interactive
+keyboard_interactive_msg([#ssh{user = User,
+ opts = Opts,
+ service = Service} = Ssh]) ->
+ case proplists:get_value(password, Opts) of
+ not_ok ->
+ {not_ok,Ssh}; % No need to use a failed pwd once more
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "keyboard-interactive",
+ data = << ?STRING(<<"">>),
+ ?STRING(<<>>) >> },
+ Ssh)
+ end.
+
publickey_msg([Alg, #ssh{user = User,
session_id = SessionId,
service = Service,
opts = Opts} = Ssh]) ->
- Hash = sha, %% Maybe option?!
+ Hash = ssh_transport:sha(Alg),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
case KeyCb:user_key(Alg, Opts) of
{ok, PrivKey} ->
StrAlgo = atom_to_list(Alg),
case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of
not_ok ->
- not_ok;
+ {not_ok, Ssh};
PubKeyBlob ->
SigData = build_sig_data(SessionId,
User, Service, PubKeyBlob, StrAlgo),
@@ -65,52 +164,15 @@ publickey_msg([Alg, #ssh{user = User,
Ssh)
end;
_Error ->
- not_ok
- end.
-
-password_msg([#ssh{opts = Opts, io_cb = IoCb,
- user = User, service = Service} = Ssh]) ->
- Password = case proplists:get_value(password, Opts) of
- undefined ->
- user_interaction(IoCb, Ssh);
- PW ->
- PW
- end,
- case Password of
- not_ok ->
- not_ok;
- _ ->
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "password",
- data =
- <<?BOOLEAN(?FALSE),
- ?STRING(unicode:characters_to_binary(Password))>>},
- Ssh)
+ {not_ok, Ssh}
end.
-user_interaction(ssh_no_io, _) ->
- not_ok;
-user_interaction(IoCb, Ssh) ->
- IoCb:read_password("ssh password: ", Ssh).
-
-
-%% See RFC 4256 for info on keyboard-interactive
-keyboard_interactive_msg([#ssh{user = User,
- service = Service} = Ssh]) ->
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "keyboard-interactive",
- data = << ?STRING(<<"">>),
- ?STRING(<<>>) >> },
- Ssh).
-
+%%%----------------------------------------------------------------
service_request_msg(Ssh) ->
ssh_transport:ssh_packet(#ssh_msg_service_request{name = "ssh-userauth"},
Ssh#ssh{service = "ssh-userauth"}).
+%%%----------------------------------------------------------------
init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
case user_name(Opts) of
{ok, User} ->
@@ -140,34 +202,9 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
description = ErrStr})
end.
-userauth_request_msg(#ssh{userauth_preference = []} = Ssh) ->
- Msg = #ssh_msg_disconnect{code =
- ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
- description = "Unable to connect using the available"
- " authentication methods",
- language = "en"},
- {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh)};
-
-userauth_request_msg(#ssh{userauth_methods = Methods,
- userauth_preference = [{Pref, Module,
- Function, Args} | Prefs]}
- = Ssh0) ->
- Ssh = Ssh0#ssh{userauth_preference = Prefs},
- case lists:member(Pref, Methods) of
- true ->
- case Module:Function(Args ++ [Ssh]) of
- not_ok ->
- userauth_request_msg(Ssh);
- Result ->
- {Pref,Result}
- end;
- false ->
- userauth_request_msg(Ssh)
- end.
-
-
-handle_userauth_request(#ssh_msg_service_request{name =
- Name = "ssh-userauth"},
+%%%----------------------------------------------------------------
+%%% called by server
+handle_userauth_request(#ssh_msg_service_request{name = Name = "ssh-userauth"},
_, Ssh) ->
{ok, ssh_transport:ssh_packet(#ssh_msg_service_accept{name = Name},
Ssh#ssh{service = "ssh-connection"})};
@@ -223,32 +260,54 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "publickey",
- data = Data},
- SessionId,
+ data = <<?BYTE(?FALSE),
+ ?UINT32(ALen), BAlg:ALen/binary,
+ ?UINT32(KLen), KeyBlob:KLen/binary,
+ _/binary
+ >>
+ },
+ _SessionId,
#ssh{opts = Opts,
userauth_supported_methods = Methods} = Ssh) ->
- <<?BYTE(HaveSig), ?UINT32(ALen), BAlg:ALen/binary,
- ?UINT32(KLen), KeyBlob:KLen/binary, SigWLen/binary>> = Data,
- Alg = binary_to_list(BAlg),
- case HaveSig of
- ?TRUE ->
- case verify_sig(SessionId, User, "ssh-connection", Alg,
- KeyBlob, SigWLen, Opts) of
- true ->
- {authorized, User,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_success{}, Ssh)};
- false ->
- {not_authorized, {User, undefined},
- ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
- authentications = Methods,
- partial_success = false}, Ssh)}
- end;
- ?FALSE ->
+
+ case pre_verify_sig(User, binary_to_list(BAlg),
+ KeyBlob, Opts) of
+ true ->
{not_authorized, {User, undefined},
ssh_transport:ssh_packet(
- #ssh_msg_userauth_pk_ok{algorithm_name = Alg,
- key_blob = KeyBlob}, Ssh)}
+ #ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
+ key_blob = KeyBlob}, Ssh)};
+ false ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
+ authentications = Methods,
+ partial_success = false}, Ssh)}
+ end;
+
+handle_userauth_request(#ssh_msg_userauth_request{user = User,
+ service = "ssh-connection",
+ method = "publickey",
+ data = <<?BYTE(?TRUE),
+ ?UINT32(ALen), BAlg:ALen/binary,
+ ?UINT32(KLen), KeyBlob:KLen/binary,
+ SigWLen/binary>>
+ },
+ SessionId,
+ #ssh{opts = Opts,
+ userauth_supported_methods = Methods} = Ssh) ->
+
+ case verify_sig(SessionId, User, "ssh-connection",
+ binary_to_list(BAlg),
+ KeyBlob, SigWLen, Opts) of
+ true ->
+ {authorized, User,
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_success{}, Ssh)};
+ false ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
+ authentications = Methods,
+ partial_success = false}, Ssh)}
end;
handle_userauth_request(#ssh_msg_userauth_request{user = User,
@@ -319,31 +378,54 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
partial_success = false}, Ssh)}.
-
-handle_userauth_info_request(
- #ssh_msg_userauth_info_request{name = Name,
- instruction = Instr,
- num_prompts = NumPrompts,
- data = Data}, IoCb,
- #ssh{opts = Opts} = Ssh) ->
+%%%----------------------------------------------------------------
+%%% keyboard-interactive client
+handle_userauth_info_request(#ssh_msg_userauth_info_request{name = Name,
+ instruction = Instr,
+ num_prompts = NumPrompts,
+ data = Data},
+ #ssh{opts = Opts,
+ io_cb = IoCb
+ } = Ssh) ->
PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data),
- Responses = keyboard_interact_get_responses(IoCb, Opts,
- Name, Instr, PromptInfos),
- {ok,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_info_response{num_responses = NumPrompts,
- data = Responses}, Ssh)}.
+ case keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) of
+ not_ok ->
+ not_ok;
+ Responses ->
+ {ok,
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_info_response{num_responses = NumPrompts,
+ data = Responses}, Ssh)}
+ end.
+%%%----------------------------------------------------------------
+%%% keyboard-interactive server
handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
data = <<?UINT32(Sz), Password:Sz/binary>>},
#ssh{opts = Opts,
kb_tries_left = KbTriesLeft,
user = User,
userauth_supported_methods = Methods} = Ssh) ->
+ SendOneEmpty =
+ (proplists:get_value(tstflg,Opts) == one_empty)
+ orelse
+ proplists:get_value(one_empty, proplists:get_value(tstflg,Opts,[]), false),
+
case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of
+ {true,Ssh1} when SendOneEmpty==true ->
+ Msg = #ssh_msg_userauth_info_request{name = "",
+ instruction = "",
+ language_tag = "",
+ num_prompts = 0,
+ data = <<?BOOLEAN(?FALSE)>>
+ },
+ {authorized_but_one_more, User,
+ ssh_transport:ssh_packet(Msg, Ssh1)};
+
{true,Ssh1} ->
{authorized, User,
ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh1)};
+
{false,Ssh1} ->
{not_authorized, {User, {error,"Bad user or password"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
@@ -353,6 +435,11 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
)}
end;
+handle_userauth_info_response({extra,#ssh_msg_userauth_info_response{}},
+ #ssh{user = User} = Ssh) ->
+ {authorized, User,
+ ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)};
+
handle_userauth_info_response(#ssh_msg_userauth_info_response{},
_Auth) ->
ssh_connection_handler:disconnect(
@@ -369,11 +456,6 @@ method_preference(Algs) ->
[{"publickey", ?MODULE, publickey_msg, [A]} | Acc]
end,
[{"password", ?MODULE, password_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
{"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
],
Algs).
@@ -434,19 +516,34 @@ get_password_option(Opts, User) ->
false -> proplists:get_value(password, Opts, false)
end.
-verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
- {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+pre_verify_sig(User, Alg, KeyBlob, Opts) ->
+ try
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+ KeyCb:is_auth_key(Key, User, Opts)
+ catch
+ _:_ ->
+ false
+ end.
- case KeyCb:is_auth_key(Key, User, Opts) of
- true ->
- PlainText = build_sig_data(SessionId, User,
- Service, KeyBlob, Alg),
- <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen,
- <<?UINT32(AlgLen), _Alg:AlgLen/binary,
- ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig,
- ssh_transport:verify(PlainText, sha, Sig, Key);
- false ->
+verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
+ try
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+
+ case KeyCb:is_auth_key(Key, User, Opts) of
+ true ->
+ PlainText = build_sig_data(SessionId, User,
+ Service, KeyBlob, Alg),
+ <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen,
+ <<?UINT32(AlgLen), _Alg:AlgLen/binary,
+ ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig,
+ ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key);
+ false ->
+ false
+ end
+ catch
+ _:_ ->
false
end.
@@ -473,6 +570,9 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
proplists:get_value(password, Opts, undefined), IoCb, Name,
Instr, PromptInfos, Opts, NumPrompts).
+
+keyboard_interact_get_responses(_, _, not_ok, _, _, _, _, _, _) ->
+ not_ok;
keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _,
1) when Password =/= undefined ->
[Password]; %% Password auth implemented with keyboard-interaction and passwd is known
@@ -486,17 +586,18 @@ keyboard_interact_get_responses(true, Fun, _Pwd, _IoCb, Name, Instr, PromptInfos
keyboard_interact_fun(Fun, Name, Instr, PromptInfos, NumPrompts).
keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
- if Name /= "" -> IoCb:format("~s~n", [Name]);
- true -> ok
- end,
- if Instr /= "" -> IoCb:format("~s~n", [Instr]);
- true -> ok
- end,
+ write_if_nonempty(IoCb, Name),
+ write_if_nonempty(IoCb, Instr),
lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts);
({Prompt, false}) -> IoCb:read_password(Prompt, Opts)
end,
Prompts).
+write_if_nonempty(_, "") -> ok;
+write_if_nonempty(_, <<>>) -> ok;
+write_if_nonempty(IoCb, Text) -> IoCb:format("~s~n",[Text]).
+
+
keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) ->
Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end,
PromptInfos),
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index a8e6ebde16..85b31f3669 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -93,11 +93,16 @@ call(ChannelPid, Msg, TimeOute) ->
catch
exit:{noproc, _} ->
{error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{shutdown, _} ->
+ {error, closed};
+ exit:{{shutdown, _}, _} ->
+ {error, closed};
exit:{timeout, _} ->
{error, timeout}
end.
-
cast(ChannelPid, Msg) ->
gen_server:cast(ChannelPid, Msg).
@@ -256,7 +261,7 @@ handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager,
adjust_window(Msg),
{noreply, State#state{channel_state = ChannelState}, Timeout};
{stop, ChannelId, ChannelState} ->
- ssh_connection:close(ConnectionManager, ChannelId),
+ catch ssh_connection:close(ConnectionManager, ChannelId),
{stop, normal, State#state{close_sent = true,
channel_state = ChannelState}}
end;
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 74cd2e081a..94d1275e7b 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -127,7 +127,8 @@ handle_ssh_msg({ssh_cm, ConnectionHandler,
cm = ConnectionHandler}};
handle_ssh_msg({ssh_cm, ConnectionHandler,
- {exec, ChannelId, WantReply, Cmd}}, #state{exec=undefined} = State) ->
+ {exec, ChannelId, WantReply, Cmd}}, #state{exec=undefined,
+ shell=?DEFAULT_SHELL} = State) ->
{Reply, Status} = exec(Cmd),
write_chars(ConnectionHandler,
ChannelId, io_lib:format("~p\n", [Reply])),
@@ -136,6 +137,15 @@ handle_ssh_msg({ssh_cm, ConnectionHandler,
ssh_connection:exit_status(ConnectionHandler, ChannelId, Status),
ssh_connection:send_eof(ConnectionHandler, ChannelId),
{stop, ChannelId, State#state{channel = ChannelId, cm = ConnectionHandler}};
+
+handle_ssh_msg({ssh_cm, ConnectionHandler,
+ {exec, ChannelId, WantReply, _Cmd}}, #state{exec = undefined} = State) ->
+ write_chars(ConnectionHandler, ChannelId, 1, "Prohibited.\n"),
+ ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId),
+ ssh_connection:exit_status(ConnectionHandler, ChannelId, 255),
+ ssh_connection:send_eof(ConnectionHandler, ChannelId),
+ {stop, ChannelId, State#state{channel = ChannelId, cm = ConnectionHandler}};
+
handle_ssh_msg({ssh_cm, ConnectionHandler,
{exec, ChannelId, WantReply, Cmd}}, State) ->
NewState = start_shell(ConnectionHandler, Cmd, State),
@@ -208,8 +218,15 @@ handle_msg({Group, Req}, #state{group = Group, buf = Buf, pty = Pty,
write_chars(ConnectionHandler, ChannelId, Chars),
{ok, State#state{buf = NewBuf}};
-handle_msg({'EXIT', Group, _Reason}, #state{group = Group,
- channel = ChannelId} = State) ->
+handle_msg({'EXIT', Group, Reason}, #state{group = Group,
+ cm = ConnectionHandler,
+ channel = ChannelId} = State) ->
+ Status = case Reason of
+ normal -> 0;
+ _ -> -1
+ end,
+ ssh_connection:exit_status(ConnectionHandler, ChannelId, Status),
+ ssh_connection:send_eof(ConnectionHandler, ChannelId),
{stop, ChannelId, State};
handle_msg(_, State) ->
@@ -446,14 +463,23 @@ move_cursor(From, To, #ssh_pty{width=Width, term=Type}) ->
%% %%% make sure that there is data to send
%% %%% before calling ssh_connection:send
write_chars(ConnectionHandler, ChannelId, Chars) ->
- case erlang:iolist_size(Chars) of
- 0 ->
- ok;
- _ ->
- ssh_connection:send(ConnectionHandler, ChannelId,
- ?SSH_EXTENDED_DATA_DEFAULT, Chars)
+ write_chars(ConnectionHandler, ChannelId, ?SSH_EXTENDED_DATA_DEFAULT, Chars).
+
+write_chars(ConnectionHandler, ChannelId, Type, Chars) ->
+ case has_chars(Chars) of
+ false -> ok;
+ true -> ssh_connection:send(ConnectionHandler,
+ ChannelId,
+ Type,
+ Chars)
end.
+has_chars([C|_]) when is_integer(C) -> true;
+has_chars([H|T]) when is_list(H) ; is_binary(H) -> has_chars(H) orelse has_chars(T);
+has_chars(<<_:8,_/binary>>) -> true;
+has_chars(_) -> false.
+
+
%%% tail, works with empty lists
tl1([_|A]) -> A;
tl1(_) -> [].
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index d0f2d54c06..c7a2c92670 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -287,6 +287,9 @@ handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
ssh_channel:cache_update(Cache, Channel#channel{
remote_id = RemoteId,
+ recv_packet_size = max(32768, % rfc4254/5.2
+ min(PacketSz, Channel#channel.recv_packet_size)
+ ),
send_window_size = WindowSz,
send_packet_size = PacketSz}),
{Reply, Connection} = reply_msg(Channel, Connection0, {open, ChannelId}),
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e952a333ff..7d055f0579 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -60,7 +60,8 @@
]).
%%% Behaviour callbacks
--export([handle_event/4, terminate/3, format_status/2, code_change/4]).
+-export([callback_mode/0, handle_event/4, terminate/3,
+ format_status/2, code_change/4]).
%%% Exports not intended to be used :). They are used for spawning and tests
-export([init_connection_handler/3, % proc_lib:spawn needs this
@@ -374,14 +375,12 @@ init_connection_handler(Role, Socket, Opts) ->
S ->
gen_statem:enter_loop(?MODULE,
[], %%[{debug,[trace,log,statistics,debug]} || Role==server],
- handle_event_function,
{hello,Role},
S)
catch
_:Error ->
gen_statem:enter_loop(?MODULE,
[],
- handle_event_function,
{init_error,Error},
S0)
end.
@@ -428,7 +427,12 @@ init_connection(server, C = #connection{}, Opts) ->
init_ssh_record(Role, Socket, Opts) ->
{ok, PeerAddr} = inet:peername(Socket),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
- AuthMethods = proplists:get_value(auth_methods, Opts, ?SUPPORTED_AUTH_METHODS),
+ AuthMethods = proplists:get_value(auth_methods,
+ Opts,
+ case Role of
+ server -> ?SUPPORTED_AUTH_METHODS;
+ client -> undefined
+ end),
S0 = #ssh{role = Role,
key_cb = KeyCb,
opts = Opts,
@@ -499,6 +503,9 @@ init_ssh_record(Role, Socket, Opts) ->
%%% ######## Error in the initialisation ####
+callback_mode() ->
+ handle_event_function.
+
handle_event(_, _Event, {init_error,Error}, _) ->
case Error of
{badmatch,{error,enotconn}} ->
@@ -518,7 +525,7 @@ handle_event(_, _Event, {init_error,Error}, _) ->
%% The very first event that is sent when the we are set as controlling process of Socket
handle_event(_, socket_control, {hello,_}, D) ->
VsnMsg = ssh_transport:hello_version_msg(string_version(D#data.ssh_params)),
- ok = send_bytes(VsnMsg, D),
+ send_bytes(VsnMsg, D),
case inet:getopts(Socket=D#data.socket, [recbuf]) of
{ok, [{recbuf,Size}]} ->
%% Set the socket to the hello text line handling mode:
@@ -538,12 +545,13 @@ handle_event(_, {info_line,_Line}, {hello,Role}, D) ->
case Role of
client ->
%% The server may send info lines to the client before the version_exchange
+ %% RFC4253/4.2
inet:setopts(D#data.socket, [{active, once}]),
keep_state_and_data;
server ->
%% But the client may NOT send them to the server. Openssh answers with cleartext,
%% and so do we
- ok = send_bytes("Protocol mismatch.", D),
+ send_bytes("Protocol mismatch.", D),
{stop, {shutdown,"Protocol mismatch in version exchange. Client sent info lines."}}
end;
@@ -558,7 +566,7 @@ handle_event(_, {version_exchange,Version}, {hello,Role}, D) ->
{active, once},
{recbuf, D#data.inet_initial_recbuf_size}]),
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1),
- ok = send_bytes(SshPacket, D),
+ send_bytes(SshPacket, D),
{next_state, {kexinit,Role,init}, D#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg}};
not_supported ->
@@ -576,7 +584,7 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
Ssh1 = ssh_transport:key_init(peer_role(Role), D#data.ssh_params, Payload),
Ssh = case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
{ok, NextKexMsg, Ssh2} when Role==client ->
- ok = send_bytes(NextKexMsg, D),
+ send_bytes(NextKexMsg, D),
Ssh2;
{ok, Ssh2} when Role==server ->
Ssh2
@@ -589,43 +597,45 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
%%%---- diffie-hellman
handle_event(_, #ssh_msg_kexdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexdhReply, Ssh1} = ssh_transport:handle_kexdh_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexdhReply, D),
+ send_bytes(KexdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- diffie-hellman group exchange
handle_event(_, #ssh_msg_kex_dh_gex_request{} = Msg, {key_exchange,server,ReNeg}, D) ->
- {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- ok = send_bytes(GexGroup, D),
+ {ok, GexGroup, Ssh1} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
+ send_bytes(GexGroup, D),
+ Ssh = ssh_transport:parallell_gen_key(Ssh1),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_request_old{} = Msg, {key_exchange,server,ReNeg}, D) ->
- {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- ok = send_bytes(GexGroup, D),
+ {ok, GexGroup, Ssh1} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
+ send_bytes(GexGroup, D),
+ Ssh = ssh_transport:parallell_gen_key(Ssh1),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, KexGexInit, Ssh} = ssh_transport:handle_kex_dh_gex_group(Msg, D#data.ssh_params),
- ok = send_bytes(KexGexInit, D),
+ send_bytes(KexGexInit, D),
{next_state, {key_exchange_dh_gex_reply,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- elliptic curve diffie-hellman
handle_event(_, #ssh_msg_kex_ecdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexEcdhReply, D),
+ send_bytes(KexEcdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
@@ -633,9 +643,9 @@ handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D)
handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,server,ReNeg}, D) ->
{ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexGexReply, D),
+ send_bytes(KexGexReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
@@ -643,7 +653,7 @@ handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,serv
handle_event(_, #ssh_msg_kex_dh_gex_reply{} = Msg, {key_exchange_dh_gex_reply,client,ReNeg}, D) ->
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh1}};
@@ -655,7 +665,7 @@ handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
Ssh = case Role of
client ->
{MsgReq, Ssh2} = ssh_auth:service_request_msg(Ssh1),
- ok = send_bytes(MsgReq, D),
+ send_bytes(MsgReq, D),
Ssh2;
server ->
Ssh1
@@ -663,8 +673,9 @@ handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
{next_state, {service_request,Role}, D#data{ssh_params=Ssh}};
%% Subsequent key exchange rounds (renegotiation):
-handle_event(_, #ssh_msg_newkeys{}, {new_keys,Role,renegotiate}, D) ->
- {next_state, {connected,Role}, D};
+handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,renegotiate}, D) ->
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
+ {next_state, {connected,Role}, D#data{ssh_params=Ssh}};
%%% ######## {service_request, client|server}
@@ -673,7 +684,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
"ssh-userauth" ->
Ssh0 = #ssh{session_id=SessionId} = D#data.ssh_params,
{ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{next_state, {userauth,server}, D#data{ssh_params = Ssh}};
_ ->
@@ -685,7 +696,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
handle_event(_, #ssh_msg_service_accept{name = "ssh-userauth"}, {service_request,client},
#data{ssh_params = #ssh{service="ssh-userauth"} = Ssh0} = State) ->
{Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0),
- ok = send_bytes(Msg, State),
+ send_bytes(Msg, State),
{next_state, {userauth,client}, State#data{auth_user = Ssh#ssh.user, ssh_params = Ssh}};
@@ -702,7 +713,7 @@ handle_event(_,
%% Probably the very first userauth_request but we deny unauthorized login
{not_authorized, _, {Reply,Ssh}} =
ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}};
{"ssh-connection", "ssh-connection", Method} ->
@@ -712,7 +723,7 @@ handle_event(_,
%% Yepp! we support this method
case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of
{authorized, User, {Reply, Ssh}} ->
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
D#data.starter ! ssh_connected,
connected_fun(User, Method, D),
{next_state, {connected,server},
@@ -720,11 +731,11 @@ handle_event(_,
ssh_params = Ssh#ssh{authenticated = true}}};
{not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" ->
retry_fun(User, Reason, D),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{next_state, {userauth_keyboard_interactive,server}, D#data{ssh_params = Ssh}};
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
retry_fun(User, Reason, D),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}}
end;
false ->
@@ -794,9 +805,13 @@ handle_event(_, #ssh_msg_userauth_banner{message = Msg}, {userauth,client}, D) -
handle_event(_, #ssh_msg_userauth_info_request{} = Msg, {userauth_keyboard_interactive, client},
#data{ssh_params = Ssh0} = D) ->
- {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_info_request(Msg, Ssh0#ssh.io_cb, Ssh0),
- send_bytes(Reply, D),
- {next_state, {userauth_keyboard_interactive_info_response,client}, D#data{ssh_params = Ssh}};
+ case ssh_auth:handle_userauth_info_request(Msg, Ssh0) of
+ {ok, {Reply, Ssh}} ->
+ send_bytes(Reply, D),
+ {next_state, {userauth_keyboard_interactive_info_response,client}, D#data{ssh_params = Ssh}};
+ not_ok ->
+ {next_state, {userauth,client}, D, [{next_event, internal, Msg}]}
+ end;
handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_interactive, server}, D) ->
case ssh_auth:handle_userauth_info_response(Msg, D#data.ssh_params) of
@@ -809,9 +824,21 @@ handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_inte
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
retry_fun(User, Reason, D),
send_bytes(Reply, D),
- {next_state, {userauth,server}, D#data{ssh_params = Ssh}}
+ {next_state, {userauth,server}, D#data{ssh_params = Ssh}};
+
+ {authorized_but_one_more, _User, {Reply, Ssh}} ->
+ send_bytes(Reply, D),
+ {next_state, {userauth_keyboard_interactive_extra,server}, D#data{ssh_params = Ssh}}
end;
+handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_interactive_extra, server}, D) ->
+ {authorized, User, {Reply, Ssh}} = ssh_auth:handle_userauth_info_response({extra,Msg}, D#data.ssh_params),
+ send_bytes(Reply, D),
+ D#data.starter ! ssh_connected,
+ connected_fun(User, "keyboard-interactive", D),
+ {next_state, {connected,server}, D#data{auth_user = User,
+ ssh_params = Ssh#ssh{authenticated = true}}};
+
handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive, client},
#data{ssh_params = Ssh0} = D0) ->
Prefs = [{Method,M,F,A} || {Method,M,F,A} <- Ssh0#ssh.userauth_preference,
@@ -819,7 +846,18 @@ handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactiv
D = D0#data{ssh_params = Ssh0#ssh{userauth_preference=Prefs}},
{next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
-handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client}, D) ->
+handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
+ #data{ssh_params = Ssh0} = D0) ->
+ Opts = Ssh0#ssh.opts,
+ D = case proplists:get_value(password, Opts) of
+ undefined ->
+ D0;
+ _ ->
+ D0#data{ssh_params =
+ Ssh0#ssh{opts =
+ lists:keyreplace(password,1,Opts,
+ {password,not_ok})}} % FIXME:intermodule dependency
+ end,
{next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
handle_event(_, Msg=#ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
@@ -892,6 +930,7 @@ handle_event(internal, Msg=#ssh_msg_channel_request{}, StateName, D) -
handle_connection_msg(Msg, StateName, D);
handle_event(internal, Msg=#ssh_msg_channel_success{}, StateName, D) ->
+ update_inet_buffers(D#data.socket),
handle_connection_msg(Msg, StateName, D);
handle_event(internal, Msg=#ssh_msg_channel_failure{}, StateName, D) ->
@@ -971,6 +1010,7 @@ handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = RemoteId} ->
Msg = ssh_connection:channel_success_msg(RemoteId),
+ update_inet_buffers(D#data.socket),
{keep_state, send_msg(Msg,D)};
undefined ->
@@ -1006,13 +1046,13 @@ handle_event({call,From}, get_print_info, StateName, D) ->
{keep_state_and_data, [{reply,From,Reply}]};
handle_event({call,From}, {connection_info, Options}, _, D) ->
- Info = ssh_info(Options, D, []),
+ Info = fold_keys(Options, fun conn_info/2, D),
{keep_state_and_data, [{reply,From,Info}]};
handle_event({call,From}, {channel_info,ChannelId,Options}, _, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{} = Channel ->
- Info = ssh_channel_info(Options, Channel, []),
+ Info = fold_keys(Options, fun chann_info/2, Channel),
{keep_state_and_data, [{reply,From,Info}]};
undefined ->
{keep_state_and_data, [{reply,From,[]}]}
@@ -1158,17 +1198,17 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
ssh_message:decode(set_kex_overload_prefix(DecryptedBytes,D))
of
Msg = #ssh_msg_kexinit{} ->
- {keep_state, D, [{next_event, internal, {Msg,DecryptedBytes}},
- {next_event, internal, prepare_next_packet}
+ {keep_state, D, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, {Msg,DecryptedBytes}}
]};
Msg ->
- {keep_state, D, [{next_event, internal, Msg},
- {next_event, internal, prepare_next_packet}
+ {keep_state, D, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, Msg}
]}
catch
_C:_E ->
disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Encountered unexpected input"},
+ description = "Bad packet"},
StateName, D)
end;
@@ -1183,13 +1223,12 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
{bad_mac, Ssh1} ->
disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad mac"},
+ description = "Bad packet"},
StateName, D0#data{ssh_params=Ssh1});
- {error, {exceeds_max_size,PacketLen}} ->
+ {error, {exceeds_max_size,_PacketLen}} ->
disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad packet length "
- ++ integer_to_list(PacketLen)},
+ description = "Bad packet"},
StateName, D0)
catch
_C:_E ->
@@ -1206,16 +1245,20 @@ handle_event(internal, prepare_next_packet, _, D) ->
Sz when Sz >= Enough ->
self() ! {D#data.transport_protocol, D#data.socket, <<>>};
_ ->
- inet:setopts(D#data.socket, [{active, once}])
+ ok
end,
+ inet:setopts(D#data.socket, [{active, once}]),
keep_state_and_data;
handle_event(info, {CloseTag,Socket}, StateName,
D = #data{socket = Socket,
transport_close_tag = CloseTag}) ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Connection closed"},
- StateName, D);
+ %% Simulate a disconnect from the peer
+ handle_event(info,
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "Connection closed"},
+ StateName,
+ D);
handle_event(info, {timeout, {_, From} = Request}, _,
#data{connection_state = #connection{requests = Requests} = C0} = D) ->
@@ -1237,8 +1280,21 @@ handle_event(info, {'DOWN', _Ref, process, ChannelPid, _Reason}, _, D0) ->
{keep_state, D, Repls};
%%% So that terminate will be run when supervisor is shutdown
-handle_event(info, {'EXIT', _Sup, Reason}, _, _) ->
- {stop, {shutdown, Reason}};
+handle_event(info, {'EXIT', _Sup, Reason}, StateName, _) ->
+ Role = role(StateName),
+ if
+ Role == client ->
+ %% OTP-8111 tells this function clause fixes a problem in
+ %% clients, but there were no check for that role.
+ {stop, {shutdown, Reason}};
+
+ Reason == normal ->
+ %% An exit normal should not cause a server to crash. This has happend...
+ keep_state_and_data;
+
+ true ->
+ {stop, {shutdown, Reason}}
+ end;
handle_event(info, check_cache, _, D) ->
{keep_state, cache_check_set_idle_timer(D)};
@@ -1315,12 +1371,10 @@ terminate(shutdown, StateName, State0) ->
State = send_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
description = "Application shutdown"},
State0),
-timer:sleep(400), %% FIXME!!! gen_tcp:shutdown instead
finalize_termination(StateName, State);
%% terminate({shutdown,Msg}, StateName, State0) when is_record(Msg,ssh_msg_disconnect)->
%% State = send_msg(Msg, State0),
-%% timer:sleep(400), %% FIXME!!! gen_tcp:shutdown instead
%% finalize_termination(StateName, Msg, State);
terminate({shutdown,_R}, StateName, State) ->
@@ -1382,12 +1436,12 @@ fmt_stat_rec(FieldNames, Rec, Exclude) ->
state_name(),
#data{},
term()
- ) -> {gen_statem:callback_mode(), state_name(), #data{}}.
+ ) -> {ok, state_name(), #data{}}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
code_change(_OldVsn, StateName, State, _Extra) ->
- {handle_event_function, StateName, State}.
+ {ok, StateName, State}.
%%====================================================================
@@ -1434,7 +1488,7 @@ role({_,Role,_}) -> Role.
%%--------------------------------------------------------------------
%% Check the StateName to see if we are in the renegotiation phase
-renegotiation({_,_,ReNeg}) -> ReNeg == renegotiation;
+renegotiation({_,_,ReNeg}) -> ReNeg == renegotiate;
renegotiation(_) -> false.
%%--------------------------------------------------------------------
@@ -1476,7 +1530,8 @@ send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
State#data{ssh_params=Ssh}.
send_bytes(Bytes, #data{socket = Socket, transport_cb = Transport}) ->
- Transport:send(Socket, Bytes).
+ _ = Transport:send(Socket, Bytes),
+ ok.
handle_version({2, 0} = NumVsn, StrVsn, Ssh0) ->
Ssh = counterpart_versions(NumVsn, StrVsn, Ssh0),
@@ -1635,7 +1690,6 @@ new_channel_id(#data{connection_state = #connection{channel_id_seed = Id} =
disconnect(Msg=#ssh_msg_disconnect{description=Description}, _StateName, State0) ->
State = send_msg(Msg, State0),
disconnect_fun(Description, State),
-timer:sleep(400),
{stop, {shutdown,Description}, State}.
%%%----------------------------------------------------------------
@@ -1644,43 +1698,43 @@ counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) ->
counterpart_versions(NumVsn, StrVsn, #ssh{role = client} = Ssh) ->
Ssh#ssh{s_vsn = NumVsn , s_version = StrVsn}.
-ssh_info([], _State, Acc) ->
- Acc;
-ssh_info([client_version | Rest], #data{ssh_params = #ssh{c_vsn = IntVsn,
- c_version = StringVsn}} = State, Acc) ->
- ssh_info(Rest, State, [{client_version, {IntVsn, StringVsn}} | Acc]);
-
-ssh_info([server_version | Rest], #data{ssh_params =#ssh{s_vsn = IntVsn,
- s_version = StringVsn}} = State, Acc) ->
- ssh_info(Rest, State, [{server_version, {IntVsn, StringVsn}} | Acc]);
-ssh_info([peer | Rest], #data{ssh_params = #ssh{peer = Peer}} = State, Acc) ->
- ssh_info(Rest, State, [{peer, Peer} | Acc]);
-ssh_info([sockname | Rest], #data{socket = Socket} = State, Acc) ->
- {ok, SockName} = inet:sockname(Socket),
- ssh_info(Rest, State, [{sockname, SockName}|Acc]);
-ssh_info([user | Rest], #data{auth_user = User} = State, Acc) ->
- ssh_info(Rest, State, [{user, User}|Acc]);
-ssh_info([ _ | Rest], State, Acc) ->
- ssh_info(Rest, State, Acc).
-
-
-ssh_channel_info([], _, Acc) ->
- Acc;
+%%%----------------------------------------------------------------
+conn_info(client_version, #data{ssh_params=S}) -> {S#ssh.c_vsn, S#ssh.c_version};
+conn_info(server_version, #data{ssh_params=S}) -> {S#ssh.s_vsn, S#ssh.s_version};
+conn_info(peer, #data{ssh_params=S}) -> S#ssh.peer;
+conn_info(user, D) -> D#data.auth_user;
+conn_info(sockname, D) -> {ok, SockName} = inet:sockname(D#data.socket),
+ SockName;
+%% dbg options ( = not documented):
+conn_info(socket, D) -> D#data.socket;
+conn_info(chan_ids, D) ->
+ ssh_channel:cache_foldl(fun(#channel{local_id=Id}, Acc) ->
+ [Id | Acc]
+ end, [], cache(D)).
-ssh_channel_info([recv_window | Rest], #channel{recv_window_size = WinSize,
- recv_packet_size = Packsize
- } = Channel, Acc) ->
- ssh_channel_info(Rest, Channel, [{recv_window, {{win_size, WinSize},
- {packet_size, Packsize}}} | Acc]);
-ssh_channel_info([send_window | Rest], #channel{send_window_size = WinSize,
- send_packet_size = Packsize
- } = Channel, Acc) ->
- ssh_channel_info(Rest, Channel, [{send_window, {{win_size, WinSize},
- {packet_size, Packsize}}} | Acc]);
-ssh_channel_info([ _ | Rest], Channel, Acc) ->
- ssh_channel_info(Rest, Channel, Acc).
+%%%----------------------------------------------------------------
+chann_info(recv_window, C) ->
+ {{win_size, C#channel.recv_window_size},
+ {packet_size, C#channel.recv_packet_size}};
+chann_info(send_window, C) ->
+ {{win_size, C#channel.send_window_size},
+ {packet_size, C#channel.send_packet_size}};
+%% dbg options ( = not documented):
+chann_info(pid, C) ->
+ C#channel.user.
+%%%----------------------------------------------------------------
+%% Assisting meta function for the *_info functions
+fold_keys(Keys, Fun, Extra) ->
+ lists:foldr(fun(Key, Acc) ->
+ try Fun(Key, Extra) of
+ Value -> [{Key,Value}|Acc]
+ catch
+ _:_ -> Acc
+ end
+ end, [], Keys).
+%%%----------------------------------------------------------------
log_error(Reason) ->
Report = io_lib:format("Erlang ssh connection handler failed with reason:~n"
" ~p~n"
@@ -1689,7 +1743,6 @@ log_error(Reason) ->
[Reason, erlang:get_stacktrace()]),
error_logger:error_report(Report).
-
%%%----------------------------------------------------------------
not_connected_filter({connection_reply, _Data}) -> true;
not_connected_filter(_) -> false.
@@ -1701,6 +1754,11 @@ send_replies(Repls, State) ->
Repls).
get_repl({connection_reply,Msg}, {CallRepls,S}) ->
+ if is_record(Msg, ssh_msg_channel_success) ->
+ update_inet_buffers(S#data.socket);
+ true ->
+ ok
+ end,
{CallRepls, send_msg(Msg,S)};
get_repl({channel_data,undefined,_Data}, Acc) ->
Acc;
@@ -1889,3 +1947,13 @@ handshake(Pid, Ref, Timeout) ->
{error, timeout}
end.
+update_inet_buffers(Socket) ->
+ {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
+ MinVal = 655360,
+ case
+ [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
+ Val < MinVal]
+ of
+ [] -> ok;
+ NewOpts -> inet:setopts(Socket, NewOpts)
+ end.
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 480795cfc7..251741da7e 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,9 +24,13 @@
-export([messages/0,
messages/1,
+ messages/2,
stop/0
]).
+-export([shrink_bin/1,
+ wr_record/3]).
+
-include("ssh.hrl").
-include("ssh_transport.hrl").
-include("ssh_connect.hrl").
@@ -36,45 +40,72 @@
writer,
acc = []}).
%%%================================================================
-messages() -> messages(fun(String,_D) -> io:format(String) end).
-%% messages() -> messages(fun(String,Acc) -> [String|Acc] end)
+messages() ->
+ messages(fun(String,_D) -> io:format(String) end).
messages(Write) when is_function(Write,2) ->
+ messages(Write, fun(X) -> X end).
+
+messages(Write, MangleArg) when is_function(Write,2),
+ is_function(MangleArg,1) ->
catch dbg:start(),
- setup_tracer(Write),
- dbg:p(new,c),
+ setup_tracer(Write, MangleArg),
+ dbg:p(new,[c,timestamp]),
dbg_ssh_messages().
dbg_ssh_messages() ->
dbg:tp(ssh_message,encode,1, x),
dbg:tp(ssh_message,decode,1, x),
- dbg:tpl(ssh_transport,select_algorithm,3, x).
-
+ dbg:tpl(ssh_transport,select_algorithm,3, x),
+ dbg:tp(ssh_transport,hello_version_msg,1, x),
+ dbg:tp(ssh_transport,handle_hello_version,1, x).
+
%%%----------------------------------------------------------------
stop() ->
dbg:stop().
%%%================================================================
-msg_formater({trace,Pid,call,{ssh_message,encode,[Msg]}}, D) ->
- fmt("~nSEND ~p ~s~n", [Pid,wr_record(shrink_bin(Msg))], D);
-msg_formater({trace,_Pid,return_from,{ssh_message,encode,1},_Res}, D) ->
+msg_formater({trace_ts,Pid,call,{ssh_message,encode,[Msg]},TS}, D) ->
+ fmt("~n~s SEND ~p ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
+msg_formater({trace_ts,_Pid,return_from,{ssh_message,encode,1},_Res,_TS}, D) ->
D;
-msg_formater({trace,_Pid,call,{ssh_message,decode,_}}, D) ->
+msg_formater({trace_ts,_Pid,call,{ssh_message,decode,_},_TS}, D) ->
D;
-msg_formater({trace,Pid,return_from,{ssh_message,decode,1},Msg}, D) ->
- fmt("~nRECV ~p ~s~n", [Pid,wr_record(shrink_bin(Msg))], D);
+msg_formater({trace_ts,Pid,return_from,{ssh_message,decode,1},Msg,TS}, D) ->
+ fmt("~n~s ~p RECV ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
-msg_formater({trace,_Pid,call,{ssh_transport,select_algorithm,_}}, D) ->
+msg_formater({trace_ts,_Pid,call,{ssh_transport,select_algorithm,_},_TS}, D) ->
+ D;
+msg_formater({trace_ts,Pid,return_from,{ssh_transport,select_algorithm,3},{ok,Alg},TS}, D) ->
+ fmt("~n~s ~p ALGORITHMS~n~s~n", [ts(TS),Pid, wr_record(Alg)], D);
+
+msg_formater({trace_ts,_Pid,call,{ssh_transport,hello_version_msg,_},_TS}, D) ->
+ D;
+msg_formater({trace_ts,Pid,return_from,{ssh_transport,hello_version_msg,1},Hello,TS}, D) ->
+ fmt("~n~s ~p TCP SEND HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
+
+msg_formater({trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},TS}, D) ->
+ fmt("~n~s ~p RECV HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
+msg_formater({trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
D;
-msg_formater({trace,Pid,return_from,{ssh_transport,select_algorithm,3},{ok,Alg}}, D) ->
- fmt("~nALGORITHMS ~p~n~s~n", [Pid, wr_record(Alg)], D);
-msg_formater({trace,Pid,send,ErlangMsg,Dest}, D) ->
- fmt("~nERL MSG ~p SEND TO ~p~n ~p~n", [Pid,Dest, shrink_bin(ErlangMsg)], D);
+msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Pid,TS}, D) ->
+ fmt("~n~s ~p TCP SEND on ~p~n ~p~n", [ts(TS),Pid,Sock, shrink_bin(Bytes)], D);
+
+msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Dest,TS}, D) ->
+ fmt("~n~s ~p TCP SEND from ~p TO ~p~n ~p~n", [ts(TS),Pid,Sock,Dest, shrink_bin(Bytes)], D);
+
+msg_formater({trace_ts,Pid,send,ErlangMsg,Dest,TS}, D) ->
+ fmt("~n~s ~p ERL MSG SEND TO ~p~n ~p~n", [ts(TS),Pid,Dest, shrink_bin(ErlangMsg)], D);
+
+
+msg_formater({trace_ts,Pid,'receive',{tcp,Sock,Bytes},TS}, D) ->
+ fmt("~n~s ~p TCP RECEIVE on ~p~n ~p~n", [ts(TS),Pid,Sock,shrink_bin(Bytes)], D);
+
+msg_formater({trace_ts,Pid,'receive',ErlangMsg,TS}, D) ->
+ fmt("~n~s ~p ERL MSG RECEIVE~n ~p~n", [ts(TS),Pid,shrink_bin(ErlangMsg)], D);
-msg_formater({trace,Pid,'receive',ErlangMsg}, D) ->
- fmt("~nERL MSG ~p RECIEVE~n ~p~n", [Pid,shrink_bin(ErlangMsg)], D);
msg_formater(M, D) ->
fmt("~nDBG ~n~p~n", [shrink_bin(M)], D).
@@ -86,15 +117,27 @@ msg_formater(M, D) ->
fmt(Fmt, Args, D=#data{writer=Write,acc=Acc}) ->
D#data{acc = Write(io_lib:format(Fmt, Args), Acc)}.
+ts({_,_,Usec}=Now) ->
+ {_Date,{HH,MM,SS}} = calendar:now_to_local_time(Now),
+ io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
+ts(_) ->
+ "-".
%%%----------------------------------------------------------------
-setup_tracer(Write) ->
- Handler = fun msg_formater/2,
+setup_tracer(Write, MangleArg) ->
+ Handler = fun(Arg, D) ->
+ msg_formater(MangleArg(Arg), D)
+ end,
InitialData = #data{writer = Write},
{ok,_} = dbg:tracer(process, {Handler, InitialData}),
ok.
%%%----------------------------------------------------------------
-shrink_bin(B) when is_binary(B), size(B)>100 -> {'*** SHRINKED BIN',size(B),element(1,split_binary(B,20)),'***'};
+shrink_bin(B) when is_binary(B), size(B)>256 -> {'*** SHRINKED BIN',
+ size(B),
+ element(1,split_binary(B,64)),
+ '...',
+ element(2,split_binary(B,size(B)-64))
+ };
shrink_bin(L) when is_list(L) -> lists:map(fun shrink_bin/1, L);
shrink_bin(T) when is_tuple(T) -> list_to_tuple(shrink_bin(tuple_to_list(T)));
shrink_bin(X) -> X.
diff --git a/lib/ssh/src/ssh_dbg.hrl b/lib/ssh/src/ssh_dbg.hrl
new file mode 100644
index 0000000000..e94664737b
--- /dev/null
+++ b/lib/ssh/src/ssh_dbg.hrl
@@ -0,0 +1,27 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-ifndef(SSH_DBG_HRL).
+-define(SSH_DBG_HRL, 1).
+
+-define(formatrec(RecName,R),
+ ssh_dbg:wr_record(R, record_info(fields,RecName), [])).
+
+-endif. % SSH_DBG_HRL defined
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 0c24c09887..d464def6fa 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 026d0f6151..1d8f370884 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -31,56 +31,55 @@ read_line(Prompt, Ssh) ->
format("~s", [listify(Prompt)]),
proplists:get_value(user_pid, Ssh) ! {self(), question},
receive
- Answer ->
+ Answer when is_list(Answer) ->
Answer
end.
yes_no(Prompt, Ssh) ->
- io:format("~s [y/n]?", [Prompt]),
+ format("~s [y/n]?", [Prompt]),
proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question},
receive
- Answer ->
+ %% I can't see that the atoms y and n are ever received, but it must
+ %% be investigated before removing
+ y -> yes;
+ n -> no;
+
+ Answer when is_list(Answer) ->
case trim(Answer) of
"y" -> yes;
"n" -> no;
"Y" -> yes;
"N" -> no;
- y -> yes;
- n -> no;
_ ->
- io:format("please answer y or n\n"),
+ format("please answer y or n\n",[]),
yes_no(Prompt, Ssh)
end
end.
-read_password(Prompt, Ssh) ->
+read_password(Prompt, #ssh{opts=Opts}) -> read_password(Prompt, Opts);
+read_password(Prompt, Opts) when is_list(Opts) ->
format("~s", [listify(Prompt)]),
- case is_list(Ssh) of
- false ->
- proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), user_password};
- _ ->
- proplists:get_value(user_pid, Ssh) ! {self(), user_password}
- end,
+ proplists:get_value(user_pid, Opts) ! {self(), user_password},
receive
- Answer ->
- case Answer of
- "" ->
- read_password(Prompt, Ssh);
- Pass -> Pass
- end
+ Answer when is_list(Answer) ->
+ case trim(Answer) of
+ "" ->
+ read_password(Prompt, Opts);
+ Pwd ->
+ Pwd
+ end
end.
-listify(A) when is_atom(A) ->
- atom_to_list(A);
-listify(L) when is_list(L) ->
- L;
-listify(B) when is_binary(B) ->
- binary_to_list(B).
format(Fmt, Args) ->
io:format(Fmt, Args).
+%%%================================================================
+listify(A) when is_atom(A) -> atom_to_list(A);
+listify(L) when is_list(L) -> L;
+listify(B) when is_binary(B) -> binary_to_list(B).
+
trim(Line) when is_list(Line) ->
lists:reverse(trim1(lists:reverse(trim1(Line))));
@@ -93,6 +92,3 @@ trim1([$\r|Cs]) -> trim(Cs);
trim1([$\n|Cs]) -> trim(Cs);
trim1([$\t|Cs]) -> trim(Cs);
trim1(Cs) -> Cs.
-
-
-
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index dca018f20f..8589730438 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -384,10 +384,12 @@ handle_op(?SSH_FXP_REMOVE, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>,
case IsDir of %% This version 6 we still have ver 5
true when Vsn > 5 ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory");
+ ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory"),
+ State0;
true ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FAILURE, "File is a directory");
+ ?SSH_FX_FAILURE, "File is a directory"),
+ State0;
false ->
{Status, FS1} = FileMod:delete(Path, FS0),
State1 = State0#state{file_state = FS1},
@@ -664,29 +666,25 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 ->
do_open(ReqId, State, Path, Flags).
do_open(ReqId, State0, Path, Flags) ->
- #state{file_handler = FileMod, file_state = FS0, root = Root, xf = #ssh_xfer{vsn = Vsn}} = State0,
- XF = State0#state.xf,
- F = [binary | Flags],
- {IsDir, _FS1} = FileMod:is_dir(Path, FS0),
+ #state{file_handler = FileMod, file_state = FS0, xf = #ssh_xfer{vsn = Vsn}} = State0,
+ AbsPath = relate_file_name(Path, State0),
+ {IsDir, _FS1} = FileMod:is_dir(AbsPath, FS0),
case IsDir of
true when Vsn > 5 ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory");
+ ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory"),
+ State0;
true ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FAILURE, "File is a directory");
+ ?SSH_FX_FAILURE, "File is a directory"),
+ State0;
false ->
- AbsPath = case Root of
- "" ->
- Path;
- _ ->
- relate_file_name(Path, State0)
- end,
- {Res, FS1} = FileMod:open(AbsPath, F, FS0),
+ OpenFlags = [binary | Flags],
+ {Res, FS1} = FileMod:open(AbsPath, OpenFlags, FS0),
State1 = State0#state{file_state = FS1},
case Res of
{ok, IoDevice} ->
- add_handle(State1, XF, ReqId, file, {Path,IoDevice});
+ add_handle(State1, State0#state.xf, ReqId, file, {Path,IoDevice});
{error, Error} ->
ssh_xfer:xf_send_status(State1#state.xf, ReqId,
ssh_xfer:encode_erlang_status(Error)),
@@ -742,6 +740,10 @@ resolve_symlinks_2([], State, _LinkCnt, AccPath) ->
{{ok, AccPath}, State}.
+%% The File argument is always in a user visible file system, i.e.
+%% is under Root and is relative to CWD or Root, if starts with "/".
+%% The result of the function is always an absolute path in a
+%% "backend" file system.
relate_file_name(File, State) ->
relate_file_name(File, State, _Canonicalize=true).
@@ -749,19 +751,20 @@ relate_file_name(File, State, Canonicalize) when is_binary(File) ->
relate_file_name(unicode:characters_to_list(File), State, Canonicalize);
relate_file_name(File, #state{cwd = CWD, root = ""}, Canonicalize) ->
relate_filename_to_path(File, CWD, Canonicalize);
-relate_file_name(File, #state{root = Root}, Canonicalize) ->
- case is_within_root(Root, File) of
- true ->
- File;
- false ->
- RelFile = make_relative_filename(File),
- NewFile = relate_filename_to_path(RelFile, Root, Canonicalize),
- case is_within_root(Root, NewFile) of
- true ->
- NewFile;
- false ->
- Root
- end
+relate_file_name(File, #state{cwd = CWD, root = Root}, Canonicalize) ->
+ CWD1 = case is_within_root(Root, CWD) of
+ true -> CWD;
+ false -> Root
+ end,
+ AbsFile = case make_relative_filename(File) of
+ File ->
+ relate_filename_to_path(File, CWD1, Canonicalize);
+ RelFile ->
+ relate_filename_to_path(RelFile, Root, Canonicalize)
+ end,
+ case is_within_root(Root, AbsFile) of
+ true -> AbsFile;
+ false -> Root
end.
is_within_root(Root, File) ->
diff --git a/lib/ssh/src/ssh_sftpd_file_api.erl b/lib/ssh/src/ssh_sftpd_file_api.erl
index 78f452df67..81f181f1fc 100644
--- a/lib/ssh/src/ssh_sftpd_file_api.erl
+++ b/lib/ssh/src/ssh_sftpd_file_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@
-callback list_dir(file:name(), State::term()) ->
{{ok, Filenames::term()}, State::term()} | {{error, Reason::term()}, State::term()}.
-callback make_dir(Dir::term(), State::term()) ->
- {{ok, State::term()},State::term()} | {{error, Reason::term()}, State::term()}.
+ {ok, State::term()} | {{error, Reason::term()}, State::term()}.
-callback make_symlink(Path2::term(), Path::term(), State::term()) ->
{ok, State::term()} | {{error, Reason::term()}, State::term()}.
-callback open(Path::term(), Flags::term(), State::term()) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 7cb3b75ac0..a160309b95 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,9 +44,10 @@
handle_kexdh_reply/2,
handle_kex_ecdh_init/2,
handle_kex_ecdh_reply/2,
+ parallell_gen_key/1,
extract_public_key/1,
ssh_packet/2, pack/2,
- sign/3, verify/4]).
+ sha/1, sign/3, verify/4]).
%%% For test suites
-export([pack/3]).
@@ -296,9 +297,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
end.
-%% TODO: diffie-hellman-group14-sha1 should also be supported.
-%% Maybe check more things ...
-
verify_algorithm(#alg{kex = undefined}) -> false;
verify_algorithm(#alg{hkey = undefined}) -> false;
verify_algorithm(#alg{send_mac = undefined}) -> false;
@@ -316,17 +314,29 @@ verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)
key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ;
Kex == 'diffie-hellman-group14-sha1' ->
{G, P} = dh_group(Kex),
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Ssh0#ssh.algorithms),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0),
{ok, SshPacket,
Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}};
key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-group-exchange-sha1' ;
Kex == 'diffie-hellman-group-exchange-sha256' ->
- {Min,NBits,Max} =
+ {Min,NBits0,Max} =
proplists:get_value(dh_gex_limits, Opts, {?DEFAULT_DH_GROUP_MIN,
?DEFAULT_DH_GROUP_NBITS,
?DEFAULT_DH_GROUP_MAX}),
+ DhBits = dh_bits(Ssh0#ssh.algorithms),
+ NBits1 =
+ %% NIST Special Publication 800-57 Part 1 Revision 4: Recommendation for Key Management
+ if
+ DhBits =< 112 -> 2048;
+ DhBits =< 128 -> 3072;
+ DhBits =< 192 -> 7680;
+ true -> 8192
+ end,
+ NBits = min(max(max(NBits0,NBits1),Min), Max),
+
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_request{min = Min,
n = NBits,
@@ -350,12 +360,13 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
%%% diffie-hellman-group14-sha1
%%%
handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
- Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) ->
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex} = Algs}) ->
%% server
{G, P} = dh_group(Kex),
if
1=<E, E=<(P-1) ->
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Algs),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
K = compute_key(dh, E, Private, [P,G]),
MyPrivHostKey = get_host_key(Ssh0),
MyPubHostKey = extract_public_key(MyPrivHostKey),
@@ -426,13 +437,12 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0,
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
proplists:get_value(dh_gex_groups,Opts)) of
- {ok, {_Sz, {G,P}}} ->
- {Public, Private} = generate_key(dh, [P,G]),
+ {ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
- Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
- keyex_info = {Min, Max, NBits}
+ Ssh#ssh{keyex_key = {x, {G, P}},
+ keyex_info = {Min0, Max0, NBits}
}};
{error,_} ->
ssh_connection_handler:disconnect(
@@ -461,12 +471,11 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
proplists:get_value(dh_gex_groups,Opts)) of
- {ok, {_Sz, {G,P}}} ->
- {Public, Private} = generate_key(dh, [P,G]),
+ {ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
- Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
+ Ssh#ssh{keyex_key = {x, {G, P}},
keyex_info = {-1, -1, NBits} % flag for kex_h hash calc
}};
{error,_} ->
@@ -507,7 +516,8 @@ adjust_gex_min_max(Min0, Max0, Opts) ->
handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) ->
%% client
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Ssh0#ssh.algorithms),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), % Pub = G^Priv mod P (def)
@@ -734,12 +744,16 @@ public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
-accepted_host(Ssh, PeerName, Opts) ->
+accepted_host(Ssh, PeerName, Public, Opts) ->
case proplists:get_value(silently_accept_hosts, Opts, false) of
+ F when is_function(F,2) ->
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(Public)));
+ {DigestAlg,F} when is_function(F,2) ->
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(DigestAlg,Public)));
true ->
- yes;
+ true;
false ->
- yes_no(Ssh, "New host " ++ PeerName ++ " accept")
+ yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept")
end.
known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
@@ -749,10 +763,10 @@ known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
true ->
ok;
false ->
- case accepted_host(Ssh, PeerName, Opts) of
- yes ->
+ case accepted_host(Ssh, PeerName, Public, Opts) of
+ true ->
Mod:add_host_key(PeerName, Public, Opts);
- no ->
+ false ->
{error, rejected}
end
end.
@@ -1113,6 +1127,51 @@ verify(PlainText, Hash, Sig, Key) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Unit: bytes
+
+-record(cipher_data, {
+ key_bytes,
+ iv_bytes,
+ block_bytes
+ }).
+
+%%% Start of a more parameterized crypto handling.
+cipher('AEAD_AES_128_GCM') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 12,
+ block_bytes = 16};
+
+cipher('AEAD_AES_256_GCM') ->
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 12,
+ block_bytes = 16};
+
+cipher('3des-cbc') ->
+ #cipher_data{key_bytes = 24,
+ iv_bytes = 8,
+ block_bytes = 8};
+
+cipher('aes128-cbc') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes128-ctr') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes192-ctr') ->
+ #cipher_data{key_bytes = 24,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes256-ctr') ->
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 16,
+ block_bytes = 16}.
+
+
encrypt_init(#ssh{encrypt = none} = Ssh) ->
{ok, Ssh};
encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
@@ -1493,11 +1552,11 @@ send_mac_init(SSH) ->
common ->
case SSH#ssh.role of
client ->
- KeySize = mac_key_size(SSH#ssh.send_mac),
+ KeySize = 8*mac_key_bytes(SSH#ssh.send_mac),
Key = hash(SSH, "E", KeySize),
{ok, SSH#ssh { send_mac_key = Key }};
server ->
- KeySize = mac_key_size(SSH#ssh.send_mac),
+ KeySize = 8*mac_key_bytes(SSH#ssh.send_mac),
Key = hash(SSH, "F", KeySize),
{ok, SSH#ssh { send_mac_key = Key }}
end;
@@ -1516,10 +1575,10 @@ recv_mac_init(SSH) ->
common ->
case SSH#ssh.role of
client ->
- Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)),
+ Key = hash(SSH, "F", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }};
server ->
- Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)),
+ Key = hash(SSH, "E", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }}
end;
aead ->
@@ -1604,13 +1663,13 @@ kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
L = if Min==-1; Max==-1 ->
- %% flag from 'ssh_msg_kex_dh_gex_request_old'
- %% It was like this before that message was supported,
- %% why?
+ %% ssh_msg_kex_dh_gex_request_old
<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
- ?Empint(E), ?Empint(F), ?Empint(K)>>;
+ ?Euint32(NBits),
+ ?Empint(Prime), ?Empint(Gen), ?Empint(E), ?Empint(F), ?Empint(K)>>;
true ->
+ %% ssh_msg_kex_dh_gex_request
<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
?Euint32(Min), ?Euint32(NBits), ?Euint32(Max),
@@ -1619,6 +1678,11 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
+sha('ssh-rsa') -> sha;
+sha('ssh-dss') -> sha;
+sha('ecdsa-sha2-nistp256') -> sha(secp256r1);
+sha('ecdsa-sha2-nistp384') -> sha(secp384r1);
+sha('ecdsa-sha2-nistp521') -> sha(secp521r1);
sha(secp256r1) -> sha256;
sha(secp384r1) -> sha384;
sha(secp521r1) -> sha512;
@@ -1631,13 +1695,15 @@ sha(?'secp384r1') -> sha(secp384r1);
sha(?'secp521r1') -> sha(secp521r1).
-mac_key_size('hmac-sha1') -> 20*8;
-mac_key_size('hmac-sha1-96') -> 20*8;
-mac_key_size('hmac-md5') -> 16*8;
-mac_key_size('hmac-md5-96') -> 16*8;
-mac_key_size('hmac-sha2-256')-> 32*8;
-mac_key_size('hmac-sha2-512')-> 512;
-mac_key_size(none) -> 0.
+mac_key_bytes('hmac-sha1') -> 20;
+mac_key_bytes('hmac-sha1-96') -> 20;
+mac_key_bytes('hmac-md5') -> 16;
+mac_key_bytes('hmac-md5-96') -> 16;
+mac_key_bytes('hmac-sha2-256')-> 32;
+mac_key_bytes('hmac-sha2-512')-> 64;
+mac_key_bytes('AEAD_AES_128_GCM') -> 0;
+mac_key_bytes('AEAD_AES_256_GCM') -> 0;
+mac_key_bytes(none) -> 0.
mac_digest_size('hmac-sha1') -> 20;
mac_digest_size('hmac-sha1-96') -> 12;
@@ -1662,6 +1728,13 @@ dh_group('diffie-hellman-group1-sha1') -> ?dh_group1;
dh_group('diffie-hellman-group14-sha1') -> ?dh_group14.
%%%----------------------------------------------------------------
+parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
+ algorithms = Algs}) ->
+ Sz = dh_bits(Algs),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
+ Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
+
+
generate_key(Algorithm, Args) ->
{Public,Private} = crypto:generate_key(Algorithm, Args),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
@@ -1672,6 +1745,15 @@ compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
crypto:bytes_to_integer(Shared).
+dh_bits(#alg{encrypt = Encrypt,
+ send_mac = SendMac}) ->
+ C = cipher(Encrypt),
+ 8 * lists:max([C#cipher_data.key_bytes,
+ C#cipher_data.block_bytes,
+ C#cipher_data.iv_bytes,
+ mac_key_bytes(SendMac)
+ ]).
+
ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
ecdh_curve('ecdh-sha2-nistp521') -> secp521r1.
@@ -1745,12 +1827,6 @@ same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
trim_tail(Str) ->
- lists:reverse(trim_head(lists:reverse(Str))).
-
-trim_head([$\s|Cs]) -> trim_head(Cs);
-trim_head([$\t|Cs]) -> trim_head(Cs);
-trim_head([$\n|Cs]) -> trim_head(Cs);
-trim_head([$\r|Cs]) -> trim_head(Cs);
-trim_head(Cs) -> Cs.
-
-
+ lists:takewhile(fun(C) ->
+ C=/=$\r andalso C=/=$\n
+ end, Str).
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 6ce6d6f537..3fca78237c 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -52,7 +52,8 @@ MODULES= \
ssh_echo_server \
ssh_peername_sockname_server \
ssh_test_cli \
- ssh_relay
+ ssh_relay \
+ ssh_eqc_event_handler
HRL_FILES_NEEDED_IN_TEST= \
$(ERL_TOP)/lib/ssh/test/ssh_test_lib.hrl \
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
new file mode 100644
index 0000000000..c07140dc43
--- /dev/null
+++ b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
@@ -0,0 +1,92 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ssh_eqc_client_info_timing).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+%%-define(PROPER,true).
+%%-define(TRIQ,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+
+%%% Properties:
+
+prop_seq(_Config) ->
+ {ok,Pid} = ssh_eqc_event_handler:add_report_handler(),
+ {_, _, Port} = init_daemon(),
+ numtests(1000,
+ ?FORALL(Delay, choose(0,100),%% Micro seconds
+ try
+ send_bad_sequence(Port, Delay, Pid),
+ not any_relevant_error_report(Pid)
+ catch
+ C:E -> io:format('~p:~p~n',[C,E]),
+ false
+ end
+ )).
+
+send_bad_sequence(Port, Delay, Pid) ->
+ {ok,S} = gen_tcp:connect("localhost",Port,[]),
+ gen_tcp:send(S,"Illegal info-string\r\n"),
+ ssh_test_lib:sleep_microsec(Delay),
+ gen_tcp:close(S).
+
+any_relevant_error_report(Pid) ->
+ {ok, Reports} = ssh_eqc_event_handler:get_reports(Pid),
+ lists:any(fun({error_report,_,{_,supervisor_report,L}}) when is_list(L) ->
+ lists:member({reason,{badmatch,{error,closed}}}, L);
+ (_) ->
+ false
+ end, Reports).
+
+%%%================================================================
+init_daemon() ->
+ ok = begin ssh:stop(), ssh:start() end,
+ ssh_test_lib:daemon([]).
+
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index dc3b7dc7e6..410a9ea983 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -54,15 +54,18 @@
-endif.
-endif.
+%% Public key records:
+-include_lib("public_key/include/public_key.hrl").
%%% Properties:
prop_ssh_decode() ->
- ?FORALL(Msg, ssh_msg(),
- try ssh_message:decode(Msg)
+ ?FORALL({Msg,KexFam}, ?LET(KF, kex_family(), {ssh_msg(KF),KF} ),
+ try ssh_message:decode(decode_state(Msg,KexFam))
of
_ -> true
catch
+
C:E -> io:format('~p:~p~n',[C,E]),
false
end
@@ -71,122 +74,101 @@ prop_ssh_decode() ->
%%% This fails because ssh_message is not symmetric in encode and decode regarding data types
prop_ssh_decode_encode() ->
- ?FORALL(Msg, ssh_msg(),
- Msg == ssh_message:encode(ssh_message:decode(Msg))
+ ?FORALL({Msg,KexFam}, ?LET(KF, kex_family(), {ssh_msg(KF),KF} ),
+ Msg == ssh_message:encode(
+ fix_asym(
+ ssh_message:decode(decode_state(Msg,KexFam))))
).
%%%================================================================
%%%
-%%% Scripts to generate message generators
-%%%
-
-%% awk '/^( |\t)+byte( |\t)+SSH/,/^( |\t)*$/{print}' rfc425?.txt | sed 's/^\( \|\\t\)*//' > msgs.txt
-
-%% awk '/^byte( |\t)+SSH/{print $2","}' < msgs.txt
-
-%% awk 'BEGIN{print "%%%---- BEGIN GENERATED";prev=0} END{print " >>.\n%%%---- END GENERATED"} /^byte( |\t)+SSH/{if (prev==1) print " >>.\n"; prev=1; printf "%c%s%c",39,$2,39; print "()->\n <<?"$2;next} /^string( |\t)+\"/{print " ,"$2;next} /^string( |\t)+.*address/{print " ,(ssh_string_address())/binary %%",$2,$3,$4,$5,$6;next}/^string( |\t)+.*US-ASCII/{print " ,(ssh_string_US_ASCII())/binary %%",$2,$3,$4,$5,$6;next} /^string( |\t)+.*UTF-8/{print " ,(ssh_string_UTF_8())/binary %% ",$2,$3,$4,$5,$6;next} /^[a-z0-9]+( |\t)/{print " ,(ssh_"$1"())/binary %%",$2,$3,$4,$5,$6;next} /^byte\[16\]( |\t)+/{print" ,(ssh_byte_16())/binary %%",$2,$3,$4,$5,$6;next} /^name-list( |\t)+/{print" ,(ssh_name_list())/binary %%",$2,$3,$4,$5,$6;next} /./{print "?? %%",$0}' < msgs.txt > gen.txt
-
-%%%================================================================
-%%%
%%% Generators
%%%
-ssh_msg() -> ?LET(M,oneof(
-[[msg_code('SSH_MSG_CHANNEL_CLOSE'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_DATA'),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_EOF'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_EXTENDED_DATA'),gen_uint32(),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_FAILURE'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("direct-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("forwarded-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("session"),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("x11"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN_CONFIRMATION'),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN_FAILURE'),gen_uint32(),gen_uint32(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("env"),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exec"),gen_boolean(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-signal"),0,gen_string( ),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-status"),0,gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("pty-req"),gen_boolean(),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("shell"),gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("signal"),0,gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("subsystem"),gen_boolean(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("window-change"),0,gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("x11-req"),gen_boolean(),gen_boolean(),gen_string( ),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("xon-xoff"),0,gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string( ),gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_SUCCESS'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_WINDOW_ADJUST'),gen_uint32(),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_DEBUG'),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_DISCONNECT'),gen_uint32(),gen_string( ),gen_string( )],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("cancel-tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string( ),gen_boolean()],
- [msg_code('SSH_MSG_IGNORE'),gen_string( )],
- %% [msg_code('SSH_MSG_KEXDH_INIT'),gen_mpint()],
- %% [msg_code('SSH_MSG_KEXDH_REPLY'),gen_string( ),gen_mpint(),gen_string( )],
- %% [msg_code('SSH_MSG_KEXINIT'),gen_byte(16),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_boolean(),gen_uint32()],
- [msg_code('SSH_MSG_KEX_DH_GEX_GROUP'),gen_mpint(),gen_mpint()],
- [msg_code('SSH_MSG_NEWKEYS')],
- [msg_code('SSH_MSG_REQUEST_FAILURE')],
- [msg_code('SSH_MSG_REQUEST_SUCCESS')],
- [msg_code('SSH_MSG_REQUEST_SUCCESS'),gen_uint32()],
- [msg_code('SSH_MSG_SERVICE_ACCEPT'),gen_string( )],
- [msg_code('SSH_MSG_SERVICE_REQUEST'),gen_string( )],
- [msg_code('SSH_MSG_UNIMPLEMENTED'),gen_uint32()],
- [msg_code('SSH_MSG_USERAUTH_BANNER'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_FAILURE'),gen_name_list(),gen_boolean()],
- [msg_code('SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_PK_OK'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_SUCCESS')]
-]
-
-), list_to_binary(M)).
-
-
-%%%================================================================
-%%%
-%%% Generator
-%%%
-
-do() ->
- io_lib:format('[~s~n]',
- [write_gen(
- files(["rfc4254.txt",
- "rfc4253.txt",
- "rfc4419.txt",
- "rfc4252.txt",
- "rfc4256.txt"]))]).
-
-
-write_gen(L) when is_list(L) ->
- string:join(lists:map(fun write_gen/1, L), ",\n ");
-write_gen({MsgName,Args}) ->
- lists:flatten(["[",generate_args([MsgName|Args]),"]"]).
-
-generate_args(As) -> string:join([generate_arg(A) || A <- As], ",").
-
-generate_arg({<<"string">>, <<"\"",B/binary>>}) ->
- S = get_string($",B),
- ["gen_string(\"",S,"\")"];
-generate_arg({<<"string">>, _}) -> "gen_string( )";
-generate_arg({<<"byte[",B/binary>>, _}) ->
- io_lib:format("gen_byte(~p)",[list_to_integer(get_string($],B))]);
-generate_arg({<<"byte">> ,_}) -> "gen_byte()";
-generate_arg({<<"uint16">>,_}) -> "gen_uint16()";
-generate_arg({<<"uint32">>,_}) -> "gen_uint32()";
-generate_arg({<<"uint64">>,_}) -> "gen_uint64()";
-generate_arg({<<"mpint">>,_}) -> "gen_mpint()";
-generate_arg({<<"name-list">>,_}) -> "gen_name_list()";
-generate_arg({<<"boolean">>,<<"FALSE">>}) -> "0";
-generate_arg({<<"boolean">>,<<"TRUE">>}) -> "1";
-generate_arg({<<"boolean">>,_}) -> "gen_boolean()";
-generate_arg({<<"....">>,_}) -> ""; %% FIXME
-generate_arg(Name) when is_binary(Name) ->
- lists:flatten(["msg_code('",binary_to_list(Name),"')"]).
-
+ssh_msg(<<"dh">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEXDH_INIT'),gen_mpint()], % 30
+ [msg_code('SSH_MSG_KEXDH_REPLY'),gen_pubkey_string(rsa),gen_mpint(),gen_signature_string(rsa)] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M));
+
+ssh_msg(<<"dh_gex">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEX_DH_GEX_REQUEST_OLD'),gen_uint32()], % 30
+ [msg_code('SSH_MSG_KEX_DH_GEX_GROUP'),gen_mpint(),gen_mpint()] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M));
+
+ ssh_msg(<<"ecdh">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEX_ECDH_INIT'),gen_mpint()], % 30
+ [msg_code('SSH_MSG_KEX_ECDH_REPLY'),gen_pubkey_string(ecdsa),gen_mpint(),gen_signature_string(ecdsa)] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M)).
+
+
+rest_ssh_msgs() ->
+ [%% SSH_MSG_USERAUTH_INFO_RESPONSE
+ %% hard args SSH_MSG_USERAUTH_INFO_REQUEST
+ %% rfc4252 p12 error SSH_MSG_USERAUTH_REQUEST
+ [msg_code('SSH_MSG_KEX_DH_GEX_REQUEST'),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_KEX_DH_GEX_INIT'),gen_mpint()],
+ [msg_code('SSH_MSG_KEX_DH_GEX_REPLY'),gen_pubkey_string(rsa),gen_mpint(),gen_signature_string(rsa)],
+ [msg_code('SSH_MSG_CHANNEL_CLOSE'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_DATA'),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_EOF'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_EXTENDED_DATA'),gen_uint32(),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_FAILURE'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("direct-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("forwarded-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("session"),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("x11"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN_CONFIRMATION'),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN_FAILURE'),gen_uint32(),gen_uint32(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("env"),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exec"),gen_boolean(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-signal"),0,gen_string( ),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-status"),0,gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("pty-req"),gen_boolean(),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("shell"),gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("signal"),0,gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("subsystem"),gen_boolean(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("window-change"),0,gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("x11-req"),gen_boolean(),gen_boolean(),gen_string( ),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("xon-xoff"),0,gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string( ),gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_SUCCESS'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_WINDOW_ADJUST'),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_DEBUG'),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_DISCONNECT'),gen_uint32(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("cancel-tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string( ),gen_boolean()],
+ [msg_code('SSH_MSG_IGNORE'),gen_string( )],
+ [msg_code('SSH_MSG_KEXINIT'),gen_byte(16),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_boolean(),gen_uint32()],
+ [msg_code('SSH_MSG_NEWKEYS')],
+ [msg_code('SSH_MSG_REQUEST_FAILURE')],
+ [msg_code('SSH_MSG_REQUEST_SUCCESS')],
+ [msg_code('SSH_MSG_REQUEST_SUCCESS'),gen_uint32()],
+ [msg_code('SSH_MSG_SERVICE_ACCEPT'),gen_string( )],
+ [msg_code('SSH_MSG_SERVICE_REQUEST'),gen_string( )],
+ [msg_code('SSH_MSG_UNIMPLEMENTED'),gen_uint32()],
+ [msg_code('SSH_MSG_USERAUTH_BANNER'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_FAILURE'),gen_name_list(),gen_boolean()],
+ [msg_code('SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_PK_OK'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_SUCCESS')]
+ ].
+
+kex_family() -> oneof([<<"dh">>, <<"dh_gex">>, <<"ecdh">>]).
gen_boolean() -> choose(0,1).
@@ -202,10 +184,7 @@ gen_byte(N) when N>0 -> [gen_byte() || _ <- lists:seq(1,N)].
gen_char() -> choose($a,$z).
-gen_mpint() -> ?LET(Size, choose(1,20),
- ?LET(Str, vector(Size, gen_byte()),
- gen_string( strip_0s(Str) )
- )).
+gen_mpint() -> ?LET(I, largeint(), ssh_bits:mpint(I)).
strip_0s([0|T]) -> strip_0s(T);
strip_0s(X) -> X.
@@ -230,13 +209,22 @@ gen_name() -> gen_string().
uint32_to_list(I) -> binary_to_list(<<I:32/unsigned-big-integer>>).
-%%%----
-get_string(Delim, B) ->
- binary_to_list( element(1, split_binary(B, count_string_chars(Delim,B,0))) ).
-
-count_string_chars(Delim, <<Delim,_/binary>>, Acc) -> Acc;
-count_string_chars(Delim, <<_,B/binary>>, Acc) -> count_string_chars(Delim, B, Acc+1).
+gen_pubkey_string(Type) ->
+ PubKey = case Type of
+ rsa -> #'RSAPublicKey'{modulus = 12345,publicExponent = 2};
+ ecdsa -> {#'ECPoint'{point=[1,2,3,4,5]},
+ {namedCurve,{1,2,840,10045,3,1,7}}} % 'secp256r1' nistp256
+ end,
+ gen_string(public_key:ssh_encode(PubKey, ssh2_pubkey)).
+
+gen_signature_string(Type) ->
+ Signature = <<"hejhopp">>,
+ Id = case Type of
+ rsa -> "ssh-rsa";
+ ecdsa -> "ecdsa-sha2-nistp256"
+ end,
+ gen_string(gen_string(Id) ++ gen_string(Signature)).
-define(MSG_CODE(Name,Num),
msg_code(Name) -> Num;
@@ -273,124 +261,34 @@ msg_code(Num) -> Name
?MSG_CODE('SSH_MSG_CHANNEL_FAILURE', 100);
?MSG_CODE('SSH_MSG_USERAUTH_INFO_REQUEST', 60);
?MSG_CODE('SSH_MSG_USERAUTH_INFO_RESPONSE', 61);
+?MSG_CODE('SSH_MSG_KEXDH_INIT', 30);
+?MSG_CODE('SSH_MSG_KEXDH_REPLY', 31);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_REQUEST_OLD', 30);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_REQUEST', 34);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_GROUP', 31);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_INIT', 32);
-?MSG_CODE('SSH_MSG_KEX_DH_GEX_REPLY', 33).
-
-%%%=============================================================================
-%%%=============================================================================
-%%%=============================================================================
-
-files(Fs) ->
- Defs = lists:usort(lists:flatten(lists:map(fun file/1, Fs))),
- DefinedIDs = lists:usort([binary_to_list(element(1,D)) || D <- Defs]),
- WantedIDs = lists:usort(wanted_messages()),
- Missing = WantedIDs -- DefinedIDs,
- case Missing of
- [] -> ok;
- _ -> io:format('%% Warning: missing ~p~n', [Missing])
- end,
- Defs.
-
-
-file(F) ->
- {ok,B} = file:read_file(F),
- hunt_msg_def(B).
-
-
-hunt_msg_def(<<"\n",B/binary>>) -> some_hope(skip_blanks(B));
-hunt_msg_def(<<_, B/binary>>) -> hunt_msg_def(B);
-hunt_msg_def(<<>>) -> [].
-
-some_hope(<<"byte ", B/binary>>) -> try_message(skip_blanks(B));
-some_hope(B) -> hunt_msg_def(B).
-
-try_message(B = <<"SSH_MSG_",_/binary>>) ->
- {ID,Rest} = get_id(B),
- case lists:member(binary_to_list(ID), wanted_messages()) of
- true ->
- {Lines,More} = get_def_lines(skip_blanks(Rest), []),
- [{ID,lists:reverse(Lines)} | hunt_msg_def(More)];
- false ->
- hunt_msg_def(Rest)
- end;
-try_message(B) -> hunt_msg_def(B).
-
-
-skip_blanks(<<32, B/binary>>) -> skip_blanks(B);
-skip_blanks(<< 9, B/binary>>) -> skip_blanks(B);
-skip_blanks(B) -> B.
-
-get_def_lines(B0 = <<"\n",B/binary>>, Acc) ->
- {ID,Rest} = get_id(skip_blanks(B)),
- case {size(ID), skip_blanks(Rest)} of
- {0,<<"....",More/binary>>} ->
- {Text,LineEnd} = get_to_eol(skip_blanks(More)),
- get_def_lines(LineEnd, [{<<"....">>,Text}|Acc]);
- {0,_} ->
- {Acc,B0};
- {_,Rest1} ->
- {Text,LineEnd} = get_to_eol(Rest1),
- get_def_lines(LineEnd, [{ID,Text}|Acc])
- end;
-get_def_lines(B, Acc) ->
- {Acc,B}.
-
-
-get_to_eol(B) -> split_binary(B, count_to_eol(B,0)).
-
-count_to_eol(<<"\n",_/binary>>, Acc) -> Acc;
-count_to_eol(<<>>, Acc) -> Acc;
-count_to_eol(<<_,B/binary>>, Acc) -> count_to_eol(B,Acc+1).
-
-
-get_id(B) -> split_binary(B, count_id_chars(B,0)).
-
-count_id_chars(<<C,B/binary>>, Acc) when $A=<C,C=<$Z -> count_id_chars(B,Acc+1);
-count_id_chars(<<C,B/binary>>, Acc) when $a=<C,C=<$z -> count_id_chars(B,Acc+1);
-count_id_chars(<<C,B/binary>>, Acc) when $0=<C,C=<$9 -> count_id_chars(B,Acc+1);
-count_id_chars(<<"_",B/binary>>, Acc) -> count_id_chars(B,Acc+1);
-count_id_chars(<<"-",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g name-list
-count_id_chars(<<"[",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g byte[16]
-count_id_chars(<<"]",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g byte[16]
-count_id_chars(_, Acc) -> Acc.
-
-wanted_messages() ->
- ["SSH_MSG_CHANNEL_CLOSE",
- "SSH_MSG_CHANNEL_DATA",
- "SSH_MSG_CHANNEL_EOF",
- "SSH_MSG_CHANNEL_EXTENDED_DATA",
- "SSH_MSG_CHANNEL_FAILURE",
- "SSH_MSG_CHANNEL_OPEN",
- "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
- "SSH_MSG_CHANNEL_OPEN_FAILURE",
- "SSH_MSG_CHANNEL_REQUEST",
- "SSH_MSG_CHANNEL_SUCCESS",
- "SSH_MSG_CHANNEL_WINDOW_ADJUST",
- "SSH_MSG_DEBUG",
- "SSH_MSG_DISCONNECT",
- "SSH_MSG_GLOBAL_REQUEST",
- "SSH_MSG_IGNORE",
- "SSH_MSG_KEXDH_INIT",
- "SSH_MSG_KEXDH_REPLY",
- "SSH_MSG_KEXINIT",
- "SSH_MSG_KEX_DH_GEX_GROUP",
- "SSH_MSG_KEX_DH_GEX_REQUEST",
- "SSH_MSG_KEX_DH_GEX_REQUEST_OLD",
- "SSH_MSG_NEWKEYS",
- "SSH_MSG_REQUEST_FAILURE",
- "SSH_MSG_REQUEST_SUCCESS",
- "SSH_MSG_SERVICE_ACCEPT",
- "SSH_MSG_SERVICE_REQUEST",
- "SSH_MSG_UNIMPLEMENTED",
- "SSH_MSG_USERAUTH_BANNER",
- "SSH_MSG_USERAUTH_FAILURE",
-%% hard args "SSH_MSG_USERAUTH_INFO_REQUEST",
-%% "SSH_MSG_USERAUTH_INFO_RESPONSE",
- "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
- "SSH_MSG_USERAUTH_PK_OK",
-%%rfc4252 p12 error "SSH_MSG_USERAUTH_REQUEST",
- "SSH_MSG_USERAUTH_SUCCESS"].
+?MSG_CODE('SSH_MSG_KEX_DH_GEX_REPLY', 33);
+?MSG_CODE('SSH_MSG_KEX_ECDH_INIT', 30);
+?MSG_CODE('SSH_MSG_KEX_ECDH_REPLY', 31).
+
+%%%====================================================
+%%%=== WARNING: Knowledge of the test object ahead! ===
+%%%====================================================
+
+%% SSH message records:
+-include_lib("ssh/src/ssh_connect.hrl").
+-include_lib("ssh/src/ssh_transport.hrl").
+
+%%% Encoding and decodeing is asymetric so out=binary in=string. Sometimes. :(
+fix_asym(#ssh_msg_global_request{name=N} = M) -> M#ssh_msg_global_request{name = binary_to_list(N)};
+fix_asym(#ssh_msg_debug{message=D,language=L} = M) -> M#ssh_msg_debug{message = binary_to_list(D),
+ language = binary_to_list(L)};
+fix_asym(#ssh_msg_kexinit{cookie=C} = M) -> M#ssh_msg_kexinit{cookie = <<C:128>>};
+fix_asym(M) -> M.
+
+%%% Message codes 30 and 31 are overloaded depending on kex family so arrange the decoder
+%%% input as the test object does
+decode_state(<<30,_/binary>>=Msg, KexFam) -> <<KexFam/binary, Msg/binary>>;
+decode_state(<<31,_/binary>>=Msg, KexFam) -> <<KexFam/binary, Msg/binary>>;
+decode_state(Msg, _) -> Msg.
diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover
index a4221fbbbe..69d2a1c4f8 100644
--- a/lib/ssh/test/ssh.cover
+++ b/lib/ssh/test/ssh.cover
@@ -1,2 +1,3 @@
{incl_app,ssh,details}.
+{excl_mods, ssh, [ssh_dbg, ssh_info, ssh_server_key_api, ssh_sftpd_file_api]}. \ No newline at end of file
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 0f68130a05..28a013ea33 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,9 +58,11 @@ groups() ->
|| {Tag,Algs} <- ErlAlgos,
lists:member(Tag,tags())
],
+
+ TypeSSH = ssh_test_lib:ssh_type(),
AlgoTcSet =
- [{Alg, [parallel], specific_test_cases(Tag,Alg,SshcAlgos,SshdAlgos)}
+ [{Alg, [parallel], specific_test_cases(Tag,Alg,SshcAlgos,SshdAlgos,TypeSSH)}
|| {Tag,Algs} <- ErlAlgos ++ DoubleAlgos,
Alg <- Algs],
@@ -180,38 +182,35 @@ simple_exec(Config) ->
%%--------------------------------------------------------------------
%% Testing if no group matches
simple_exec_groups_no_match_too_small(Config) ->
- try simple_exec_group({400,500,600}, Config)
- of
- _ -> ct:fail("Exec though no group available")
- catch
- error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} ->
- ok
- end.
+ try_exec_simple_group({400,500,600}, Config).
simple_exec_groups_no_match_too_large(Config) ->
- try simple_exec_group({9200,9500,9700}, Config)
+ try_exec_simple_group({9200,9500,9700}, Config).
+
+
+try_exec_simple_group(Group, Config) ->
+ try simple_exec_group(Group, Config)
of
_ -> ct:fail("Exec though no group available")
catch
- error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} ->
- ok
+ error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} -> ok;
+ error:{badmatch,{error,"Connection closed"}} -> ok
end.
%%--------------------------------------------------------------------
%% Testing all default groups
-simple_exec_groups() -> [{timetrap,{minutes,5}}].
-
+simple_exec_groups() ->
+ [{timetrap,{seconds,120}}].
+
simple_exec_groups(Config) ->
Sizes = interpolate( public_key:dh_gex_group_sizes() ),
lists:foreach(
fun(Sz) ->
ct:log("Try size ~p",[Sz]),
ct:comment(Sz),
- case simple_exec_group(Sz, Config) of
- expected -> ct:log("Size ~p ok",[Sz]);
- _ -> ct:log("Size ~p not ok",[Sz])
- end
+ simple_exec_group(Sz, Config),
+ ct:log("Size ~p ok",[Sz])
end, Sizes),
ct:comment("~p",[lists:map(fun({_,I,_}) -> I;
(I) -> I
@@ -319,18 +318,13 @@ concat(A1, A2) -> list_to_atom(lists:concat([A1," + ",A2])).
split(Alg) -> ssh_test_lib:to_atoms(string:tokens(atom_to_list(Alg), " + ")).
-specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos) ->
+specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos, TypeSSH) ->
[simple_exec, simple_sftp] ++
case supports(Tag, Alg, SshcAlgos) of
- true ->
- case ssh_test_lib:ssh_type() of
- openSSH ->
- [sshc_simple_exec_os_cmd];
- _ ->
- []
- end;
- false ->
- []
+ true when TypeSSH == openSSH ->
+ [sshc_simple_exec_os_cmd];
+ _ ->
+ []
end ++
case supports(Tag, Alg, SshdAlgos) of
true ->
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 733414e23a..0a0ab5cdf7 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -50,7 +50,12 @@
inet6_option/1,
inet_option/1,
internal_error/1,
- known_hosts/1,
+ known_hosts/1,
+ login_bad_pwd_no_retry1/1,
+ login_bad_pwd_no_retry2/1,
+ login_bad_pwd_no_retry3/1,
+ login_bad_pwd_no_retry4/1,
+ login_bad_pwd_no_retry5/1,
misc_ssh_options/1,
openssh_zlib_basic_test/1,
packet_size_zero/1,
@@ -62,7 +67,8 @@
shell_unicode_string/1,
ssh_info_print/1,
key_callback/1,
- key_callback_options/1
+ key_callback_options/1,
+ shell_exit_status/1
]).
%%% Common test callbacks
@@ -100,7 +106,9 @@ all() ->
daemon_opt_fd,
multi_daemon_opt_fd,
packet_size_zero,
- ssh_info_print
+ ssh_info_print,
+ {group, login_bad_pwd_no_retry},
+ shell_exit_status
].
groups() ->
@@ -116,7 +124,13 @@ groups() ->
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{key_cb, [], [key_callback, key_callback_options]},
- {internal_error, [], [internal_error]}
+ {internal_error, [], [internal_error]},
+ {login_bad_pwd_no_retry, [], [login_bad_pwd_no_retry1,
+ login_bad_pwd_no_retry2,
+ login_bad_pwd_no_retry3,
+ login_bad_pwd_no_retry4,
+ login_bad_pwd_no_retry5
+ ]}
].
@@ -301,9 +315,9 @@ init_per_testcase(TC, Config) when TC==shell_no_unicode ;
{user_passwords, [{"foo", "bar"}]}]),
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir,
- [{silently_accept_hosts, true},
- {user,"foo"},{password,"bar"}]),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {silently_accept_hosts, true},
+ {user,"foo"},{password,"bar"}]),
ct:log("IO=~p, Shell=~p, self()=~p",[IO,Shell,self()]),
ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p",
[file:native_name_encoding(),io:getopts()]),
@@ -329,14 +343,15 @@ end_per_testcase(TC, Config) when TC==shell_no_unicode ;
TC==shell_unicode_string ->
case proplists:get_value(sftpd, Config) of
{Pid, _, _} ->
- ssh:stop_daemon(Pid),
- ssh:stop();
+ catch ssh:stop_daemon(Pid);
_ ->
- ssh:stop()
- end;
+ ok
+ end,
+ end_per_testcase(Config);
end_per_testcase(_TestCase, Config) ->
end_per_testcase(Config).
-end_per_testcase(_Config) ->
+
+end_per_testcase(_Config) ->
ssh:stop(),
ok.
@@ -510,7 +525,7 @@ shell(Config) when is_list(Config) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir}]),
receive
{'EXIT', _, _} ->
ct:fail(no_ssh_connection);
@@ -548,10 +563,10 @@ exec_key_differs(Config, UserPKAlgs) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir,
- [{preferred_algorithms,[{public_key,['ssh-rsa']}]},
- {pref_public_key_algs,UserPKAlgs}
- ]),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {preferred_algorithms,[{public_key,['ssh-rsa']}]},
+ {pref_public_key_algs,UserPKAlgs}
+ ]),
receive
@@ -582,9 +597,9 @@ exec_key_differs_fail(Config) when is_list(Config) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- ssh_test_lib:start_shell(Port, IO, UserDir,
- [{preferred_algorithms,[{public_key,['ssh-rsa']}]},
- {pref_public_key_algs,['ssh-dss']}]),
+ ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {preferred_algorithms,[{public_key,['ssh-rsa']}]},
+ {pref_public_key_algs,['ssh-dss']}]),
receive
{'EXIT', _, _} ->
ok;
@@ -1090,6 +1105,99 @@ ssh_info_print(Config) ->
%%--------------------------------------------------------------------
+%% Check that a basd pwd is not tried more times. Could cause lock-out
+%% on server
+
+login_bad_pwd_no_retry1(Config) ->
+ login_bad_pwd_no_retry(Config, "keyboard-interactive,password").
+
+login_bad_pwd_no_retry2(Config) ->
+ login_bad_pwd_no_retry(Config, "password,keyboard-interactive").
+
+login_bad_pwd_no_retry3(Config) ->
+ login_bad_pwd_no_retry(Config, "password,publickey,keyboard-interactive").
+
+login_bad_pwd_no_retry4(Config) ->
+ login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive").
+
+login_bad_pwd_no_retry5(Config) ->
+ login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive,password,password").
+
+
+
+
+
+login_bad_pwd_no_retry(Config, AuthMethods) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ Parent = self(),
+ PwdFun = fun(_, _, _, undefined) -> {false, 1};
+ (_, _, _, _) -> Parent ! retry_bad_pwd,
+ false
+ end,
+
+ {DaemonRef, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {auth_methods, AuthMethods},
+ {user_passwords, [{"foo","somepwd"}]},
+ {pwdfun, PwdFun}
+ ]),
+
+ ConnRes = ssh:connect("localhost", Port,
+ [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "badpwd"},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+
+ receive
+ retry_bad_pwd ->
+ ssh:stop_daemon(DaemonRef),
+ {fail, "Retry bad password"}
+ after 0 ->
+ case ConnRes of
+ {error,"Unable to connect using the available authentication methods"} ->
+ ssh:stop_daemon(DaemonRef),
+ ok;
+ {ok,Conn} ->
+ ssh:close(Conn),
+ ssh:stop_daemon(DaemonRef),
+ {fail, "Connect erroneosly succeded"}
+ end
+ end.
+
+
+%%----------------------------------------------------------------------------
+%%% Test that when shell REPL exit with reason normal client receives status 0
+shell_exit_status(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ ShellFun = fun (_User) -> spawn(fun() -> ok end) end,
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"vego", "morot"}]},
+ {shell, ShellFun},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user, "vego"},
+ {password, "morot"},
+ {user_interaction, false}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ok = ssh_connection:shell(ConnectionRef, ChannelId),
+ ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
+ ssh:stop_daemon(Pid).
+
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
%% Due to timing the error message may or may not be delivered to
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
index c2bfc48449..f3ed6a5b9b 100644
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -1,7 +1,7 @@
%%%-------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]},
- {timetrap,{minutes,3}}
+ {timetrap,{minutes,6}}
].
%%suite() -> [{ct_hooks,[ts_install_cth]}].
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index bcf3b01824..952fb8da99 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -45,6 +45,8 @@ all() ->
{group, openssh},
small_interrupted_send,
interrupted_send,
+ exec_erlang_term,
+ exec_erlang_term_non_default_shell,
start_shell,
start_shell_exec,
start_shell_exec_fun,
@@ -381,13 +383,13 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
{password, "morot"},
{subsystems, [{"echo_n",EchoSS_spec}]}]),
- ct:log("connect", []),
+ ct:log("~p:~p connect", [?MODULE,?LINE]),
ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
{password, "morot"},
{user_interaction, false},
{user_dir, UserDir}]),
- ct:log("connected", []),
+ ct:log("~p:~p connected", [?MODULE,?LINE]),
%% build big binary
Data = << <<X:32>> || X <- lists:seq(1,SendSize div 4)>>,
@@ -399,58 +401,80 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
Parent = self(),
ResultPid = spawn(
fun() ->
- ct:log("open channel",[]),
+ ct:log("~p:~p open channel",[?MODULE,?LINE]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- ct:log("start subsystem", []),
+ ct:log("~p:~p start subsystem", [?MODULE,?LINE]),
case ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity) of
success ->
Parent ! {self(), channelId, ChannelId},
Result =
- try collect_data(ConnectionRef, ChannelId)
+ try collect_data(ConnectionRef, ChannelId, EchoSize)
of
ExpectedData ->
+ ct:log("~p:~p got expected data",[?MODULE,?LINE]),
ok;
- _ ->
- {fail,"unexpected result"}
+ Other ->
+ ct:log("~p:~p unexpect: ~p", [?MODULE,?LINE,Other]),
+ {fail,"unexpected result in listener"}
catch
Class:Exception ->
- {fail, io_lib:format("Exception ~p:~p",[Class,Exception])}
+ {fail, io_lib:format("Listener exception ~p:~p",[Class,Exception])}
end,
- Parent ! {self(), Result};
+ Parent ! {self(), result, Result};
Other ->
Parent ! {self(), channelId, error, Other}
end
end),
receive
+ {ResultPid, channelId, error, Other} ->
+ ct:log("~p:~p channelId error ~p", [?MODULE,?LINE,Other]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ {fail, "ssh_connection:subsystem"};
+
{ResultPid, channelId, ChannelId} ->
- %% pre-adjust receive window so the other end doesn't block
- ct:log("adjust window", []),
- ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
-
- ct:log("going to send ~p bytes", [size(Data)]),
- case ssh_connection:send(ConnectionRef, ChannelId, Data, 30000) of
- {error, closed} ->
- ct:log("{error,closed} - That's what we expect :)", []),
- ok;
- Msg ->
- ct:log("Got ~p - that's bad, very bad indeed",[Msg]),
- ct:fail({expected,{error,closed}, got, Msg})
- end,
- ct:log("going to check the result (if it is available)", []),
+ ct:log("~p:~p ~p going to send ~p bytes", [?MODULE,?LINE,self(),size(Data)]),
+ SenderPid = spawn(fun() ->
+ Parent ! {self(), ssh_connection:send(ConnectionRef, ChannelId, Data, 30000)}
+ end),
receive
- {ResultPid, Result} ->
- ct:log("Got result: ~p", [Result]),
+ {ResultPid, result, {fail, Fail}} ->
+ ct:log("~p:~p Listener failed: ~p", [?MODULE,?LINE,Fail]),
+ {fail, Fail};
+
+ {ResultPid, result, Result} ->
+ ct:log("~p:~p Got result: ~p", [?MODULE,?LINE,Result]),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid),
- Result
- end;
+ ct:log("~p:~p Check sender", [?MODULE,?LINE]),
+ receive
+ {SenderPid, {error, closed}} ->
+ ct:log("~p:~p {error,closed} - That's what we expect :)",[?MODULE,?LINE]),
+ ok;
+ Msg ->
+ ct:log("~p:~p Not expected send result: ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Not expected msg"}
+ end;
+
+ {SenderPid, {error, closed}} ->
+ ct:log("~p:~p {error,closed} - That's what we expect, but client channel handler has not reported yet",[?MODULE,?LINE]),
+ receive
+ {ResultPid, result, Result} ->
+ ct:log("~p:~p Now got the result: ~p", [?MODULE,?LINE,Result]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ ok;
+ Msg ->
+ ct:log("~p:~p Got an unexpected msg ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Un-expected msg"}
+ end;
- {ResultPid, channelId, error, Other} ->
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid),
- {fail, io_lib:format("ssh_connection:subsystem: ~p",[Other])}
+ Msg ->
+ ct:log("~p:~p Got unexpected ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Unexpected msg"}
+ end
end.
%%--------------------------------------------------------------------
@@ -520,6 +544,79 @@ start_shell_exec(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+exec_erlang_term(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"}
+ ]),
+
+ ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, true},
+ {user_dir, UserDir}]),
+
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "1+2.", infinity),
+ TestResult =
+ receive
+ {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"3",_/binary>>}} = R ->
+ ct:log("Got expected ~p",[R]);
+ Other ->
+ ct:log("Got unexpected ~p",[Other])
+ after 5000 ->
+ {fail,"Exec Timeout"}
+ end,
+
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ TestResult.
+
+%%--------------------------------------------------------------------
+exec_erlang_term_non_default_shell(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {shell, fun(U, H) -> start_our_shell(U, H) end}
+ ]),
+
+ ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, true},
+ {user_dir, UserDir}
+ ]),
+
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "1+2.", infinity),
+ TestResult =
+ receive
+ {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"3",_/binary>>}} = R ->
+ ct:log("Got unexpected ~p",[R]),
+ {fail,"Could exec erlang term although non-erlang shell"};
+ Other ->
+ ct:log("Got expected ~p",[Other])
+ after 5000 ->
+ {fail, "Exec Timeout"}
+ end,
+
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ TestResult.
+
+%%--------------------------------------------------------------------
start_shell_exec_fun() ->
[{doc, "start shell to exec command"}].
@@ -909,36 +1006,46 @@ big_cat_rx(ConnectionRef, ChannelId, Acc) ->
timeout
end.
-collect_data(ConnectionRef, ChannelId) ->
- ct:log("Listener ~p running! ConnectionRef=~p, ChannelId=~p",[self(),ConnectionRef,ChannelId]),
- collect_data(ConnectionRef, ChannelId, [], 0).
+collect_data(ConnectionRef, ChannelId, EchoSize) ->
+ ct:log("~p:~p Listener ~p running! ConnectionRef=~p, ChannelId=~p",[?MODULE,?LINE,self(),ConnectionRef,ChannelId]),
+ collect_data(ConnectionRef, ChannelId, EchoSize, [], 0).
-collect_data(ConnectionRef, ChannelId, Acc, Sum) ->
+collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum) ->
TO = 5000,
receive
{ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} when is_binary(Data) ->
- ct:log("collect_data: received ~p bytes. total ~p bytes",[size(Data),Sum+size(Data)]),
- collect_data(ConnectionRef, ChannelId, [Data | Acc], Sum+size(Data));
- {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
- try
- iolist_to_binary(lists:reverse(Acc))
- of
- Bin ->
- ct:log("collect_data: received eof.~nGot in total ~p bytes",[size(Bin)]),
- Bin
- catch
- C:E ->
- ct:log("collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p",
- [C,E,Acc]),
- {error,{C,E}}
- end;
+ ct:log("~p:~p collect_data: received ~p bytes. total ~p bytes, want ~p more",
+ [?MODULE,?LINE,size(Data),Sum+size(Data),EchoSize-Sum]),
+ ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
+ collect_data(ConnectionRef, ChannelId, EchoSize, [Data | Acc], Sum+size(Data));
+ {ssh_cm, ConnectionRef, Msg={eof, ChannelId}} ->
+ collect_data_report_end(Acc, Msg, EchoSize);
+
+ {ssh_cm, ConnectionRef, Msg={closed,ChannelId}} ->
+ collect_data_report_end(Acc, Msg, EchoSize);
+
Msg ->
- ct:log("collect_data: ***** unexpected message *****~n~p",[Msg]),
- collect_data(ConnectionRef, ChannelId, Acc, Sum)
+ ct:log("~p:~p collect_data: ***** unexpected message *****~n~p",[?MODULE,?LINE,Msg]),
+ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
after TO ->
- ct:log("collect_data: ----- Nothing received for ~p seconds -----~n",[]),
- collect_data(ConnectionRef, ChannelId, Acc, Sum)
+ ct:log("~p:~p collect_data: ----- Nothing received for ~p seconds -----~n",[?MODULE,?LINE,TO]),
+ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
+ end.
+
+collect_data_report_end(Acc, Msg, EchoSize) ->
+ try
+ iolist_to_binary(lists:reverse(Acc))
+ of
+ Bin ->
+ ct:log("~p:~p collect_data: received ~p.~nGot in total ~p bytes, want ~p more",
+ [?MODULE,?LINE,Msg,size(Bin),EchoSize,size(Bin)]),
+ Bin
+ catch
+ C:E ->
+ ct:log("~p:~p collect_data: received ~p.~nAcc is strange...~nException=~p:~p~nAcc=~p",
+ [?MODULE,?LINE,Msg,C,E,Acc]),
+ {error,{C,E}}
end.
%%%-------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_eqc_event_handler.erl b/lib/ssh/test/ssh_eqc_event_handler.erl
new file mode 100644
index 0000000000..233965012a
--- /dev/null
+++ b/lib/ssh/test/ssh_eqc_event_handler.erl
@@ -0,0 +1,43 @@
+-module(ssh_eqc_event_handler).
+
+-compile(export_all).
+
+-behaviour(gen_event).
+
+add_report_handler() ->
+ error_logger:add_report_handler(?MODULE, [self(),Ref=make_ref()]),
+ receive
+ {event_handler_started,HandlerPid,Ref} ->
+ {ok,HandlerPid}
+ end.
+
+get_reports(Pid) ->
+ Pid ! {get_reports,self(),Ref=make_ref()},
+ receive
+ {reports,Reports,Ref} ->
+ {ok,Reports}
+ end.
+
+%%%================================================================
+
+-record(state, {
+ reports = []
+ }).
+
+%% error_logger:add_report_handler(ssh_eqc_event_handler, [self()]).
+
+init([CallerPid,Ref]) ->
+ CallerPid ! {event_handler_started,self(),Ref},
+ {ok, #state{}}.
+
+handle_event(Event, State) ->
+ {ok, State#state{reports = [Event|State#state.reports]}}.
+
+handle_info({get_reports,From,Ref}, State) ->
+ From ! {reports, lists:reverse(State#state.reports), Ref},
+ {ok, State#state{reports=[]}}.
+
+handle_call(_Request, State) -> {ok,reply,State}.
+terminate(_Arg, _State) -> stop.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 61883c0647..aefd31834a 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,9 @@
id_string_no_opt_client/1,
id_string_no_opt_server/1,
id_string_own_string_client/1,
+ id_string_own_string_client_trail_space/1,
id_string_own_string_server/1,
+ id_string_own_string_server_trail_space/1,
id_string_random_client/1,
id_string_random_server/1,
max_sessions_sftp_start_channel_parallel/1,
@@ -61,7 +63,14 @@
unexpectedfun_option_client/1,
unexpectedfun_option_server/1,
user_dir_option/1,
- connectfun_disconnectfun_server/1
+ connectfun_disconnectfun_server/1,
+ hostkey_fingerprint_check/1,
+ hostkey_fingerprint_check_md5/1,
+ hostkey_fingerprint_check_sha/1,
+ hostkey_fingerprint_check_sha256/1,
+ hostkey_fingerprint_check_sha384/1,
+ hostkey_fingerprint_check_sha512/1,
+ hostkey_fingerprint_check_list/1
]).
%%% Common test callbacks
@@ -100,11 +109,20 @@ all() ->
disconnectfun_option_client,
unexpectedfun_option_server,
unexpectedfun_option_client,
+ hostkey_fingerprint_check,
+ hostkey_fingerprint_check_md5,
+ hostkey_fingerprint_check_sha,
+ hostkey_fingerprint_check_sha256,
+ hostkey_fingerprint_check_sha384,
+ hostkey_fingerprint_check_sha512,
+ hostkey_fingerprint_check_list,
id_string_no_opt_client,
id_string_own_string_client,
+ id_string_own_string_client_trail_space,
id_string_random_client,
id_string_no_opt_server,
id_string_own_string_server,
+ id_string_own_string_server_trail_space,
id_string_random_server,
{group, hardening_tests}
].
@@ -540,10 +558,18 @@ connectfun_disconnectfun_server(Config) ->
{disconnect,Ref,R} ->
ct:log("Disconnect result: ~p",[R]),
ssh:stop_daemon(Pid)
- after 2000 ->
+ after 5000 ->
+ receive
+ X -> ct:log("received ~p",[X])
+ after 0 -> ok
+ end,
{fail, "No disconnectfun action"}
end
- after 2000 ->
+ after 5000 ->
+ receive
+ X -> ct:log("received ~p",[X])
+ after 0 -> ok
+ end,
{fail, "No connectfun action"}
end.
@@ -649,7 +675,7 @@ disconnectfun_option_server(Config) ->
ct:log("Server detected disconnect: ~p",[Reason]),
ssh:stop_daemon(Pid),
ok
- after 3000 ->
+ after 5000 ->
receive
X -> ct:log("received ~p",[X])
after 0 -> ok
@@ -774,6 +800,106 @@ unexpectedfun_option_client(Config) ->
end.
%%--------------------------------------------------------------------
+hostkey_fingerprint_check(Config) ->
+ do_hostkey_fingerprint_check(Config, old).
+
+hostkey_fingerprint_check_md5(Config) ->
+ do_hostkey_fingerprint_check(Config, md5).
+
+hostkey_fingerprint_check_sha(Config) ->
+ do_hostkey_fingerprint_check(Config, sha).
+
+hostkey_fingerprint_check_sha256(Config) ->
+ do_hostkey_fingerprint_check(Config, sha256).
+
+hostkey_fingerprint_check_sha384(Config) ->
+ do_hostkey_fingerprint_check(Config, sha384).
+
+hostkey_fingerprint_check_sha512(Config) ->
+ do_hostkey_fingerprint_check(Config, sha512).
+
+hostkey_fingerprint_check_list(Config) ->
+ do_hostkey_fingerprint_check(Config, [sha,md5,sha256]).
+
+%%%----
+do_hostkey_fingerprint_check(Config, HashAlg) ->
+ case supported_hash(HashAlg) of
+ true ->
+ really_do_hostkey_fingerprint_check(Config, HashAlg);
+ false ->
+ {skip,{unsupported_hash,HashAlg}}
+ end.
+
+supported_hash(old) -> true;
+supported_hash(HashAlg) ->
+ Hs = if is_atom(HashAlg) -> [HashAlg];
+ is_list(HashAlg) -> HashAlg
+ end,
+ [] == (Hs -- proplists:get_value(hashs, crypto:supports(), [])).
+
+
+really_do_hostkey_fingerprint_check(Config, HashAlg) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDirServer = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDirServer),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ UserDirClient =
+ ssh_test_lib:create_random_dir(Config), % Ensure no 'known_hosts' disturbs
+
+ %% All host key fingerprints. Trust that public_key has checked the ssh_hostkey_fingerprint
+ %% function since that function is used by the ssh client...
+ FPs0 = [case HashAlg of
+ old -> public_key:ssh_hostkey_fingerprint(Key);
+ _ -> public_key:ssh_hostkey_fingerprint(HashAlg, Key)
+ end
+ || FileCandidate <- begin
+ {ok,KeyFileCands} = file:list_dir(SysDir),
+ KeyFileCands
+ end,
+ nomatch =/= re:run(FileCandidate, ".*\\.pub", []),
+ {Key,_Cmnts} <- begin
+ {ok,Bin} = file:read_file(filename:join(SysDir, FileCandidate)),
+ try public_key:ssh_decode(Bin, public_key)
+ catch
+ _:_ -> []
+ end
+ end],
+ FPs = if is_atom(HashAlg) -> FPs0;
+ is_list(HashAlg) -> lists:concat(FPs0)
+ end,
+ ct:log("Fingerprints(~p) = ~p",[HashAlg,FPs]),
+
+ %% Start daemon with the public keys that we got fingerprints from
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDirServer},
+ {password, "morot"}]),
+
+ FP_check_fun = fun(PeerName, FP) ->
+ ct:pal("PeerName = ~p, FP = ~p",[PeerName,FP]),
+ HostCheck = (Host == PeerName),
+ FPCheck =
+ if is_atom(HashAlg) -> lists:member(FP, FPs);
+ is_list(HashAlg) -> lists:all(fun(FP1) -> lists:member(FP1,FPs) end,
+ FP)
+ end,
+ ct:log("check ~p == ~p (~p) and ~n~p~n in ~p (~p)~n",
+ [PeerName,Host,HostCheck,FP,FPs,FPCheck]),
+ HostCheck and FPCheck
+ end,
+
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts,
+ case HashAlg of
+ old -> FP_check_fun;
+ _ -> {HashAlg, FP_check_fun}
+ end},
+ {user, "foo"},
+ {password, "morot"},
+ {user_dir, UserDirClient},
+ {user_interaction, false}]),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
%%% Test connect_timeout option in ssh:connect/4
ssh_connect_timeout(_Config) ->
ConnTimeout = 2000,
@@ -912,6 +1038,19 @@ id_string_own_string_client(Config) ->
end.
%%--------------------------------------------------------------------
+id_string_own_string_client_trail_space(Config) ->
+ {Server, _Host, Port} = fake_daemon(Config),
+ {error,_} = ssh:connect("localhost", Port, [{id_string,"Pelle "}], 1000),
+ receive
+ {id,Server,"SSH-2.0-Pelle \r\n"} ->
+ ok;
+ {id,Server,Other} ->
+ ct:fail("Unexpected id: ~s.",[Other])
+ after 5000 ->
+ {fail,timeout}
+ end.
+
+%%--------------------------------------------------------------------
id_string_random_client(Config) ->
{Server, _Host, Port} = fake_daemon(Config),
{error,_} = ssh:connect("localhost", Port, [{id_string,random}], 1000),
@@ -940,6 +1079,12 @@ id_string_own_string_server(Config) ->
{ok,"SSH-2.0-Olle\r\n"} = gen_tcp:recv(S1, 0, 2000).
%%--------------------------------------------------------------------
+id_string_own_string_server_trail_space(Config) ->
+ {_Server, Host, Port} = ssh_test_lib:std_daemon(Config, [{id_string,"Olle "}]),
+ {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]),
+ {ok,"SSH-2.0-Olle \r\n"} = gen_tcp:recv(S1, 0, 2000).
+
+%%--------------------------------------------------------------------
id_string_random_server(Config) ->
{_Server, Host, Port} = ssh_test_lib:std_daemon(Config, [{id_string,random}]),
{ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]),
@@ -974,7 +1119,14 @@ ssh_connect_negtimeout(Config, Parallel) ->
ct:sleep(round(Factor * NegTimeOut)),
case inet:sockname(Socket) of
- {ok,_} -> ct:fail("Socket not closed");
+ {ok,_} ->
+ %% Give it another chance...
+ ct:log("Sleep more...",[]),
+ ct:sleep(round(Factor * NegTimeOut)),
+ case inet:sockname(Socket) of
+ {ok,_} -> ct:fail("Socket not closed");
+ {error,_} -> ok
+ end;
{error,_} -> ok
end.
@@ -1003,7 +1155,7 @@ ssh_connect_nonegtimeout_connected(Config, Parallel) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir}]),
receive
Error = {'EXIT', _, _} ->
ct:log("~p",[Error]),
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index c8aabcedb7..9b2a84d8e4 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -38,6 +38,7 @@
-include_lib("common_test/include/ct.hrl").
all() -> [{group, messages},
+ client_sends_info_timing,
{group, client_server}
].
@@ -67,9 +68,6 @@ init_per_group(_, Config) ->
end_per_group(_, Config) ->
Config.
-%%% Always skip the testcase that is not quite in phase with the
-%%% ssh_message.erl code
-init_per_testcase(decode_encode, _) -> {skip, "Fails - testcase is not ok"};
init_per_testcase(_TestCase, Config) -> Config.
end_per_testcase(_TestCase, Config) -> Config.
@@ -106,3 +104,9 @@ client_server_parallel_multi(Config) ->
ssh_eqc_client_server:prop_parallel_multi(Config),
Config
).
+
+client_sends_info_timing(Config) ->
+ ct_property_test:quickcheck(
+ ssh_eqc_client_info_timing:prop_seq(Config),
+ Config
+ ).
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 4fac1f718a..619ff5e27a 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% The 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,6 +48,7 @@ suite() ->
all() ->
[{group,tool_tests},
+ client_info_line,
{group,kex},
{group,service_requests},
{group,authentication},
@@ -106,7 +107,10 @@ init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
TC == gex_client_old_request_noexact ->
Opts = case TC of
gex_client_init_option_groups ->
- [{dh_gex_groups, [{2345, 3, 41}]}];
+ [{dh_gex_groups,
+ [{1023, 5,
+ 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A770E2EC9F
+ }]}];
gex_client_init_option_groups_file ->
DataDir = proplists:get_value(data_dir, Config),
F = filename:join(DataDir, "dh_group_test"),
@@ -118,10 +122,12 @@ init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
_ when TC == gex_server_gex_limit ;
TC == gex_client_old_request_exact ;
TC == gex_client_old_request_noexact ->
- [{dh_gex_groups, [{ 500, 3, 17},
- {1000, 7, 91},
- {3000, 5, 61}]},
- {dh_gex_limits,{500,1500}}
+ [{dh_gex_groups,
+ [{1023, 2, 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A771225323},
+ {1535, 5, 16#D1391174233D315398FE2830AC6B2B66BCCD01B0A634899F339B7879F1DB85712E9DC4E4B1C6C8355570C1D2DCB53493DF18175A9C53D1128B592B4C72D97136F5542FEB981CBFE8012FDD30361F288A42BD5EBB08BAB0A5640E1AC48763B2ABD1945FEE36B2D55E1D50A1C86CED9DD141C4E7BE2D32D9B562A0F8E2E927020E91F58B57EB9ACDDA106A59302D7E92AD5F6E851A45FA1CFE86029A0F727F65A8F475F33572E2FDAB6073F0C21B8B54C3823DB2EF068927E5D747498F96E1E827},
+ {3071, 2, 16#DFAA35D35531E0F524F0099877A482D2AC8D589F374394A262A8E81A8A4FB2F65FADBAB395E05D147B29D486DFAA41F41597A256DA82A8B6F76401AED53D0253F956CEC610D417E42E3B287F7938FC24D8821B40BFA218A956EB7401BED6C96C68C7FD64F8170A8A76B953DD2F05420118F6B144D8FE48060A2BCB85056B478EDEF96DBC70427053ECD2958C074169E9550DD877779A3CF17C5AC850598C7586BEEA9DCFE9DD2A5FB62DF5F33EA7BC00CDA31B9D2DD721F979EA85B6E63F0C4E30BDDCD3A335522F9004C4ED50B15DC537F55324DD4FA119FB3F101467C6D7E1699DE4B3E3C478A8679B8EB3FA5C9B826B44530FD3BE9AD3063B240B0C853EBDDBD68DD940332D98F148D5D9E1DC977D60A0D23D0CA1198637FEAE4E7FAAC173AF2B84313A666CFB4EE6972811921D0AD867CE57F3BBC8D6CB057E3B66757BB46C9F72662624D44E14528327E3A7100E81A12C43C4E236118318CD90C8AA185BBB0C764826DAEAEE8DD245C5B451B4944E6122CC522D1C335C2EEF9429825A2B}
+ ]},
+ {dh_gex_limits, {1023,2000}}
];
_ ->
[]
@@ -350,20 +356,25 @@ no_common_alg_client_disconnects(Config) ->
%%%--------------------------------------------------------------------
gex_client_init_option_groups(Config) ->
- do_gex_client_init(Config, {2000, 2048, 4000},
- {3,41}).
+ do_gex_client_init(Config, {512, 2048, 4000},
+ {5,16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A770E2EC9F}
+ ).
gex_client_init_option_groups_file(Config) ->
do_gex_client_init(Config, {2000, 2048, 4000},
- {5,61}).
+ {5, 16#DFAA35D35531E0F524F0099877A482D2AC8D589F374394A262A8E81A8A4FB2F65FADBAB395E05D147B29D486DFAA41F41597A256DA82A8B6F76401AED53D0253F956CEC610D417E42E3B287F7938FC24D8821B40BFA218A956EB7401BED6C96C68C7FD64F8170A8A76B953DD2F05420118F6B144D8FE48060A2BCB85056B478EDEF96DBC70427053ECD2958C074169E9550DD877779A3CF17C5AC850598C7586BEEA9DCFE9DD2A5FB62DF5F33EA7BC00CDA31B9D2DD721F979EA85B6E63F0C4E30BDDCD3A335522F9004C4ED50B15DC537F55324DD4FA119FB3F101467C6D7E1699DE4B3E3C478A8679B8EB3FA5C9B826B44530FD3BE9AD3063B240B0C853EBDDBD68DD940332D98F148D5D9E1DC977D60A0D23D0CA1198637FEAE4E7FAAC173AF2B84313A666CFB4EE6972811921D0AD867CE57F3BBC8D6CB057E3B66757BB46C9F72662624D44E14528327E3A7100E81A12C43C4E236118318CD90C8AA185BBB0C764826DAEAEE8DD245C5B451B4944E6122CC522D1C335C2EEF9424273F1F}
+ ).
gex_client_init_option_groups_moduli_file(Config) ->
do_gex_client_init(Config, {2000, 2048, 4000},
- {5,16#B7}).
+ {5, 16#DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C604293683A9635F}
+ ).
gex_server_gex_limit(Config) ->
do_gex_client_init(Config, {1000, 3000, 4000},
- {7,91}).
+ %% {7,91}).
+ {5, 16#D1391174233D315398FE2830AC6B2B66BCCD01B0A634899F339B7879F1DB85712E9DC4E4B1C6C8355570C1D2DCB53493DF18175A9C53D1128B592B4C72D97136F5542FEB981CBFE8012FDD30361F288A42BD5EBB08BAB0A5640E1AC48763B2ABD1945FEE36B2D55E1D50A1C86CED9DD141C4E7BE2D32D9B562A0F8E2E927020E91F58B57EB9ACDDA106A59302D7E92AD5F6E851A45FA1CFE86029A0F727F65A8F475F33572E2FDAB6073F0C21B8B54C3823DB2EF068927E5D747498F96E1E827}
+ ).
do_gex_client_init(Config, {Min,N,Max}, {G,P}) ->
@@ -389,8 +400,15 @@ do_gex_client_init(Config, {Min,N,Max}, {G,P}) ->
).
%%%--------------------------------------------------------------------
-gex_client_old_request_exact(Config) -> do_gex_client_init_old(Config, 500, {3,17}).
-gex_client_old_request_noexact(Config) -> do_gex_client_init_old(Config, 800, {7,91}).
+gex_client_old_request_exact(Config) ->
+ do_gex_client_init_old(Config, 1023,
+ {2, 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A771225323}
+ ).
+
+gex_client_old_request_noexact(Config) ->
+ do_gex_client_init_old(Config, 1400,
+ {5, 16#D1391174233D315398FE2830AC6B2B66BCCD01B0A634899F339B7879F1DB85712E9DC4E4B1C6C8355570C1D2DCB53493DF18175A9C53D1128B592B4C72D97136F5542FEB981CBFE8012FDD30361F288A42BD5EBB08BAB0A5640E1AC48763B2ABD1945FEE36B2D55E1D50A1C86CED9DD141C4E7BE2D32D9B562A0F8E2E927020E91F58B57EB9ACDDA106A59302D7E92AD5F6E851A45FA1CFE86029A0F727F65A8F475F33572E2FDAB6073F0C21B8B54C3823DB2EF068927E5D747498F96E1E827}
+ ).
do_gex_client_init_old(Config, N, {G,P}) ->
{ok,_} =
@@ -575,6 +593,36 @@ client_handles_keyboard_interactive_0_pwds(Config) ->
).
+
+%%%--------------------------------------------------------------------
+client_info_line(_Config) ->
+ %% A client must not send an info-line. If it does, the server should handle
+ %% handle this gracefully
+ {ok,Pid} = ssh_eqc_event_handler:add_report_handler(),
+ {_, _, Port} = ssh_test_lib:daemon([]),
+
+ %% Fake client:
+ {ok,S} = gen_tcp:connect("localhost",Port,[]),
+ gen_tcp:send(S,"An illegal info-string\r\n"),
+ gen_tcp:close(S),
+
+ %% wait for server to react:
+ timer:sleep(1000),
+
+ %% check if a badmatch was received:
+ {ok, Reports} = ssh_eqc_event_handler:get_reports(Pid),
+ case lists:any(fun({error_report,_,{_,supervisor_report,L}}) when is_list(L) ->
+ lists:member({reason,{badmatch,{error,closed}}}, L);
+ (_) ->
+ false
+ end, Reports) of
+ true ->
+ ct:fail("Bad error report on info_line from client");
+ false ->
+ ok
+ end.
+
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test
index 2887bb4b60..87c4b4afc8 100644
--- a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test
@@ -1,3 +1,3 @@
-{2222, 5, 61}.
-{1111, 7, 91}.
+{1023, 5, 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A770E2EC9F}.
+{3071, 5, 16#DFAA35D35531E0F524F0099877A482D2AC8D589F374394A262A8E81A8A4FB2F65FADBAB395E05D147B29D486DFAA41F41597A256DA82A8B6F76401AED53D0253F956CEC610D417E42E3B287F7938FC24D8821B40BFA218A956EB7401BED6C96C68C7FD64F8170A8A76B953DD2F05420118F6B144D8FE48060A2BCB85056B478EDEF96DBC70427053ECD2958C074169E9550DD877779A3CF17C5AC850598C7586BEEA9DCFE9DD2A5FB62DF5F33EA7BC00CDA31B9D2DD721F979EA85B6E63F0C4E30BDDCD3A335522F9004C4ED50B15DC537F55324DD4FA119FB3F101467C6D7E1699DE4B3E3C478A8679B8EB3FA5C9B826B44530FD3BE9AD3063B240B0C853EBDDBD68DD940332D98F148D5D9E1DC977D60A0D23D0CA1198637FEAE4E7FAAC173AF2B84313A666CFB4EE6972811921D0AD867CE57F3BBC8D6CB057E3B66757BB46C9F72662624D44E14528327E3A7100E81A12C43C4E236118318CD90C8AA185BBB0C764826DAEAEE8DD245C5B451B4944E6122CC522D1C335C2EEF9424273F1F}.
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli
index f6995ba4c9..6d2b4bcb59 100644
--- a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli
@@ -1,3 +1,2 @@
-20151021104105 2 6 100 2222 5 B7
-20151021104106 2 6 100 1111 5 4F
-
+20120821044046 2 6 100 1023 2 D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A7711F2C6B
+20120821050554 2 6 100 2047 5 DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C604293683A9635F
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl
index b10ec3707f..74bbc291b2 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE.erl
+++ b/lib/ssh/test/ssh_renegotiate_SUITE.erl
@@ -92,11 +92,11 @@ rekey(Config) ->
ConnectionRef =
ssh_test_lib:std_connect(Config, Host, Port,
[{rekey_limit, 0}]),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
receive
after ?REKEY_DATA_TMO ->
%%By this time rekeying would have been done
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid)
@@ -120,31 +120,31 @@ rekey_limit(Config) ->
{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
timer:sleep(?REKEY_DATA_TMO),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
Data = lists:duplicate(159000,1),
ok = ssh_sftp:write_file(SftpPid, DataFile, Data),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
ssh_sftp:stop_channel(SftpPid),
ssh:close(ConnectionRef),
@@ -169,7 +169,7 @@ renegotiate1(Config) ->
ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
{ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
@@ -181,7 +181,7 @@ renegotiate1(Config) ->
timer:sleep(2000),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
@@ -208,7 +208,7 @@ renegotiate2(Config) ->
ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
{ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
@@ -223,7 +223,7 @@ renegotiate2(Config) ->
timer:sleep(2000),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
@@ -235,19 +235,3 @@ renegotiate2(Config) ->
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-%% get_kex_init - helper function to get key_exchange_init_msg
-get_kex_init(Conn) ->
- %% First, validate the key exchange is complete (StateName == connected)
- {{connected,_},S} = sys:get_state(Conn),
- %% Next, walk through the elements of the #state record looking
- %% for the #ssh_msg_kexinit record. This method is robust against
- %% changes to either record. The KEXINIT message contains a cookie
- %% unique to each invocation of the key exchange procedure (RFC4253)
- SL = tuple_to_list(S),
- case lists:keyfind(ssh_msg_kexinit, 1, SL) of
- false ->
- throw(not_found);
- KexInit ->
- KexInit
- end.
-
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index 19ad81e7da..acf76157a2 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -60,12 +60,16 @@ end_per_suite(_onfig) ->
groups() ->
[{not_unicode, [], [{group,erlang_server},
{group,openssh_server},
+ {group,big_recvpkt_size},
sftp_nonexistent_subsystem]},
{unicode, [], [{group,erlang_server},
{group,openssh_server},
sftp_nonexistent_subsystem]},
+ {big_recvpkt_size, [], [{group,erlang_server},
+ {group,openssh_server}]},
+
{erlang_server, [], [{group,write_read_tests},
version_option,
{group,remote_tar}]},
@@ -149,6 +153,9 @@ init_per_group(unicode, Config) ->
{skip, "Not unicode file encoding"}
end;
+init_per_group(big_recvpkt_size, Config) ->
+ [{pkt_sz,123456} | Config];
+
init_per_group(erlang_server, Config) ->
ct:comment("Begin ~p",[grps(Config)]),
PrivDir = proplists:get_value(priv_dir, Config),
@@ -257,7 +264,10 @@ init_per_testcase(Case, Config00) ->
Dog = ct:timetrap(2 * ?default_timeout),
User = proplists:get_value(user, Config0),
Passwd = proplists:get_value(passwd, Config0),
-
+ PktSzOpt = case proplists:get_value(pkt_sz, Config0) of
+ undefined -> [];
+ Sz -> [{packet_size,Sz}]
+ end,
Config =
case proplists:get_value(group,Config2) of
erlang_server ->
@@ -267,7 +277,9 @@ init_per_testcase(Case, Config00) ->
[{user, User},
{password, Passwd},
{user_interaction, false},
- {silently_accept_hosts, true}]
+ {silently_accept_hosts, true}
+ | PktSzOpt
+ ]
),
Sftp = {ChannelPid, Connection},
[{sftp, Sftp}, {watchdog, Dog} | Config2];
@@ -278,7 +290,9 @@ init_per_testcase(Case, Config00) ->
{ok, ChannelPid, Connection} =
ssh_sftp:start_channel(Host,
[{user_interaction, false},
- {silently_accept_hosts, true}]),
+ {silently_accept_hosts, true}
+ | PktSzOpt
+ ]),
Sftp = {ChannelPid, Connection},
[{sftp, Sftp}, {watchdog, Dog} | Config2]
end,
@@ -1024,7 +1038,7 @@ oldprep(Config) ->
prepare(Config0) ->
PrivDir = proplists:get_value(priv_dir, Config0),
- Dir = filename:join(PrivDir, random_chars(10)),
+ Dir = filename:join(PrivDir, ssh_test_lib:random_chars(10)),
file:make_dir(Dir),
Keys = [filename,
testfile,
@@ -1044,8 +1058,6 @@ prepare(Config0) ->
[{sftp_priv_dir,Dir} | Config2].
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
-
foldl_keydelete(Keys, L) ->
lists:foldl(fun(K,E) -> lists:keydelete(K,1,E) end,
L,
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 52a26110c4..2c6eaeee0d 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -65,7 +65,12 @@ all() ->
ver3_open_flags,
relpath,
sshd_read_file,
- ver6_basic].
+ ver6_basic,
+ access_outside_root,
+ root_with_cwd,
+ relative_path,
+ open_file_dir_v5,
+ open_file_dir_v6].
groups() ->
[].
@@ -117,6 +122,31 @@ init_per_testcase(TestCase, Config) ->
ver6_basic ->
SubSystems = [ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}])],
ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ access_outside_root ->
+ %% Build RootDir/access_outside_root/a/b and set Root and CWD
+ BaseDir = filename:join(PrivDir, access_outside_root),
+ RootDir = filename:join(BaseDir, a),
+ CWD = filename:join(RootDir, b),
+ %% Make the directory chain:
+ ok = filelib:ensure_dir(filename:join(CWD, tmp)),
+ SubSystems = [ssh_sftpd:subsystem_spec([{root, RootDir},
+ {cwd, CWD}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ root_with_cwd ->
+ RootDir = filename:join(PrivDir, root_with_cwd),
+ CWD = filename:join(RootDir, home),
+ SubSystems = [ssh_sftpd:subsystem_spec([{root, RootDir}, {cwd, CWD}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ relative_path ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ open_file_dir_v5 ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ open_file_dir_v6 ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir},
+ {sftpd_vsn, 6}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
_ ->
SubSystems = [ssh_sftpd:subsystem_spec([])],
ssh:daemon(0, [{subsystems, SubSystems}|Options])
@@ -646,6 +676,133 @@ ver6_basic(Config) when is_list(Config) ->
open_file(PrivDir, Cm, Channel, ReqId,
?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+access_outside_root() ->
+ [{doc, "Try access files outside the tree below RootDir"}].
+access_outside_root(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ BaseDir = filename:join(PrivDir, access_outside_root),
+ %% A file outside the tree below RootDir which is BaseDir/a
+ %% Make the file BaseDir/bad :
+ BadFilePath = filename:join([BaseDir, bad]),
+ ok = file:write_file(BadFilePath, <<>>),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ %% Try to access a file parallell to the RootDir:
+ try_access("/../bad", Cm, Channel, 0),
+ %% Try to access the same file via the CWD which is /b relative to the RootDir:
+ try_access("../../bad", Cm, Channel, 1).
+
+
+try_access(Path, Cm, Channel, ReqId) ->
+ Return =
+ open_file(Path, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING),
+ ct:log("Try open ~p -> ~p",[Path,Return]),
+ case Return of
+ {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), _Handle0/binary>>, _} ->
+ ct:fail("Could open a file outside the root tree!");
+ {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), ?UINT32(Code), Rest/binary>>, <<>>} ->
+ case Code of
+ ?SSH_FX_FILE_IS_A_DIRECTORY ->
+ ct:pal("Got the expected SSH_FX_FILE_IS_A_DIRECTORY status",[]),
+ ok;
+ ?SSH_FX_FAILURE ->
+ ct:pal("Got the expected SSH_FX_FAILURE status",[]),
+ ok;
+ _ ->
+ case Rest of
+ <<?UINT32(Len), Txt:Len/binary, _/binary>> ->
+ ct:fail("Got unexpected SSH_FX_code: ~p (~p)",[Code,Txt]);
+ _ ->
+ ct:fail("Got unexpected SSH_FX_code: ~p",[Code])
+ end
+ end;
+ _ ->
+ ct:fail("Completly unexpected return: ~p", [Return])
+ end.
+
+%%--------------------------------------------------------------------
+root_with_cwd() ->
+ [{doc, "Check if files are found, if the CWD and Root are specified"}].
+root_with_cwd(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ RootDir = filename:join(PrivDir, root_with_cwd),
+ CWD = filename:join(RootDir, home),
+ FileName = "root_with_cwd.txt",
+ FilePath = filename:join(CWD, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:write_file(FilePath ++ "0", <<>>),
+ ok = file:write_file(FilePath ++ "1", <<>>),
+ ok = file:write_file(FilePath ++ "2", <<>>),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId0 = 0,
+ {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId0), _Handle0/binary>>, _} =
+ open_file(FileName ++ "0", Cm, Channel, ReqId0,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING),
+ ReqId1 = 1,
+ {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId1), _Handle1/binary>>, _} =
+ open_file("./" ++ FileName ++ "1", Cm, Channel, ReqId1,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING),
+ ReqId2 = 2,
+ {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId2), _Handle2/binary>>, _} =
+ open_file("/home/" ++ FileName ++ "2", Cm, Channel, ReqId2,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+relative_path() ->
+ [{doc, "Test paths relative to CWD when opening a file handle."}].
+relative_path(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileName = "test_relative_path.txt",
+ FilePath = filename:join(PrivDir, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:write_file(FilePath, <<>>),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId = 0,
+ {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), _Handle/binary>>, _} =
+ open_file(FileName, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+open_file_dir_v5() ->
+ [{doc, "Test if open_file fails when opening existing directory."}].
+open_file_dir_v5(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileName = "open_file_dir_v5",
+ FilePath = filename:join(PrivDir, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:make_dir(FilePath),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId = 0,
+ {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId),
+ ?UINT32(?SSH_FX_FAILURE), _/binary>>, _} =
+ open_file(FileName, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+open_file_dir_v6() ->
+ [{doc, "Test if open_file fails when opening existing directory."}].
+open_file_dir_v6(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileName = "open_file_dir_v6",
+ FilePath = filename:join(PrivDir, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:make_dir(FilePath),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId = 0,
+ {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId),
+ ?UINT32(?SSH_FX_FILE_IS_A_DIRECTORY), _/binary>>, _} =
+ open_file(FileName, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -688,9 +845,7 @@ reply(Cm, Channel, RBuf) ->
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end.
-
open_file(File, Cm, Channel, ReqId, Access, Flags) ->
-
Data = list_to_binary([?uint32(ReqId),
?binary(list_to_binary(File)),
?uint32(Access),
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 6233680dce..643ff8e41d 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -113,38 +113,41 @@ std_simple_exec(Host, Port, Config) ->
std_simple_exec(Host, Port, Config, []).
std_simple_exec(Host, Port, Config, Opts) ->
+ ct:log("~p:~p std_simple_exec",[?MODULE,?LINE]),
ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts),
+ ct:log("~p:~p connected! ~p",[?MODULE,?LINE,ConnectionRef]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity),
- Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"42\n">>}},
- case ssh_test_lib:receive_exec_result(Data) of
- expected ->
- ok;
- Other ->
- ct:fail(Other)
- end,
- ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
- ssh:close(ConnectionRef).
-
-
-start_shell(Port, IOServer, UserDir) ->
- start_shell(Port, IOServer, UserDir, []).
-
-start_shell(Port, IOServer, UserDir, Options) ->
- spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}|Options]]).
+ ct:log("~p:~p session_channel ok ~p",[?MODULE,?LINE,ChannelId]),
+ ExecResult = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity),
+ ct:log("~p:~p exec ~p",[?MODULE,?LINE,ExecResult]),
+ case ExecResult of
+ success ->
+ Expected = {ssh_cm, ConnectionRef, {data,ChannelId,0,<<"42\n">>}},
+ case receive_exec_result(Expected) of
+ expected ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end,
+ receive_exec_end(ConnectionRef, ChannelId),
+ ssh:close(ConnectionRef);
+ _ ->
+ ct:fail(ExecResult)
+ end.
start_shell(Port, IOServer) ->
- spawn_link(?MODULE, init_shell, [Port, IOServer, []]).
+ start_shell(Port, IOServer, []).
-init_shell(Port, IOServer, UserDir) ->
- Host = hostname(),
- Options = [{user_interaction, false}, {silently_accept_hosts,
- true}] ++ UserDir,
- group_leader(IOServer, self()),
- loop_shell(Host, Port, Options).
+start_shell(Port, IOServer, ExtraOptions) ->
+ spawn_link(
+ fun() ->
+ Host = hostname(),
+ Options = [{user_interaction, false},
+ {silently_accept_hosts,true} | ExtraOptions],
+ group_leader(IOServer, self()),
+ ssh:shell(Host, Port, Options)
+ end).
-loop_shell(Host, Port, Options) ->
- ssh:shell(Host, Port, Options).
start_io_server() ->
spawn_link(?MODULE, init_io_server, [self()]).
@@ -208,6 +211,16 @@ reply(TestCase, Result) ->
rcv_expected(Expect, SshPort, Timeout) ->
receive
+ {SshPort, Recvd} when is_function(Expect) ->
+ case Expect(Recvd) of
+ true ->
+ ct:log("Got expected ~p from ~p",[Recvd,SshPort]),
+ catch port_close(SshPort),
+ rcv_lingering(50);
+ false ->
+ ct:log("Got UNEXPECTED ~p~n",[Recvd]),
+ rcv_expected(Expect, SshPort, Timeout)
+ end;
{SshPort, Expect} ->
ct:log("Got expected ~p from ~p",[Expect,SshPort]),
catch port_close(SshPort),
@@ -677,13 +690,16 @@ ssh_type() ->
ssh_type1() ->
try
+ ct:log("~p:~p os:find_executable(\"ssh\")",[?MODULE,?LINE]),
case os:find_executable("ssh") of
false ->
ct:log("~p:~p Executable \"ssh\" not found",[?MODULE,?LINE]),
not_found;
- _ ->
+ Path ->
+ ct:log("~p:~p Found \"ssh\" at ~p",[?MODULE,?LINE,Path]),
case os:cmd("ssh -V") of
- "OpenSSH" ++ _ ->
+ Version = "OpenSSH" ++ _ ->
+ ct:log("~p:~p Found OpenSSH ~p",[?MODULE,?LINE,Version]),
openSSH;
Str ->
ct:log("ssh client ~p is unknown",[Str]),
@@ -767,3 +783,82 @@ open_port(Arg1, ExtraOpts) ->
use_stdio,
overlapped_io, hide %only affects windows
| ExtraOpts]).
+
+%%%----------------------------------------------------------------
+%%% Sleeping
+
+%%% Milli sec
+sleep_millisec(Nms) -> receive after Nms -> ok end.
+
+%%% Micro sec
+sleep_microsec(Nus) ->
+ busy_wait(Nus, erlang:system_time(microsecond)).
+
+busy_wait(Nus, T0) ->
+ T = erlang:system_time(microsecond) - T0,
+ Tleft = Nus - T,
+ if
+ Tleft > 2000 ->
+ sleep_millisec((Tleft-1500) div 1000), % μs -> ms
+ busy_wait(Nus,T0);
+ Tleft > 1 ->
+ busy_wait(Nus, T0);
+ true ->
+ T
+ end.
+
+%%%----------------------------------------------------------------
+%% get_kex_init - helper function to get key_exchange_init_msg
+
+get_kex_init(Conn) ->
+ Ref = make_ref(),
+ {ok,TRef} = timer:send_after(15000, {reneg_timeout,Ref}),
+ get_kex_init(Conn, Ref, TRef).
+
+get_kex_init(Conn, Ref, TRef) ->
+ %% First, validate the key exchange is complete (StateName == connected)
+ case sys:get_state(Conn) of
+ {{connected,_}, S} ->
+ timer:cancel(TRef),
+ %% Next, walk through the elements of the #state record looking
+ %% for the #ssh_msg_kexinit record. This method is robust against
+ %% changes to either record. The KEXINIT message contains a cookie
+ %% unique to each invocation of the key exchange procedure (RFC4253)
+ SL = tuple_to_list(S),
+ case lists:keyfind(ssh_msg_kexinit, 1, SL) of
+ false ->
+ throw(not_found);
+ KexInit ->
+ KexInit
+ end;
+
+ {OtherState, S} ->
+ ct:log("Not in 'connected' state: ~p",[OtherState]),
+ receive
+ {reneg_timeout,Ref} ->
+ ct:log("S = ~p", [S]),
+ ct:fail(reneg_timeout)
+ after 0 ->
+ timer:sleep(100), % If renegotiation is complete we do not
+ % want to exit on the reneg_timeout
+ get_kex_init(Conn, Ref, TRef)
+ end
+ end.
+
+%%%----------------------------------------------------------------
+%%% Return a string with N random characters
+%%%
+random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+
+
+create_random_dir(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Name = filename:join(PrivDir, random_chars(15)),
+ case file:make_dir(Name) of
+ ok ->
+ Name;
+ {error,eexist} ->
+ %% The Name already denotes an existing file system object, try again.
+ %% The likelyhood of always generating an existing file name is low
+ create_random_dir(Config)
+ end.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index a914938c41..547f759a00 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,13 +29,14 @@
-define(TIMEOUT, 50000).
-define(SSH_DEFAULT_PORT, 22).
+-define(REKEY_DATA_TMO, 65000).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
suite() ->
- [{timetrap,{seconds,20}}].
+ [{timetrap,{seconds,60}}].
all() ->
case os:find_executable("ssh") of
@@ -55,10 +56,12 @@ groups() ->
erlang_client_openssh_server_publickey_rsa,
erlang_client_openssh_server_password,
erlang_client_openssh_server_kexs,
- erlang_client_openssh_server_nonexistent_subsystem
+ erlang_client_openssh_server_nonexistent_subsystem,
+ erlang_client_openssh_server_renegotiate
]},
{erlang_server, [], [erlang_server_openssh_client_public_key_dsa,
- erlang_server_openssh_client_public_key_rsa
+ erlang_server_openssh_client_public_key_rsa,
+ erlang_server_openssh_client_renegotiate
]}
].
@@ -104,6 +107,11 @@ init_per_testcase(erlang_server_openssh_client_public_key_rsa, Config) ->
chk_key(sshc, 'ssh-rsa', ".ssh/id_rsa", Config);
init_per_testcase(erlang_client_openssh_server_publickey_dsa, Config) ->
chk_key(sshd, 'ssh-dss', ".ssh/id_dsa", Config);
+init_per_testcase(erlang_server_openssh_client_renegotiate, Config) ->
+ case os:type() of
+ {unix,_} -> ssh:start(), Config;
+ Type -> {skip, io_lib:format("Unsupported test on ~p",[Type])}
+ end;
init_per_testcase(_TestCase, Config) ->
ssh:start(),
Config.
@@ -145,7 +153,7 @@ erlang_shell_client_openssh_server(Config) when is_list(Config) ->
IO = ssh_test_lib:start_io_server(),
Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO),
IO ! {input, self(), "echo Hej\n"},
- receive_hej(),
+ receive_data("Hej"),
IO ! {input, self(), "exit\n"},
receive_logout(),
receive_normal_exit(Shell).
@@ -386,6 +394,112 @@ erlang_server_openssh_client_public_key_X(Config, PubKeyAlg) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+%% Test that the Erlang/OTP server can renegotiate with openSSH
+erlang_server_openssh_client_renegotiate(Config) ->
+ PubKeyAlg = ssh_rsa,
+ SystemDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {public_key_alg, PubKeyAlg},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ct:sleep(500),
+
+ RenegLimitK = 3,
+ DataFile = filename:join(PrivDir, "renegotiate_openssh_client.data"),
+ Data = lists:duplicate(trunc(1.1*RenegLimitK*1024), $a),
+ ok = file:write_file(DataFile, Data),
+
+ Cmd = "ssh -p " ++ integer_to_list(Port) ++
+ " -o UserKnownHostsFile=" ++ KnownHosts ++
+ " -o RekeyLimit=" ++ integer_to_list(RenegLimitK) ++"K" ++
+ " " ++ Host ++ " < " ++ DataFile,
+ OpenSsh = ssh_test_lib:open_port({spawn, Cmd}),
+
+ Expect = fun({data,R}) ->
+ try
+ NonAlphaChars = [C || C<-lists:seq(1,255),
+ not lists:member(C,lists:seq($a,$z)),
+ not lists:member(C,lists:seq($A,$Z))
+ ],
+ Lines = string:tokens(binary_to_list(R), NonAlphaChars),
+ lists:any(fun(L) -> length(L)>1 andalso lists:prefix(L, Data) end,
+ Lines)
+ catch
+ _:_ -> false
+ end;
+
+ ({exit_status,E}) when E=/=0 ->
+ ct:log("exit_status ~p",[E]),
+ throw({skip,"exit status"});
+
+ (_) ->
+ false
+ end,
+
+ try
+ ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT)
+ of
+ _ ->
+ %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
+ ssh:stop_daemon(Pid)
+ catch
+ throw:{skip,R} -> {skip,R}
+ end.
+
+%%--------------------------------------------------------------------
+erlang_client_openssh_server_renegotiate(_Config) ->
+ process_flag(trap_exit, true),
+
+ IO = ssh_test_lib:start_io_server(),
+ Ref = make_ref(),
+ Parent = self(),
+
+ Shell =
+ spawn_link(
+ fun() ->
+ Host = ssh_test_lib:hostname(),
+ Options = [{user_interaction, false},
+ {silently_accept_hosts,true}],
+ group_leader(IO, self()),
+ {ok, ConnRef} = ssh:connect(Host, ?SSH_DEFAULT_PORT, Options),
+ ct:pal("Parent = ~p, IO = ~p, Shell = ~p, ConnRef = ~p~n",[Parent, IO, self(), ConnRef]),
+ case ssh_connection:session_channel(ConnRef, infinity) of
+ {ok,ChannelId} ->
+ success = ssh_connection:ptty_alloc(ConnRef, ChannelId, []),
+ Args = [{channel_cb, ssh_shell},
+ {init_args,[ConnRef, ChannelId]},
+ {cm, ConnRef}, {channel_id, ChannelId}],
+ {ok, State} = ssh_channel:init([Args]),
+ Parent ! {ok, Ref, ConnRef},
+ ssh_channel:enter_loop(State);
+ Error ->
+ Parent ! {error, Ref, Error}
+ end,
+ receive
+ nothing -> ok
+ end
+ end),
+
+ receive
+ {error, Ref, Error} ->
+ ct:fail("Error=~p",[Error]);
+ {ok, Ref, ConnectionRef} ->
+ IO ! {input, self(), "echo Hej1\n"},
+ receive_data("Hej1"),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+ ssh_connection_handler:renegotiate(ConnectionRef),
+ IO ! {input, self(), "echo Hej2\n"},
+ receive_data("Hej2"),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
+ IO ! {input, self(), "exit\n"},
+ receive_logout(),
+ receive_normal_exit(Shell),
+ true = (Kex1 =/= Kex2)
+ end.
+
+%%--------------------------------------------------------------------
erlang_client_openssh_server_password() ->
[{doc, "Test client password option"}].
erlang_client_openssh_server_password(Config) when is_list(Config) ->
@@ -440,27 +554,24 @@ erlang_client_openssh_server_nonexistent_subsystem(Config) when is_list(Config)
%%--------------------------------------------------------------------
%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
-receive_hej() ->
+receive_data(Data) ->
receive
- <<"Hej", _binary>> = Hej ->
- ct:log("Expected result: ~p~n", [Hej]);
- <<"Hej\n", _binary>> = Hej ->
- ct:log("Expected result: ~p~n", [Hej]);
- <<"Hej\r\n", _/binary>> = Hej ->
- ct:log("Expected result: ~p~n", [Hej]);
- Info ->
- Lines = binary:split(Info, [<<"\r\n">>], [global]),
- case lists:member(<<"Hej">>, Lines) of
+ Info when is_binary(Info) ->
+ Lines = string:tokens(binary_to_list(Info), "\r\n "),
+ case lists:member(Data, Lines) of
true ->
ct:log("Expected result found in lines: ~p~n", [Lines]),
ok;
false ->
ct:log("Extra info: ~p~n", [Info]),
- receive_hej()
- end
+ receive_data(Data)
+ end;
+ Other ->
+ ct:log("Unexpected: ~p",[Other]),
+ receive_data(Data)
after
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
- end.
+ end.
receive_logout() ->
receive
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index e34071af99..bc86000d81 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% The 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/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl
index b5b27c369a..7b9b109fa1 100644
--- a/lib/ssh/test/ssh_upgrade_SUITE.erl
+++ b/lib/ssh/test/ssh_upgrade_SUITE.erl
@@ -199,6 +199,4 @@ close(#state{server = Server,
connection = undefined}.
-random_contents() -> list_to_binary( random_chars(3) ).
-
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+random_contents() -> list_to_binary( ssh_test_lib:random_chars(3) ).
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index b165928877..9135d8f954 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3
+SSH_VSN = 4.4.2.4
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 3b6f988a2d..a8b284304e 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -28,6 +28,293 @@
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 8.1.3.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix alert handling so that unexpected messages are logged
+ and alerted correctly</p>
+ <p>
+ Own Id: OTP-14929</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.1.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> An erlang TLS server configured with cipher suites
+ using rsa key exchange, may be vulnerable to an Adaptive
+ Chosen Ciphertext attack (AKA Bleichenbacher attack)
+ against RSA, which when exploited, may result in
+ plaintext recovery of encrypted messages and/or a
+ Man-in-the-middle (MiTM) attack, despite the attacker not
+ having gained access to the server’s private key
+ itself. <url
+ href="https://nvd.nist.gov/vuln/detail/CVE-2017-1000385">CVE-2017-1000385</url>
+ </p> <p> Exploiting this vulnerability to perform
+ plaintext recovery of encrypted messages will, in most
+ practical cases, allow an attacker to read the plaintext
+ only after the session has completed. Only TLS sessions
+ established using RSA key exchange are vulnerable to this
+ attack. </p> <p> Exploiting this vulnerability to conduct
+ a MiTM attack requires the attacker to complete the
+ initial attack, which may require thousands of server
+ requests, during the handshake phase of the targeted
+ session within the window of the configured handshake
+ timeout. This attack may be conducted against any TLS
+ session using RSA signatures, but only if cipher suites
+ using RSA key exchange are also enabled on the server.
+ The limited window of opportunity, limitations in
+ bandwidth, and latency make this attack significantly
+ more difficult to execute. </p> <p> RSA key exchange is
+ enabled by default although least prioritized if server
+ order is honored. For such a cipher suite to be chosen it
+ must also be supported by the client and probably the
+ only shared cipher suite. </p> <p> Captured TLS sessions
+ encrypted with ephemeral cipher suites (DHE or ECDHE) are
+ not at risk for subsequent decryption due to this
+ vulnerability. </p> <p> As a workaround if default cipher
+ suite configuration was used you can configure the server
+ to not use vulnerable suites with the ciphers option like
+ this: </p> <c> {ciphers, [Suite || Suite &lt;-
+ ssl:cipher_suites(), element(1,Suite) =/= rsa]} </c> <p>
+ that is your code will look somethingh like this: </p>
+ <c> ssl:listen(Port, [{ciphers, [Suite || Suite &lt;-
+ ssl:cipher_suites(), element(1,S) =/= rsa]} | Options]).
+ </c> <p> Thanks to Hanno Böck, Juraj Somorovsky and
+ Craig Young for reporting this vulnerability. </p>
+ <p>
+ Own Id: OTP-14748</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.1.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Remove debug printout</p>
+ <p>
+ Own Id: OTP-14396</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct active once emulation, for TLS. Now all data
+ received by the connection process will be delivered
+ through active once, even when the active once arrives
+ after that the gen_tcp socket is closed by the peer.</p>
+ <p>
+ Own Id: OTP-14300</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Corrected termination behavior, that caused a PEM cache
+ bug and sometimes resulted in connection failures.</p>
+ <p>
+ Own Id: OTP-14100</p>
+ </item>
+ <item>
+ <p>
+ Fix bug that could hang ssl connection processes when
+ failing to require more data for very large handshake
+ packages. Add option max_handshake_size to mitigate DoS
+ attacks.</p>
+ <p>
+ Own Id: OTP-14138</p>
+ </item>
+ <item>
+ <p>
+ Improved support for CRL handling that could fail to work
+ as intended when an id-ce-extKeyUsage was present in the
+ certificate. Also improvements where needed to
+ distributionpoint handling so that all revocations
+ actually are found and not deemed to be not determinable.</p>
+ <p>
+ Own Id: OTP-14141</p>
+ </item>
+ <item>
+ <p>
+ A TLS handshake might accidentally match old sslv2 format
+ and ssl application would incorrectly aborted TLS
+ handshake with ssl_v2_client_hello_no_supported. Parsing
+ was altered to avoid this problem.</p>
+ <p>
+ Own Id: OTP-14222</p>
+ </item>
+ <item>
+ <p>
+ Correct default cipher list to prefer AES 128 before 3DES</p>
+ <p>
+ Own Id: OTP-14235</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Move PEM cache to a dedicated process, to avoid making
+ the SSL manager process a bottleneck. This improves
+ scalability of TLS connections.</p>
+ <p>
+ Own Id: OTP-13874</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ List of possible anonymous suites, never supported by
+ default, where incorrect for some TLS versions.</p>
+ <p>
+ Own Id: OTP-13926</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Experimental version of DTLS. It is runnable but not
+ complete and cannot be considered reliable for production
+ usage.</p>
+ <p>
+ Own Id: OTP-12982</p>
+ </item>
+ <item>
+ <p>
+ Add API options to handle ECC curve selection.</p>
+ <p>
+ Own Id: OTP-13959</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A timing related bug in event handling could cause
+ interoperability problems between an erlang TLS server
+ and some TLS clients, especially noticed with Firefox as
+ TLS client.</p>
+ <p>
+ Own Id: OTP-13917</p>
+ </item>
+ <item>
+ <p>
+ Correct ECC curve selection, the error could cause the
+ default to always be selected.</p>
+ <p>
+ Own Id: OTP-13918</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correctly formed handshake messages received out of order
+ will now correctly fail the connection with unexpected
+ message.</p>
+ <p>
+ Own Id: OTP-13853</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ ssl application now behaves gracefully also on partially
+ incorrect input from peer.</p>
+ <p>
+ Own Id: OTP-13834</p>
+ </item>
+ <item>
+ <p>
+ Add application environment configuration
+ bypass_pem_cache. This can be used as a workaround for
+ the current implementation of the PEM-cache that has
+ proven to be a bottleneck.</p>
+ <p>
+ Own Id: OTP-13883</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The TLS/SSL protocol version selection for the SSL server
+ has been corrected to follow RFC 5246 Appendix E.1
+ especially in case where the list of supported versions
+ has gaps. Now the server selects the highest protocol
+ version it supports that is not higher than what the
+ client supports.</p>
+ <p>
+ Own Id: OTP-13753 Aux Id: seq13150 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index abba5aaf59..916b41742e 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -155,7 +155,7 @@
<tag><c>cipher() =</c></tag>
<item><p><c>rc4_128 | des_cbc | '3des_ede_cbc'
- | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm</c></p></item>
+ | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305</c></p></item>
<tag><c>hash() =</c></tag>
<item><p><c>md5 | sha | sha224 | sha256 | sha348 | sha512</c></p></item>
@@ -170,6 +170,14 @@
<tag><c>SNIfun::fun()</c></tag>
<item><p><c>= fun(ServerName :: string()) -> [ssl_option()]</c></p></item>
+ <tag><c>named_curve() =</c></tag>
+ <item><p><c>sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1
+ | sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1
+ | sect283k1 | sect283r1 | brainpoolP256r1 | secp256k1 | secp256r1
+ | sect239k1 | sect233k1 | sect233r1 | secp224k1 | secp224r1
+ | sect193r1 | sect193r2 | secp192k1 | secp192r1 | sect163k1
+ | sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2</c></p></item>
+
</taglist>
</section>
@@ -217,6 +225,11 @@
Anonymous cipher suites are supported for testing purposes
only and are not be used when security matters.</p></item>
+ <tag><c>{eccs, [named_curve()]}</c></tag>
+ <item><p> Allows to specify the order of preference for named curves
+ and to restrict their usage when using a cipher suite supporting them.
+ </p></item>
+
<tag><c>{secure_renegotiate, boolean()}</c></tag>
<item><p>Specifies if to reject renegotiation attempt that does
not live up to
@@ -411,6 +424,14 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
</taglist>
</item>
+
+ <tag><c>max_handshake_size</c></tag>
+ <item>
+ <p>Integer (24 bits unsigned). Used to limit the size of
+ valid TLS handshake packets to avoid DoS attacks.
+ Defaults to 256*1024.</p>
+ </item>
+
</taglist>
</item>
@@ -751,6 +772,11 @@ fun(srp, Username :: string(), UserState :: term()) ->
(the default), use the client's preference.
</item>
+ <tag><c>{honor_ecc_order, boolean()}</c></tag>
+ <item>If true, use the server's preference for ECC curve selection. If false
+ (the default), use the client's preference.
+ </item>
+
<tag><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag>
<item><p> The algorithms specified by
this option will be the ones accepted by the server in a signature algorithm
@@ -804,6 +830,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
+ <name>eccs() -></name>
+ <name>eccs(protocol()) -> [named_curve()]</name>
+ <fsummary>Returns a list of supported ECCs.</fsummary>
+
+ <desc><p>Returns a list of supported ECCs. <c>eccs()</c>
+ is equivalent to calling <c>eccs(Protocol)</c> with all
+ supported protocols and then deduplicating the output.</p>
+ </desc>
+ </func>
+
+ <func>
<name>clear_pem_cache() -> ok </name>
<fsummary> Clears the pem cache</fsummary>
@@ -898,7 +935,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<fsummary>Returns all the connection information.
</fsummary>
<type>
- <v>Item = protocol | cipher_suite | sni_hostname | atom()</v>
+ <v>Item = protocol | cipher_suite | sni_hostname | ecc | atom()</v>
<d>Meaningful atoms, not specified above, are the ssl option names.</d>
<v>Result = [{Item::atom(), Value::term()}]</v>
<v>Reason = term()</v>
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index a66e947bc1..f317dfded4 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -141,6 +141,16 @@
marker="ssl#clear_pem_cache-0">ssl:clear_pem_cache/0</seealso>
</item>
+
+ <tag><c><![CDATA[bypass_pem_cache = boolean() <optional>]]></c></tag>
+ <item>
+ <p>Introduced in ssl-8.0.2. Disables the PEM-cache.
+ The PEM cache has proven to be a bottleneck, until the
+ implementation has been improved this can be used as
+ a workaround. Defaults to false.
+ </p>
+ </item>
+
<tag><c><![CDATA[alert_timeout = integer() <optional>]]></c></tag>
<item>
<p>
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
index 7440b6ef04..c6774b4df6 100644
--- a/lib/ssl/doc/src/ssl_crl_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2015</year><year>2015</year>
+ <year>2015</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index 4bd5f67202..61f88e3860 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -43,7 +43,7 @@
Erlang node distributed, <c>net_kernel</c> uses this module to
set up listen ports and connections.</p>
- <p>In the SSL application, an exra distribution
+ <p>In the SSL application, an extra distribution
module, <c>inet_tls_dist</c>, can be used as an
alternative. All distribution connections will use SSL and
all participating Erlang nodes in a distributed system must use
@@ -71,8 +71,8 @@
<section>
<title>Building Boot Scripts Including the ssl Application</title>
<p>Boot scripts are built using the <c>systools</c> utility in the
- <c>sasl</c> application. For more information on <c>systools</c>,
- see the <c>sasl</c> documentation. This is only an example of
+ SASL application. For more information on <c>systools</c>,
+ see the SASL documentation. This is only an example of
what can be done.</p>
<p>The simplest boot script possible includes only the Kernel
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
index b85d8fb284..a84a3dfce9 100644
--- a/lib/ssl/doc/src/ssl_session_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -4,14 +4,14 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2015</year>
+ <year>1999</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -62,8 +62,8 @@
</taglist>
</section>
-
- <funcs>
+
+ <funcs>
<func>
<name>delete(Cache, Key) -> _</name>
@@ -134,7 +134,7 @@
</p>
</desc>
</func>
-
+
<func>
<name>select_session(Cache, PartialKey) -> [session()]</name>
<fsummary>Selects sessions that can be reused.</fsummary>
@@ -151,6 +151,21 @@
</func>
<func>
+ <name>size(Cache) -> integer()</name>
+ <fsummary>Returns the number of sessions in the cache.</fsummary>
+ <type>
+ <v>Cache = cache_ref()</v>
+ </type>
+ <desc>
+ <p>Returns the number of sessions in the cache. If size
+ exceeds the maximum number of sessions, the current cache
+ entries will be invalidated regardless of their remaining
+ lifetime. Is to be callable from any process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>terminate(Cache) -> _</name>
<fsummary>Called by the process that handles the cache when it
is about to terminate.</fsummary>
@@ -178,7 +193,7 @@
</p>
</desc>
</func>
-
- </funcs>
-
+
+ </funcs>
+
</erlref>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index b625db0656..2e7df9792e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2015. All Rights Reserved.
+# Copyright Ericsson AB 1999-2016. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -48,8 +48,17 @@ MODULES= \
dtls \
ssl_alert \
ssl_app \
- ssl_dist_sup\
ssl_sup \
+ ssl_admin_sup\
+ tls_connection_sup \
+ ssl_connection_sup \
+ ssl_listen_tracker_sup\
+ dtls_connection_sup \
+ dtls_udp_listener\
+ dtls_udp_sup \
+ ssl_dist_sup\
+ ssl_dist_admin_sup\
+ ssl_dist_connection_sup\
inet_tls_dist \
inet6_tls_dist \
ssl_certificate\
@@ -60,19 +69,18 @@ MODULES= \
dtls_connection \
ssl_config \
ssl_connection \
- tls_connection_sup \
- dtls_connection_sup \
tls_handshake \
dtls_handshake\
ssl_handshake\
ssl_manager \
ssl_session \
ssl_session_cache \
+ ssl_pem_cache \
ssl_crl\
ssl_crl_cache \
ssl_crl_hash_dir \
- ssl_socket \
- ssl_listen_tracker_sup \
+ tls_socket \
+ dtls_socket \
tls_record \
dtls_record \
ssl_record \
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index b8be686b99..130a8bb1c5 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,35 +39,28 @@
-export([start_fsm/8, start_link/7, init/1]).
%% State transition handling
--export([next_record/1, next_event/3]).
+-export([next_record/1, next_event/3, next_event/4]).
%% Handshake handling
--export([%%renegotiate/2,
- send_handshake/2, queue_handshake/2, queue_change_cipher/2]).
+-export([renegotiate/2,
+ reinit_handshake_data/1,
+ send_handshake/2, queue_handshake/2, queue_change_cipher/2,
+ select_sni_extension/1]).
%% Alert and close handling
--export([%%send_alert/2, handle_own_alert/4, handle_close_alert/3,
- handle_normal_shutdown/3 %%, close/5
- %%alert_user/6, alert_user/9
- ]).
+-export([encode_alert/3,send_alert/2, close/5]).
%% Data handling
--export([%%write_application_data/3,
- read_application_data/2,
- passive_receive/2, next_record_if_active/1%,
- %%handle_common_event/4,
- %handle_packet/3
- ]).
+-export([encode_data/3, passive_receive/2, next_record_if_active/1, handle_common_event/4,
+ send/3, socket/5]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
connection/3]).
%% gen_statem callbacks
--export([terminate/3, code_change/4, format_status/2]).
-
--define(GEN_STATEM_CB_MODE, state_functions).
+-export([callback_mode/0, terminate/3, code_change/4, format_status/2]).
%%====================================================================
%% Internal application API
@@ -84,70 +77,139 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker}
catch
error:{badmatch, {error, _} = Error} ->
Error
- end;
-
-start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} = 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, Tracker),
- ok = ssl_connection:handshake(SslSocket, Timeout),
- {ok, SslSocket}
- catch
- error:{badmatch, {error, _} = Error} ->
- Error
end.
-send_handshake(Handshake, State) ->
- send_handshake_flight(queue_handshake(Handshake, State)).
-
-queue_flight_buffer(Msg, #state{negotiated_version = Version,
- connection_states = #connection_states{
- current_write =
- #connection_state{epoch = Epoch}},
- flight_buffer = Flight} = State) ->
- State#state{flight_buffer = Flight ++ [{Version, Epoch, Msg}]}.
+send_handshake(Handshake, #state{connection_states = ConnectionStates} = States) ->
+ #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
+ send_handshake_flight(queue_handshake(Handshake, States), Epoch).
+
+queue_handshake(Handshake0, #state{tls_handshake_history = Hist0,
+ negotiated_version = Version,
+ flight_buffer = #{handshakes := HsBuffer0,
+ change_cipher_spec := undefined,
+ next_sequence := Seq} = Flight0} = State) ->
+ Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
+ Hist = update_handshake_history(Handshake0, Handshake, Hist0),
+ State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0],
+ next_sequence => Seq +1},
+ tls_handshake_history = Hist};
+
+queue_handshake(Handshake0, #state{tls_handshake_history = Hist0,
+ negotiated_version = Version,
+ flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0,
+ next_sequence := Seq} = Flight0} = State) ->
+ Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
+ Hist = update_handshake_history(Handshake0, Handshake, Hist0),
+ State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0],
+ next_sequence => Seq +1},
+ tls_handshake_history = Hist}.
-queue_handshake(Handshake, #state{negotiated_version = Version,
- tls_handshake_history = Hist0,
- connection_states = ConnectionStates0} = State0) ->
- {Frag, ConnectionStates, Hist} =
- encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
- queue_flight_buffer(Frag, State0#state{connection_states = ConnectionStates,
- tls_handshake_history = Hist}).
send_handshake_flight(#state{socket = Socket,
transport_cb = Transport,
- flight_buffer = Flight,
- connection_states = ConnectionStates0} = State0) ->
-
+ flight_buffer = #{handshakes := Flight,
+ change_cipher_spec := undefined},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ %% TODO remove hardcoded Max size
{Encoded, ConnectionStates} =
- encode_handshake_flight(Flight, ConnectionStates0),
+ encode_handshake_flight(lists:reverse(Flight), Version, 1400, Epoch, ConnectionStates0),
+ send(Transport, Socket, Encoded),
+ start_flight(State0#state{connection_states = ConnectionStates});
- Transport:send(Socket, Encoded),
- State0#state{flight_buffer = [], connection_states = ConnectionStates}.
+send_handshake_flight(#state{socket = Socket,
+ transport_cb = Transport,
+ flight_buffer = #{handshakes := [_|_] = Flight0,
+ change_cipher_spec := ChangeCipher,
+ handshakes_after_change_cipher_spec := []},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ {HsBefore, ConnectionStates1} =
+ encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch, ConnectionStates0),
+ {EncChangeCipher, ConnectionStates} = encode_change_cipher(ChangeCipher, Version, Epoch, ConnectionStates1),
+
+ send(Transport, Socket, [HsBefore, EncChangeCipher]),
+ start_flight(State0#state{connection_states = ConnectionStates});
-queue_change_cipher(Msg, State) ->
- queue_flight_buffer(Msg, State).
+send_handshake_flight(#state{socket = Socket,
+ transport_cb = Transport,
+ flight_buffer = #{handshakes := [_|_] = Flight0,
+ change_cipher_spec := ChangeCipher,
+ handshakes_after_change_cipher_spec := Flight1},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ {HsBefore, ConnectionStates1} =
+ encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch-1, ConnectionStates0),
+ {EncChangeCipher, ConnectionStates2} =
+ encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates1),
+ {HsAfter, ConnectionStates} =
+ encode_handshake_flight(lists:reverse(Flight1), Version, 1400, Epoch, ConnectionStates2),
+ send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]),
+ start_flight(State0#state{connection_states = ConnectionStates});
+
+send_handshake_flight(#state{socket = Socket,
+ transport_cb = Transport,
+ flight_buffer = #{handshakes := [],
+ change_cipher_spec := ChangeCipher,
+ handshakes_after_change_cipher_spec := Flight1},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ {EncChangeCipher, ConnectionStates1} =
+ encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0),
+ {HsAfter, ConnectionStates} =
+ encode_handshake_flight(lists:reverse(Flight1), Version, 1400, Epoch, ConnectionStates1),
+ send(Transport, Socket, [EncChangeCipher, HsAfter]),
+ start_flight(State0#state{connection_states = ConnectionStates}).
+
+queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight,
+ connection_states = ConnectionStates0} = State) ->
+ ConnectionStates =
+ dtls_record:next_epoch(ConnectionStates0, write),
+ State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher},
+ connection_states = ConnectionStates}.
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),
+ encode_alert(Alert, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
State0#state{connection_states = ConnectionStates}.
+close(downgrade, _,_,_,_) ->
+ ok;
+%% Other
+close(_, Socket, Transport, _,_) ->
+ dtls_socket:close(Transport,Socket).
+
+reinit_handshake_data(#state{protocol_buffers = Buffers} = State) ->
+ State#state{premaster_secret = undefined,
+ public_key_info = undefined,
+ tls_handshake_history = ssl_handshake:init_handshake_history(),
+ flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
+ protocol_buffers =
+ Buffers#protocol_buffers{
+ dtls_handshake_next_seq = 0,
+ dtls_handshake_next_fragments = [],
+ dtls_handshake_later_fragments = []
+ }}.
+
+select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
+ HelloExtensions#hello_extensions.sni;
+select_sni_extension(_) ->
+ undefined.
+
+socket(Pid, Transport, Socket, Connection, _) ->
+ dtls_socket:socket(Pid, Transport, Socket, Connection).
+
%%====================================================================
%% tls_connection_sup API
%%====================================================================
%%--------------------------------------------------------------------
-spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
- {ok, pid()} | ignore | {error, reason()}.
+ {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
@@ -161,21 +223,23 @@ init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
- gen_statem:enter_loop(?MODULE, [], ?GEN_STATEM_CB_MODE, init, State)
+ gen_statem:enter_loop(?MODULE, [], init, State)
catch
throw:Error ->
- gen_statem:enter_loop(?MODULE, [], ?GEN_STATEM_CB_MODE, error, {Error,State0})
+ gen_statem:enter_loop(?MODULE, [], error, {Error,State0})
end.
+callback_mode() ->
+ state_functions.
+
%%--------------------------------------------------------------------
-%% State functionsconnection/2
+%% State functions
%%--------------------------------------------------------------------
init({call, From}, {start, Timeout},
#state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
session = #session{own_certificate = Cert} = Session0,
- transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _},
session_cache = Cache,
@@ -183,23 +247,28 @@ init({call, From}, {start, Timeout},
} = State0) ->
Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From),
Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
- Cache, CacheCb, Renegotiation, Cert),
-
+ Cache, CacheCb, Renegotiation, Cert),
+
Version = Hello#client_hello.client_version,
HelloVersion = dtls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
- Handshake0 = ssl_handshake:init_handshake_history(),
- {BinMsg, ConnectionStates, Handshake} =
- encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0),
- Transport:send(Socket, BinMsg),
- State1 = State0#state{connection_states = ConnectionStates,
- negotiated_version = Version, %% Requested version
+ State1 = prepare_flight(State0#state{negotiated_version = Version}),
+ {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
+ State3 = State2#state{negotiated_version = Version, %% Requested version
session =
Session0#session{session_id = Hello#client_hello.session_id},
- tls_handshake_history = Handshake,
start_or_recv_from = From,
- timer = Timer},
- {Record, State} = next_record(State1),
- next_event(hello, Record, State);
+ timer = Timer,
+ flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}
+ },
+ {Record, State} = next_record(State3),
+ next_event(hello, Record, State, Actions);
+init({call, _} = Type, Event, #state{role = server, transport_cb = gen_udp} = State) ->
+ ssl_connection:init(Type, Event,
+ State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}},
+ ?MODULE);
+init({call, _} = Type, Event, #state{role = server} = State) ->
+ %% I.E. DTLS over sctp
+ ssl_connection:init(Type, Event, State#state{flight_state = reliable}, ?MODULE);
init(Type, Event, State) ->
ssl_connection:init(Type, Event, State, ?MODULE).
@@ -216,37 +285,53 @@ error(_, _, _) ->
#state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-hello(internal, #client_hello{client_version = ClientVersion,
- extensions = #hello_extensions{ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves}} = Hello,
- State = #state{connection_states = ConnectionStates0,
- port = Port, session = #session{own_certificate = Cert} = Session0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb,
- negotiated_protocol = CurrentProtocol,
- key_algorithm = KeyExAlg,
- ssl_options = SslOpts}) ->
-
- case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
- ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
- #alert{} = Alert ->
- handle_own_alert(Alert, ClientVersion, hello, State);
- {Version, {Type, Session},
- ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
- Protocol = case Protocol0 of
- undefined -> CurrentProtocol;
- _ -> Protocol0
- end,
-
- ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt},
- State#state{connection_states = ConnectionStates,
- negotiated_version = Version,
- hashsign_algorithm = HashSign,
- session = Session,
- client_ecc = {EllipticCurves, EcPointFormats},
- negotiated_protocol = Protocol}, ?MODULE)
+hello(internal, #client_hello{cookie = <<>>,
+ client_version = Version} = Hello, #state{role = server,
+ transport_cb = Transport,
+ socket = Socket} = State0) ->
+ %% TODO: not hard code key
+ {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
+ Cookie = dtls_handshake:cookie(<<"secret">>, IP, Port, Hello),
+ VerifyRequest = dtls_handshake:hello_verify_request(Cookie, Version),
+ State1 = prepare_flight(State0#state{negotiated_version = Version}),
+ {State2, Actions} = send_handshake(VerifyRequest, State1),
+ {Record, State} = next_record(State2),
+ next_event(hello, Record, State#state{tls_handshake_history = ssl_handshake:init_handshake_history()}, Actions);
+hello(internal, #client_hello{cookie = Cookie} = Hello, #state{role = server,
+ transport_cb = Transport,
+ socket = Socket} = State0) ->
+ {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
+ %% TODO: not hard code key
+ case dtls_handshake:cookie(<<"secret">>, IP, Port, Hello) of
+ Cookie ->
+ handle_client_hello(Hello, State0);
+ _ ->
+ %% Handle bad cookie as new cookie request RFC 6347 4.1.2
+ hello(internal, Hello#client_hello{cookie = <<>>}, State0)
end;
+hello(internal, #hello_verify_request{cookie = Cookie}, #state{role = client,
+ host = Host, port = Port,
+ ssl_options = SslOpts,
+ session = #session{own_certificate = OwnCert}
+ = Session0,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb
+ } = State0) ->
+ State1 = prepare_flight(State0#state{tls_handshake_history = ssl_handshake:init_handshake_history()}),
+ Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0,
+ SslOpts,
+ Cache, CacheCb, Renegotiation, OwnCert),
+ Version = Hello#client_hello.client_version,
+ HelloVersion = dtls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
+ {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
+ State3 = State2#state{negotiated_version = Version, %% Requested version
+ session =
+ Session0#session{session_id =
+ Hello#client_hello.session_id}},
+ {Record, State} = next_record(State3),
+ next_event(hello, Record, State, Actions);
hello(internal, #server_hello{} = Hello,
#state{connection_states = ConnectionStates0,
negotiated_version = ReqVersion,
@@ -255,29 +340,64 @@ hello(internal, #server_hello{} = Hello,
ssl_options = SslOptions} = State) ->
case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
- handle_own_alert(Alert, ReqVersion, hello, State);
+ ssl_connection:handle_own_alert(Alert, ReqVersion, hello, State);
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
end;
+hello(internal, {handshake, {#client_hello{cookie = <<>>} = Handshake, _}}, State) ->
+ %% Initial hello should not be in handshake history
+ {next_state, hello, State, [{next_event, internal, Handshake}]};
+hello(internal, {handshake, {#hello_verify_request{} = Handshake, _}}, State) ->
+ %% hello_verify should not be in handshake history
+ {next_state, hello, State, [{next_event, internal, Handshake}]};
hello(info, Event, State) ->
handle_info(Event, hello, State);
-
+hello(state_timeout, Event, State) ->
+ handle_state_timeout(Event, hello, State);
hello(Type, Event, State) ->
ssl_connection:hello(Type, Event, State, ?MODULE).
abbreviated(info, Event, State) ->
handle_info(Event, abbreviated, State);
+abbreviated(internal = Type,
+ #change_cipher_spec{type = <<1>>} = Event,
+ #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
+ ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
+ ssl_connection:abbreviated(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
+abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
+ ssl_connection:abbreviated(Type, Event,
+ prepare_flight(State#state{connection_states = ConnectionStates,
+ flight_state = connection}), ?MODULE);
+abbreviated(state_timeout, Event, State) ->
+ handle_state_timeout(Event, abbreviated, State);
abbreviated(Type, Event, State) ->
ssl_connection:abbreviated(Type, Event, State, ?MODULE).
certify(info, Event, State) ->
handle_info(Event, certify, State);
+certify(internal = Type, #server_hello_done{} = Event, State) ->
+ ssl_connection:certify(Type, Event, prepare_flight(State), ?MODULE);
+certify(state_timeout, Event, State) ->
+ handle_state_timeout(Event, certify, State);
certify(Type, Event, State) ->
ssl_connection:certify(Type, Event, State, ?MODULE).
cipher(info, Event, State) ->
handle_info(Event, cipher, State);
+cipher(internal = Type, #change_cipher_spec{type = <<1>>} = Event,
+ #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
+ ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
+ ssl_connection:cipher(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
+cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
+ ssl_connection:cipher(Type, Event,
+ prepare_flight(State#state{connection_states = ConnectionStates,
+ flight_state = connection}),
+ ?MODULE);
+cipher(state_timeout, Event, State) ->
+ handle_state_timeout(Event, cipher, State);
cipher(Type, Event, State) ->
ssl_connection:cipher(Type, Event, State, ?MODULE).
@@ -291,13 +411,12 @@ connection(internal, #hello_request{}, #state{host = Host, port = Port,
renegotiation = {Renegotiation, _}} = State0) ->
Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
- State1 = send_handshake(Hello, State0),
+ {State1, Actions} = send_handshake(Hello, State0),
{Record, State} =
next_record(
State1#state{session = Session0#session{session_id
= Hello#client_hello.session_id}}),
- next_event(hello, Record, State);
-
+ next_event(hello, Record, State, Actions);
connection(internal, #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
@@ -306,21 +425,17 @@ connection(internal, #client_hello{} = Hello, #state{role = server, allow_renego
%% renegotiations immediately after each other.
erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
{next_state, hello, State#state{allow_renegotiate = false}, [{next_event, internal, Hello}]};
-
-
connection(internal, #client_hello{}, #state{role = server, allow_renegotiate = false} = State0) ->
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
State1 = send_alert(Alert, State0),
{Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
next_event(connection, Record, State);
-
connection(Type, Event, State) ->
ssl_connection:connection(Type, Event, State, ?MODULE).
downgrade(Type, Event, State) ->
ssl_connection:downgrade(Type, Event, State, ?MODULE).
-
%%--------------------------------------------------------------------
%% Description: This function is called by a gen_fsm when it receives any
%% other message than a synchronous or asynchronous event
@@ -328,15 +443,15 @@ downgrade(Type, Event, State) ->
%%--------------------------------------------------------------------
%% raw data from socket, unpack records
-handle_info({Protocol, _, Data}, StateName,
+handle_info({Protocol, _, _, _, Data}, StateName,
#state{data_tag = Protocol} = State0) ->
- case next_tls_record(Data, State0) of
+ case next_dtls_record(Data, State0) of
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
- handle_normal_shutdown(Alert, StateName, State0),
+ ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
{stop, {shutdown, own_alert}}
- end;
+ end;
handle_info({CloseTag, Socket}, StateName,
#state{socket = Socket, close_tag = CloseTag,
negotiated_version = Version} = State) ->
@@ -354,7 +469,7 @@ handle_info({CloseTag, Socket}, StateName,
%%invalidate_session(Role, Host, Port, Session)
ok
end,
- handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
{stop, {shutdown, transport_closed}};
handle_info(Msg, StateName, State) ->
ssl_connection:handle_info(Msg, StateName, State).
@@ -362,6 +477,59 @@ handle_info(Msg, StateName, State) ->
handle_call(Event, From, StateName, State) ->
ssl_connection:handle_call(Event, From, StateName, State, ?MODULE).
+handle_common_event(internal, #alert{} = Alert, StateName,
+ #state{negotiated_version = Version} = State) ->
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State);
+%%% DTLS record protocol level handshake messages
+handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE,
+ fragment = Data},
+ StateName,
+ #state{protocol_buffers = Buffers0,
+ negotiated_version = Version} = State0) ->
+ try
+ case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0) of
+ {[], Buffers} ->
+ {Record, State} = next_record(State0#state{protocol_buffers = Buffers}),
+ next_event(StateName, Record, State);
+ {Packets, Buffers} ->
+ State = State0#state{protocol_buffers = Buffers},
+ Events = dtls_handshake_events(Packets),
+ {next_state, StateName,
+ State#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
+ end
+ catch throw:#alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
+ end;
+%%% DTLS record protocol level application data messages
+handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) ->
+ {next_state, StateName, State, [{next_event, internal, {application_data, Data}}]};
+%%% DTLS record protocol level change cipher messages
+handle_common_event(internal, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
+ {next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]};
+%%% DTLS record protocol level Alert messages
+handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
+ #state{negotiated_version = Version} = State) ->
+ case decode_alerts(EncAlerts) of
+ Alerts = [_|_] ->
+ handle_alerts(Alerts, {next_state, StateName, State});
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State)
+ end;
+%% Ignore unknown TLS record level protocol messages
+handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
+ {next_state, StateName, State}.
+
+handle_state_timeout(flight_retransmission_timeout, StateName,
+ #state{flight_state = {retransmit, NextTimeout}} = State0) ->
+ {State1, Actions} = send_handshake_flight(State0#state{flight_state = {retransmit, NextTimeout}},
+ retransmit_epoch(StateName, State0)),
+ {Record, State} = next_record(State1),
+ next_event(StateName, Record, State, Actions).
+
+send(Transport, {_, {{_,_}, _} = Socket}, Data) ->
+ send(Transport, Socket, Data);
+send(Transport, Socket, Data) ->
+ dtls_socket:send(Transport, Socket, Data).
%%--------------------------------------------------------------------
%% 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
@@ -376,7 +544,7 @@ terminate(Reason, StateName, State) ->
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, StateName, State, _Extra) ->
- {?GEN_STATEM_CB_MODE, StateName, State}.
+ {ok, StateName, State}.
format_status(Type, Data) ->
ssl_connection:format_status(Type, Data).
@@ -384,88 +552,60 @@ format_status(Type, Data) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-encode_handshake(Handshake, Version, ConnectionStates0, Hist0) ->
- {Seq, ConnectionStates} = sequence(ConnectionStates0),
- {EncHandshake, Frag} = dtls_handshake:encode_handshake(Handshake, Version, Seq),
- Hist = ssl_handshake:update_handshake_history(Hist0, EncHandshake),
- {Frag, ConnectionStates, Hist}.
+handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
+ #state{connection_states = ConnectionStates0,
+ port = Port, session = #session{own_certificate = Cert} = Session0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb,
+ negotiated_protocol = CurrentProtocol,
+ key_algorithm = KeyExAlg,
+ ssl_options = SslOpts} = State0) ->
+
+ case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+ ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, ClientVersion, hello, State0);
+ {Version, {Type, Session},
+ ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
+ Protocol = case Protocol0 of
+ undefined -> CurrentProtocol;
+ _ -> Protocol0
+ end,
-encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- dtls_record:encode_change_cipher_spec(Version, ConnectionStates).
+ State = prepare_flight(State0#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ client_hello_version = ClientVersion,
+ hashsign_algorithm = HashSign,
+ session = Session,
+ negotiated_protocol = Protocol}),
+
+ ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt},
+ State, ?MODULE)
+ end.
-encode_handshake_flight(Flight, ConnectionStates) ->
- MSS = 1400,
- encode_handshake_records(Flight, ConnectionStates, MSS, init_pack_records()).
+encode_handshake_flight(Flight, Version, MaxFragmentSize, Epoch, ConnectionStates) ->
+ Fragments = lists:map(fun(Handshake) ->
+ dtls_handshake:fragment_handshake(Handshake, MaxFragmentSize)
+ end, Flight),
+ dtls_record:encode_handshake(Fragments, Version, Epoch, ConnectionStates).
-encode_handshake_records([], CS, _MSS, Recs) ->
- {finish_pack_records(Recs), CS};
+encode_change_cipher(#change_cipher_spec{}, Version, Epoch, ConnectionStates) ->
+ dtls_record:encode_change_cipher_spec(Version, Epoch, ConnectionStates).
-encode_handshake_records([{Version, _Epoch, Frag = #change_cipher_spec{}}|Tail], ConnectionStates0, MSS, Recs0) ->
- {Encoded, ConnectionStates} =
- encode_change_cipher(Frag, Version, ConnectionStates0),
- Recs = append_pack_records([Encoded], MSS, Recs0),
- encode_handshake_records(Tail, ConnectionStates, MSS, Recs);
-
-encode_handshake_records([{Version, Epoch, {MsgType, MsgSeq, Bin}}|Tail], CS0, MSS, Recs0 = {Buf0, _}) ->
- Space = MSS - iolist_size(Buf0),
- Len = byte_size(Bin),
- {Encoded, CS} =
- encode_handshake_record(Version, Epoch, Space, MsgType, MsgSeq, Len, Bin, 0, MSS, [], CS0),
- Recs = append_pack_records(Encoded, MSS, Recs0),
- encode_handshake_records(Tail, CS, MSS, Recs).
-
-%% TODO: move to dtls_handshake????
-encode_handshake_record(_Version, _Epoch, _Space, _MsgType, _MsgSeq, _Len, <<>>, _Offset, _MRS, Encoded, CS)
- when length(Encoded) > 0 ->
- %% make sure we encode at least one segment (for empty messages like Server Hello Done
- {lists:reverse(Encoded), CS};
-
-encode_handshake_record(Version, Epoch, Space, MsgType, MsgSeq, Len, Bin,
- Offset, MRS, Encoded0, CS0) ->
- MaxFragmentLen = Space - 25,
- case Bin of
- <<BinFragment:MaxFragmentLen/bytes, Rest/binary>> ->
- ok;
- _ ->
- BinFragment = Bin,
- Rest = <<>>
- end,
- FragLength = byte_size(BinFragment),
- Frag = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(Offset), ?uint24(FragLength), BinFragment],
- %% TODO Real solution, now avoid dialyzer error {Encoded, CS} = ssl_record:encode_handshake({Epoch, Frag}, Version, CS0),
- {Encoded, CS} = ssl_record:encode_handshake(Frag, Version, CS0),
- encode_handshake_record(Version, Epoch, MRS, MsgType, MsgSeq, Len, Rest, Offset + FragLength, MRS, [Encoded|Encoded0], CS).
-
-init_pack_records() ->
- {[], []}.
-
-append_pack_records([], MSS, Recs = {Buf0, Acc0}) ->
- Remaining = MSS - iolist_size(Buf0),
- if Remaining < 12 ->
- {[], [lists:reverse(Buf0)|Acc0]};
- true ->
- Recs
- end;
-append_pack_records([Head|Tail], MSS, {Buf0, Acc0}) ->
- TotLen = iolist_size(Buf0) + iolist_size(Head),
- if TotLen > MSS ->
- append_pack_records(Tail, MSS, {[Head], [lists:reverse(Buf0)|Acc0]});
- true ->
- append_pack_records(Tail, MSS, {[Head|Buf0], Acc0})
- end.
+encode_data(Data, Version, ConnectionStates0)->
+ dtls_record:encode_data(Data, Version, ConnectionStates0).
-finish_pack_records({[], Acc}) ->
- lists:reverse(Acc);
-finish_pack_records({Buf, Acc}) ->
- lists:reverse([lists:reverse(Buf)|Acc]).
+encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
+ dtls_record:encode_alert_record(Alert, Version, ConnectionStates).
-%% decode_alerts(Bin) ->
-%% ssl_alert:decode(Bin).
+decode_alerts(Bin) ->
+ ssl_alert:decode(Bin).
-initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
+initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User,
{CbModule, DataTag, CloseTag, ErrorTag}) ->
#ssl_options{beast_mitigation = BeastMitigation} = SSLOptions,
- ConnectionStates = ssl_record:init_connection_states(Role, BeastMitigation),
+ ConnectionStates = dtls_record:init_connection_states(Role, BeastMitigation),
SessionCacheCb = case application:get_env(ssl, session_cb) of
{ok, Cb} when is_atom(Cb) ->
@@ -497,10 +637,12 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
renegotiation = {false, first},
allow_renegotiate = SSLOptions#ssl_options.client_renegotiation,
start_or_recv_from = undefined,
- protocol_cb = ?MODULE
+ protocol_cb = ?MODULE,
+ flight_buffer = new_flight(),
+ flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}
}.
-next_tls_record(Data, #state{protocol_buffers = #protocol_buffers{
+next_dtls_record(Data, #state{protocol_buffers = #protocol_buffers{
dtls_record_buffer = Buf0,
dtls_cipher_texts = CT0} = Buffers} = State0) ->
case dtls_record:get_dtls_records(Data, Buf0) of
@@ -509,14 +651,15 @@ next_tls_record(Data, #state{protocol_buffers = #protocol_buffers{
next_record(State0#state{protocol_buffers =
Buffers#protocol_buffers{dtls_record_buffer = Buf1,
dtls_cipher_texts = CT1}});
-
#alert{} = Alert ->
Alert
- end.
+ end.
-next_record(#state{%%flight = #flight{state = finished},
- protocol_buffers =
- #protocol_buffers{dtls_packets = [], dtls_cipher_texts = [CT | Rest]}
+next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 ->
+ {no_record, State#state{unprocessed_handshake_events = N-1}};
+
+next_record(#state{protocol_buffers =
+ #protocol_buffers{dtls_cipher_texts = [CT | Rest]}
= Buffers,
connection_states = ConnStates0} = State) ->
case dtls_record:decode_cipher_text(CT, ConnStates0) of
@@ -527,9 +670,15 @@ next_record(#state{%%flight = #flight{state = finished},
#alert{} = Alert ->
{Alert, State}
end;
-next_record(#state{socket = Socket,
- transport_cb = Transport} = State) -> %% when FlightState =/= finished
- ssl_socket:setopts(Transport, Socket, [{active,once}]),
+next_record(#state{role = server,
+ socket = {Listener, {Client, _}},
+ transport_cb = gen_udp} = State) ->
+ dtls_udp_listener:active_once(Listener, Client, self()),
+ {no_record, State};
+next_record(#state{role = client,
+ socket = {_Server, Socket},
+ transport_cb = Transport} = State) ->
+ dtls_socket:setopts(Transport, Socket, [{active,once}]),
{no_record, State};
next_record(State) ->
{no_record, State}.
@@ -548,88 +697,146 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
{Record, State} = next_record(State0),
next_event(StateName, Record, State);
_ ->
- {Record, State} = read_application_data(<<>>, State0),
+ {Record, State} = ssl_connection:read_application_data(<<>>, State0),
next_event(StateName, Record, State)
end.
next_event(StateName, Record, State) ->
next_event(StateName, Record, State, []).
-next_event(connection = StateName, no_record, State0, Actions) ->
+next_event(connection = StateName, no_record,
+ #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
case next_record_if_active(State0) of
{no_record, State} ->
- ssl_connection:hibernate_after(StateName, State, Actions);
- {#ssl_tls{} = Record, State} ->
- {next_state, StateName, State, [{next_event, internal, {dtls_record, Record}} | Actions]};
+ ssl_connection:hibernate_after(StateName, State, Actions);
+ {#ssl_tls{epoch = CurrentEpoch} = Record, State} ->
+ {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
+ {#ssl_tls{epoch = Epoch,
+ type = ?HANDSHAKE,
+ version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
+ {State, MoreActions} = send_handshake_flight(State1, Epoch),
+ {next_state, StateName, State, Actions ++ MoreActions};
+ {#ssl_tls{epoch = _Epoch,
+ version = _Version}, State} ->
+ %% TODO maybe buffer later epoch
+ {next_state, StateName, State, Actions};
{#alert{} = Alert, State} ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end;
-next_event(StateName, Record, State, Actions) ->
+next_event(StateName, Record,
+ #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State, Actions) ->
case Record of
no_record ->
{next_state, StateName, State, Actions};
- #ssl_tls{} = Record ->
- {next_state, StateName, State, [{next_event, internal, {dtls_record, Record}} | Actions]};
+ #ssl_tls{epoch = CurrentEpoch,
+ version = Version} = Record ->
+ {next_state, StateName,
+ dtls_version(StateName, Version, State),
+ [{next_event, internal, {protocol_record, Record}} | Actions]};
+ #ssl_tls{epoch = _Epoch,
+ version = _Version} = _Record ->
+ %% TODO maybe buffer later epoch
+ {next_state, StateName, State, Actions};
#alert{} = Alert ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end.
-read_application_data(_,State) ->
- {#ssl_tls{fragment = <<"place holder">>}, State}.
-
-handle_own_alert(_,_,_, State) -> %% Place holder
- {stop, {shutdown, own_alert}, State}.
-
-handle_normal_shutdown(_, _, _State) -> %% Place holder
- ok.
-
-%% TODO This generates dialyzer warnings, has to be handled differently.
-%% handle_packet(Address, Port, Packet) ->
-%% try dtls_record:get_dtls_records(Packet, <<>>) of
-%% %% expect client hello
-%% {[#ssl_tls{type = ?HANDSHAKE, version = {254, _}} = Record], <<>>} ->
-%% handle_dtls_client_hello(Address, Port, Record);
-%% _Other ->
-%% {error, not_dtls}
-%% catch
-%% _Class:_Error ->
-%% {error, not_dtls}
-%% end.
-
-%% handle_dtls_client_hello(Address, Port,
-%% #ssl_tls{epoch = Epoch, sequence_number = Seq,
-%% version = Version} = Record) ->
-%% {[{Hello, _}], _} =
-%% dtls_handshake:get_dtls_handshake(Record,
-%% dtls_handshake: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
-%% {RequestFragment, _} = dtls_handshake:encode_handshake(
-%% dtls_handshake:hello_verify_request(Cookie),
-%% Version, 0),
-%% HelloVerifyRequest =
-%% dtls_record:encode_tls_cipher_text(?HANDSHAKE, Version, Epoch, Seq, RequestFragment),
-%% {reply, HelloVerifyRequest}
-%% end.
-
-%% 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>>.
-
-sequence(#connection_states{dtls_write_msg_seq = Seq} = CS) ->
- {Seq, CS#connection_states{dtls_write_msg_seq = Seq + 1}}.
+dtls_version(hello, Version, #state{role = server} = State) ->
+ State#state{negotiated_version = Version}; %%Inital version
+dtls_version(_,_, State) ->
+ State.
+
+prepare_flight(#state{flight_buffer = Flight,
+ connection_states = ConnectionStates0,
+ protocol_buffers =
+ #protocol_buffers{} = Buffers} = State) ->
+ ConnectionStates = dtls_record:save_current_connection_state(ConnectionStates0, write),
+ State#state{flight_buffer = next_flight(Flight),
+ connection_states = ConnectionStates,
+ protocol_buffers = Buffers#protocol_buffers{
+ dtls_handshake_next_fragments = [],
+ dtls_handshake_later_fragments = []}}.
+new_flight() ->
+ #{next_sequence => 0,
+ handshakes => [],
+ change_cipher_spec => undefined,
+ handshakes_after_change_cipher_spec => []}.
+
+next_flight(Flight) ->
+ Flight#{handshakes => [],
+ change_cipher_spec => undefined,
+ handshakes_after_change_cipher_spec => []}.
+
+start_flight(#state{transport_cb = gen_udp,
+ flight_state = {retransmit, Timeout}} = State) ->
+ start_retransmision_timer(Timeout, State);
+start_flight(#state{transport_cb = gen_udp,
+ flight_state = connection} = State) ->
+ {State, []};
+start_flight(State) ->
+ %% No retransmision needed i.e DTLS over SCTP
+ {State#state{flight_state = reliable}, []}.
+
+start_retransmision_timer(Timeout, State) ->
+ {State#state{flight_state = {retransmit, new_timeout(Timeout)}},
+ [{state_timeout, Timeout, flight_retransmission_timeout}]}.
+
+new_timeout(N) when N =< 30 ->
+ N * 2;
+new_timeout(_) ->
+ 60.
+
+dtls_handshake_events(Packets) ->
+ lists:map(fun(Packet) ->
+ {next_event, internal, {handshake, Packet}}
+ end, Packets).
+
+renegotiate(#state{role = client} = State, Actions) ->
+ %% Handle same way as if server requested
+ %% the renegotiation
+ Hs0 = ssl_handshake:init_handshake_history(),
+ {next_state, connection, State#state{tls_handshake_history = Hs0,
+ protocol_buffers = #protocol_buffers{}},
+ [{next_event, internal, #hello_request{}} | Actions]};
+
+renegotiate(#state{role = server,
+ connection_states = CS0} = State0, Actions) ->
+ HelloRequest = ssl_handshake:hello_request(),
+ CS = CS0#{write_msg_seq => 0},
+ {State1, MoreActions} = send_handshake(HelloRequest,
+ State0#state{connection_states =
+ CS}),
+ Hs0 = ssl_handshake:init_handshake_history(),
+ {Record, State} = next_record(State1#state{tls_handshake_history = Hs0,
+ protocol_buffers = #protocol_buffers{}}),
+ next_event(hello, Record, State, Actions ++ MoreActions).
+
+handle_alerts([], Result) ->
+ Result;
+handle_alerts(_, {stop,_} = Stop) ->
+ Stop;
+handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
+ handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State));
+handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
+ handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
+
+retransmit_epoch(_StateName, #state{connection_states = ConnectionStates}) ->
+ #{epoch := Epoch} =
+ ssl_record:current_connection_state(ConnectionStates, write),
+ Epoch.
+
+
+update_handshake_history(#hello_verify_request{}, _, Hist) ->
+ Hist;
+update_handshake_history(_, Handshake, Hist) ->
+ %% DTLS never needs option "v2_hello_compatible" to be true
+ ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake), false).
+
+unprocessed_events(Events) ->
+ %% The first handshake event will be processed immediately
+ %% as it is entered first in the event queue and
+ %% when it is processed there will be length(Events)-1
+ %% handshake events left to process before we should
+ %% process more TLS-records received on the socket.
+ erlang:length(Events)-1.
+
diff --git a/lib/ssl/src/dtls_connection.hrl b/lib/ssl/src/dtls_connection.hrl
index ee3daa3c14..3dd78235d0 100644
--- a/lib/ssl/src/dtls_connection.hrl
+++ b/lib/ssl/src/dtls_connection.hrl
@@ -29,20 +29,14 @@
-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_fragment_state, %%:: [], % DTLS fragments
- dtls_handshake_buffer = <<>>, %%:: binary(), % Buffer of incomplete handshakes
- dtls_cipher_texts = [], %%:: [binary()],
- dtls_cipher_texts_next %%:: [binary()] % Received for Epoch not yet active
+ dtls_record_buffer = <<>>, %% Buffer of incomplete records
+ dtls_handshake_next_seq = 0,
+ dtls_flight_last,
+ dtls_handshake_next_fragments = [], %% Fragments of the next handshake message
+ dtls_handshake_later_fragments = [], %% Fragments of handsake messages come after the one in next buffer
+ dtls_cipher_texts = [] %%:: [binary()],
}).
--record(flight, {
- last_retransmit,
- last_read_seq,
- msl_timer,
- state,
- buffer % buffer of not yet ACKed TLS records
- }).
+-define(INITIAL_RETRANSMIT_TIMEOUT, 1000). %1 sec
-endif. % -ifdef(dtls_connection).
diff --git a/lib/ssl/src/dtls_connection_sup.erl b/lib/ssl/src/dtls_connection_sup.erl
index dc7601a684..7d7be5743d 100644
--- a/lib/ssl/src/dtls_connection_sup.erl
+++ b/lib/ssl/src/dtls_connection_sup.erl
@@ -60,7 +60,7 @@ init(_O) ->
StartFunc = {dtls_connection, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [dtls_connection],
+ Modules = [dtls_connection, ssl_connection],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 5a799cf441..a94954d8f2 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,15 +18,15 @@
%% %CopyrightEnd%
-module(dtls_handshake).
+-include("dtls_connection.hrl").
-include("dtls_handshake.hrl").
-include("dtls_record.hrl").
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
--export([client_hello/8, client_hello/9, hello/4,
- hello_verify_request/1, get_dtls_handshake/2,
- dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1,
- encode_handshake/3]).
+-export([client_hello/8, client_hello/9, cookie/4, hello/4,
+ hello_verify_request/2, get_dtls_handshake/3, fragment_handshake/2,
+ handshake_bin/2, encode_handshake/3]).
-type dtls_handshake() :: #client_hello{} | #hello_verify_request{} |
ssl_handshake:ssl_handshake().
@@ -35,7 +35,7 @@
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_number(), #connection_states{},
+-spec client_hello(host(), inet:port_number(), ssl_record:connection_states(),
#ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
#client_hello{}.
%%
@@ -48,7 +48,7 @@ client_hello(Host, Port, ConnectionStates, SslOpts,
Cache, CacheCb, Renegotiation, OwnCert).
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_number(), term(), #connection_states{},
+-spec client_hello(host(), inet:port_number(), term(), ssl_record:connection_states(),
#ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
#client_hello{}.
%%
@@ -61,10 +61,11 @@ client_hello(Host, Port, Cookie, ConnectionStates,
Cache, CacheCb, Renegotiation, OwnCert) ->
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),
+ SecParams = maps:get(security_parameters, Pending),
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
+ CipherSuites = ssl_handshake:available_suites(UserSuites, TLSVersion),
- Extensions = ssl_handshake:client_hello_extensions(Host, dtls_v1:corresponding_tls_version(Version), CipherSuites,
+ Extensions = ssl_handshake:client_hello_extensions(Host, TLSVersion, CipherSuites,
SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -96,72 +97,53 @@ hello(#client_hello{client_version = ClientVersion} = Hello,
#ssl_options{versions = Versions} = SslOpts,
Info, Renegotiation) ->
Version = ssl_handshake:select_version(dtls_record, ClientVersion, Versions),
- %%
- %% TODO: handle Cipher Fallback
- %%
handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation).
--spec hello_verify_request(binary()) -> #hello_verify_request{}.
+cookie(Key, Address, Port, #client_hello{client_version = {Major, Minor},
+ random = Random,
+ session_id = SessionId,
+ cipher_suites = CipherSuites,
+ compression_methods = CompressionMethods}) ->
+ CookieData = [address_to_bin(Address, Port),
+ <<?BYTE(Major), ?BYTE(Minor)>>,
+ Random, SessionId, CipherSuites, CompressionMethods],
+ crypto:hmac(sha, Key, CookieData).
+
+-spec hello_verify_request(binary(), dtls_record:dtls_version()) -> #hello_verify_request{}.
%%
%% Description: Creates a hello verify request message sent by server to
%% verify client
%%--------------------------------------------------------------------
-hello_verify_request(Cookie) ->
- %% TODO: DTLS Versions?????
- #hello_verify_request{protocol_version = {254, 255}, cookie = Cookie}.
+hello_verify_request(Cookie, Version) ->
+ #hello_verify_request{protocol_version = Version, cookie = Cookie}.
%%--------------------------------------------------------------------
-%% %%--------------------------------------------------------------------
-encode_handshake(Handshake, Version, MsgSeq) ->
+encode_handshake(Handshake, Version, Seq) ->
{MsgType, Bin} = enc_handshake(Handshake, Version),
Len = byte_size(Bin),
- Enc = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin],
- Frag = {MsgType, MsgSeq, Bin},
- {Enc, Frag}.
+ [MsgType, ?uint24(Len), ?uint16(Seq), ?uint24(0), ?uint24(Len), Bin].
-%%--------------------------------------------------------------------
--spec get_dtls_handshake(#ssl_tls{}, #dtls_hs_state{} | undefined) ->
- {[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(Records, undefined) ->
- HsState = #dtls_hs_state{highest_record_seq = 0,
- starting_read_seq = 0,
- fragments = gb_trees:empty(),
- completed = []},
- get_dtls_handshake(Records, HsState);
-get_dtls_handshake(Records, HsState0) when is_list(Records) ->
- HsState1 = lists:foldr(fun get_dtls_handshake_aux/2, HsState0, Records),
- get_dtls_handshake_completed(HsState1);
-get_dtls_handshake(Record, HsState0) when is_record(Record, ssl_tls) ->
- HsState1 = get_dtls_handshake_aux(Record, HsState0),
- get_dtls_handshake_completed(HsState1).
+fragment_handshake(Bin, _) when is_binary(Bin)->
+ %% This is the change_cipher_spec not a "real handshake" but part of the flight
+ Bin;
+fragment_handshake([MsgType, Len, Seq, _, Len, Bin], Size) ->
+ Bins = bin_fragments(Bin, Size),
+ handshake_fragments(MsgType, Seq, Len, Bins, []).
+handshake_bin([Type, Length, Data], Seq) ->
+ handshake_bin(Type, Length, Seq, Data).
+
%%--------------------------------------------------------------------
--spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}.
+-spec get_dtls_handshake(dtls_record:dtls_version(), binary(), #protocol_buffers{}) ->
+ {[dtls_handshake()], #protocol_buffers{}}.
%%
-%% Description: Reset the DTLS decoder state for a new Epoch
+%% Description: Given buffered and new data from dtls_record, collects
+%% and returns it as a list of handshake messages, also returns
+%% possible leftover data in the new "protocol_buffers".
%%--------------------------------------------------------------------
-%% 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 = []}.
+get_dtls_handshake(Version, Fragment, ProtocolBuffers) ->
+ handle_fragments(Version, Fragment, ProtocolBuffers, []).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -170,27 +152,29 @@ handle_client_hello(Version, #client_hello{session_id = SugesstedId,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions = #hello_extensions{elliptic_curves = Curves,
- signature_algs = ClientHashSigns} = HelloExt},
+ extensions =
+ #hello_extensions{elliptic_curves = Curves,
+ signature_algs = ClientHashSigns} = HelloExt},
#ssl_options{versions = Versions,
signature_algs = SupportedHashSigns} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, _}, Renegotiation) ->
case dtls_record:is_acceptable_version(Version, Versions) of
true ->
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
AvailableHashSigns = ssl_handshake:available_signature_algs(
- ClientHashSigns, SupportedHashSigns, Cert,
- dtls_v1:corresponding_tls_version(Version)),
- ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(Version)),
+ ClientHashSigns, SupportedHashSigns, Cert,TLSVersion),
+ ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(TLSVersion)),
{Type, #session{cipher_suite = CipherSuite} = Session1}
= ssl_handshake:select_session(SugesstedId, CipherSuites, AvailableHashSigns, Compressions,
- Port, Session0#session{ecc = ECCCurve}, Version,
+ Port, Session0#session{ecc = ECCCurve}, TLSVersion,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
{KeyExAlg,_,_,_} = ssl_cipher:suite_definition(CipherSuite),
- case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg, SupportedHashSigns, Version) of
+ case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg,
+ SupportedHashSigns, TLSVersion) of
#alert{} = Alert ->
Alert;
HashSign ->
@@ -228,214 +212,15 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
end.
-get_dtls_handshake_completed(HsState = #dtls_hs_state{completed = Completed}) ->
- {lists:reverse(Completed), HsState#dtls_hs_state{completed = []}}.
-
-get_dtls_handshake_aux(#ssl_tls{version = Version,
- 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) ->
- case reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState0) of
- {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) ->
- HsState.
-
-dec_dtls_fragment(Version, SeqNo, Type, Length, MessageSeq, MsgBody,
- 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}) ->
- 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.
-
-dtls_hs_state_process_seq(HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
- Fragments1 = gb_trees:delete_any(CurrentReadSeq, Fragments0),
- HsState0#dtls_hs_state{current_read_seq = CurrentReadSeq + 1,
- 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})
- when Type == ?CLIENT_HELLO;
- Type == ?SERVER_HELLO;
- Type == ?HELLO_VERIFY_REQUEST ->
- %% First message, should be client hello
- %% return the current message and set the next expected Sequence
- %%
- %% Note: this could (should?) be restricted further, ClientHello and
- %% HelloVerifyRequest have to have message_seq = 0, ServerHello
- %% can have a message_seq of 0 or 1
- %%
- {HsState0#dtls_hs_state{current_read_seq = MessageSeq + 1}, SeqNo, Body};
-
-reassemble_dtls_fragment(_SeqNo, _Type, Length, _MessageSeq, _, Length,
- _Body, HsState = #dtls_hs_state{current_read_seq = undefined}) ->
- %% not what we expected, drop it
- HsState;
-
-reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- 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
- %%
- %% Note: this could (should?) be restricted further, the first message of a
- %% new flight has to have message_seq = 0
- %%
- HsState = dtls_hs_state_process_seq(HsState0),
- {HsState, SeqNo, Body};
-
-reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length,
- _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}) ->
- %% 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) ->
- %% 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_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})
- 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})
- when MessageSeq < CurrentReadSeq ->
- HsState;
-
-reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- 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)
- end.
-dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- 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),
- 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}) ->
- FragBuffer1 = dtls_fragment_add(FragBuffer0, FragmentOffset, FragmentLength, Body),
- Fragment = {erlang:max(SeqNo, LastSeqNo), Type, Length, MessageSeq, FragBuffer1},
- Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
- HsState#dtls_hs_state{fragments = Fragments1};
-
-%% 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}) ->
- Fragments1 = gb_trees:delete_any(MessageSeq, Fragments0),
- HsState#dtls_hs_state{fragments = Fragments1}.
-
-dtls_fragment_add({Length, FragmentList0, Bin0}, FragmentOffset, FragmentLength, Body) ->
- Bin1 = dtls_fragment_bin_add(FragmentOffset, FragmentLength, Body, Bin0),
- FragmentList1 = add_fragment(FragmentList0, {FragmentOffset, FragmentLength}),
- {Length, FragmentList1, Bin1}.
-
-dtls_fragment_init(Length, 0, Length, Body) ->
- {Length, [{0, Length}], Body};
-dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body) ->
- Bin = dtls_fragment_bin_add(FragmentOffset, FragmentLength, Body, <<0:(Length*8)>>),
- {Length, [{FragmentOffset, FragmentOffset + FragmentLength}], Bin}.
-
-dtls_fragment_bin_add(FragmentOffset, FragmentLength, Add, Buffer) ->
- <<First:FragmentOffset/bytes, _:FragmentLength/bytes, Rest/binary>> = Buffer,
- <<First/binary, Add/binary, Rest/binary>>.
-
-merge_fragment_list([], Fragment, Acc) ->
- lists:reverse([Fragment|Acc]);
-
-merge_fragment_list([H = {_, HEnd}|Rest], Frag = {FStart, _}, Acc)
- when FStart > HEnd ->
- merge_fragment_list(Rest, Frag, [H|Acc]);
-
-merge_fragment_list(Rest = [{HStart, _HEnd}|_], Frag = {_FStart, FEnd}, Acc)
- when FEnd < HStart ->
- lists:reverse(Acc) ++ [Frag|Rest];
-
-merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)
- when
- FStart =< HEnd orelse FEnd >= HStart ->
- Start = erlang:min(HStart, FStart),
- End = erlang:max(HEnd, FEnd),
- NewFrag = {Start, End},
- merge_fragment_list(Rest, NewFrag, Acc).
-
-add_fragment(List, {FragmentOffset, FragmentLength}) ->
- merge_fragment_list(List, {FragmentOffset, FragmentOffset + FragmentLength}, []).
+%%%%%%% Encodeing %%%%%%%%%%%%%
enc_handshake(#hello_verify_request{protocol_version = {Major, Minor},
cookie = Cookie}, _Version) ->
- CookieLength = byte_size(Cookie),
+ CookieLength = byte_size(Cookie),
{?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
?BYTE(CookieLength),
- Cookie/binary>>};
+ Cookie:CookieLength/binary>>};
enc_handshake(#hello_request{}, _Version) ->
{?HELLO_REQUEST, <<>>};
@@ -445,58 +230,258 @@ enc_handshake(#client_hello{client_version = {Major, Minor},
cookie = Cookie,
cipher_suites = CipherSuites,
compression_methods = CompMethods,
- extensions = HelloExtensions}, Version) ->
+ extensions = HelloExtensions}, _Version) ->
SIDLength = byte_size(SessionID),
- BinCookie = enc_client_hello_cookie(Version, Cookie),
+ CookieLength = byte_size(Cookie),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
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,
+ ?BYTE(CookieLength), Cookie/binary,
?UINT16(CsLength), BinCipherSuites/binary,
?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
+
+enc_handshake(#server_hello{} = HandshakeMsg, Version) ->
+ {Type, <<?BYTE(Major), ?BYTE(Minor), Rest/binary>>} =
+ ssl_handshake:encode_handshake(HandshakeMsg, Version),
+ {DTLSMajor, DTLSMinor} = dtls_v1:corresponding_dtls_version({Major, Minor}),
+ {Type, <<?BYTE(DTLSMajor), ?BYTE(DTLSMinor), Rest/binary>>};
+
enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
-enc_client_hello_cookie(_, <<>>) ->
- <<>>;
-enc_client_hello_cookie(_, Cookie) ->
- CookieLength = byte_size(Cookie),
- <<?BYTE(CookieLength), Cookie/binary>>.
+bin_fragments(Bin, Size) ->
+ bin_fragments(Bin, size(Bin), Size, 0, []).
-decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+bin_fragments(Bin, BinSize, FragSize, Offset, Fragments) ->
+ case (BinSize - Offset - FragSize) > 0 of
+ true ->
+ Frag = binary:part(Bin, {Offset, FragSize}),
+ bin_fragments(Bin, BinSize, FragSize, Offset + FragSize, [{Frag, Offset} | Fragments]);
+ false ->
+ Frag = binary:part(Bin, {Offset, BinSize-Offset}),
+ lists:reverse([{Frag, Offset} | Fragments])
+ end.
+
+handshake_fragments(_, _, _, [], Acc) ->
+ lists:reverse(Acc);
+handshake_fragments(MsgType, Seq, Len, [{Bin, Offset} | Bins], Acc) ->
+ FragLen = size(Bin),
+ handshake_fragments(MsgType, Seq, Len, Bins,
+ [<<?BYTE(MsgType), Len/binary, Seq/binary, ?UINT24(Offset),
+ ?UINT24(FragLen), Bin/binary>> | Acc]).
+
+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>>.
+
+%%%%%%% Decodeing %%%%%%%%%%%%%
+
+handle_fragments(Version, FragmentData, Buffers0, Acc) ->
+ Fragments = decode_handshake_fragments(FragmentData),
+ do_handle_fragments(Version, Fragments, Buffers0, Acc).
+
+do_handle_fragments(_, [], Buffers, Acc) ->
+ {lists:reverse(Acc), Buffers};
+do_handle_fragments(Version, [Fragment | Fragments], Buffers0, Acc) ->
+ case reassemble(Version, Fragment, Buffers0) of
+ {more_data, Buffers} when Fragments == [] ->
+ {lists:reverse(Acc), Buffers};
+ {more_data, Buffers} ->
+ do_handle_fragments(Version, Fragments, Buffers, Acc);
+ {HsPacket, Buffers} ->
+ do_handle_fragments(Version, Fragments, Buffers, [HsPacket | Acc])
+ end.
+
+decode_handshake(Version, <<?BYTE(Type), Bin/binary>>) ->
+ decode_handshake(Version, Type, Bin).
+
+decode_handshake(_, ?HELLO_REQUEST, <<>>) ->
+ #hello_request{};
+decode_handshake(_Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
+ ?UINT24(_), ?UINT24(_),
+ ?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
- ?BYTE(Cookie_length), Cookie:Cookie_length/binary,
+ ?BYTE(CookieLength), Cookie:CookieLength/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),
-
+ DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
+
#client_hello{
client_version = {Major,Minor},
random = Random,
- session_id = Session_ID,
cookie = Cookie,
+ session_id = Session_ID,
cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
compression_methods = Comp_methods,
extensions = DecodedExtensions
- };
+ };
+
+decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?UINT24(_), ?UINT16(_),
+ ?UINT24(_), ?UINT24(_),
+ ?BYTE(Major), ?BYTE(Minor),
+ ?BYTE(CookieLength),
+ Cookie:CookieLength/binary>>) ->
+ #hello_verify_request{protocol_version = {Major, Minor},
+ cookie = Cookie};
+
+decode_handshake(Version, Tag, <<?UINT24(_), ?UINT16(_),
+ ?UINT24(_), ?UINT24(_), Msg/binary>>) ->
+ %% DTLS specifics stripped
+ decode_tls_thandshake(Version, Tag, Msg).
+
+decode_tls_thandshake(Version, Tag, Msg) ->
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
+ ssl_handshake:decode_handshake(TLSVersion, Tag, Msg).
+
+decode_handshake_fragments(<<>>) ->
+ [<<>>];
+decode_handshake_fragments(<<?BYTE(Type), ?UINT24(Length),
+ ?UINT16(MessageSeq),
+ ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
+ Fragment:FragmentLength/binary, Rest/binary>>) ->
+ [#handshake_fragment{type = Type,
+ length = Length,
+ message_seq = MessageSeq,
+ fragment_offset = FragmentOffset,
+ fragment_length = FragmentLength,
+ fragment = Fragment} | decode_handshake_fragments(Rest)].
+
+reassemble(Version, #handshake_fragment{message_seq = Seq} = Fragment,
+ #protocol_buffers{dtls_handshake_next_seq = Seq,
+ dtls_handshake_next_fragments = Fragments0,
+ dtls_handshake_later_fragments = LaterFragments0} =
+ Buffers0)->
+ case reassemble_fragments(Fragment, Fragments0) of
+ {more_data, Fragments} ->
+ {more_data, Buffers0#protocol_buffers{dtls_handshake_next_fragments = Fragments}};
+ {raw, RawHandshake} ->
+ Handshake = decode_handshake(Version, RawHandshake),
+ {NextFragments, LaterFragments} = next_fragments(LaterFragments0),
+ {{Handshake, RawHandshake}, Buffers0#protocol_buffers{dtls_handshake_next_seq = Seq + 1,
+ dtls_handshake_next_fragments = NextFragments,
+ dtls_handshake_later_fragments = LaterFragments}}
+ end;
+reassemble(_, #handshake_fragment{message_seq = FragSeq} = Fragment,
+ #protocol_buffers{dtls_handshake_next_seq = Seq,
+ dtls_handshake_later_fragments = LaterFragments} = Buffers0) when FragSeq > Seq->
+ {more_data,
+ Buffers0#protocol_buffers{dtls_handshake_later_fragments = [Fragment | LaterFragments]}};
+reassemble(_, _, Buffers) ->
+ %% Disregard fragments FragSeq < Seq
+ {more_data, Buffers}.
+
+reassemble_fragments(Current, Fragments0) ->
+ [Frag1 | Frags] = lists:keysort(#handshake_fragment.fragment_offset, [Current | Fragments0]),
+ [Fragment | _] = Fragments = merge_fragment(Frag1, Frags),
+ case is_complete_handshake(Fragment) of
+ true ->
+ {raw, handshake_bin(Fragment)};
+ false ->
+ {more_data, Fragments}
+ end.
-decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
- ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->
+merge_fragment(Frag0, []) ->
+ [Frag0];
+merge_fragment(Frag0, [Frag1 | Rest]) ->
+ case merge_fragments(Frag0, Frag1) of
+ [_|_] = Frags ->
+ Frags ++ Rest;
+ Frag ->
+ merge_fragment(Frag, Rest)
+ end.
- #hello_verify_request{
- protocol_version = {Major,Minor},
- cookie = Cookie};
-decode_handshake(Version, Tag, Msg) ->
- ssl_handshake:decode_handshake(Version, Tag, Msg).
+is_complete_handshake(#handshake_fragment{length = Length, fragment_length = Length}) ->
+ true;
+is_complete_handshake(_) ->
+ false.
+
+next_fragments(LaterFragments) ->
+ case lists:keysort(#handshake_fragment.message_seq, LaterFragments) of
+ [] ->
+ {[], []};
+ [#handshake_fragment{message_seq = Seq} | _] = Fragments ->
+ split_frags(Fragments, Seq, [])
+ end.
-%% 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>>.
+split_frags([#handshake_fragment{message_seq = Seq} = Frag | Rest], Seq, Acc) ->
+ split_frags(Rest, Seq, [Frag | Acc]);
+split_frags(Frags, _, Acc) ->
+ {lists:reverse(Acc), Frags}.
+
+
+%% Duplicate
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData}) ->
+ Previous;
+
+%% Lager fragment save new data
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = CurrentLen,
+ fragment = CurrentData}) when CurrentLen > PreviousLen ->
+ NewLength = CurrentLen - PreviousLen,
+ <<_:PreviousLen/binary, NewData/binary>> = CurrentData,
+ Previous#handshake_fragment{
+ fragment_length = PreviousLen + NewLength,
+ fragment = <<PreviousData/binary, NewData/binary>>
+ };
+
+%% Smaller fragment
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = CurrentLen}) when CurrentLen < PreviousLen ->
+ Previous;
+%% Next fragment
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = CurrentOffSet,
+ fragment_length = CurrentLen,
+ fragment = CurrentData}) when PreviousOffSet + PreviousLen == CurrentOffSet->
+ Previous#handshake_fragment{
+ fragment_length = PreviousLen + CurrentLen,
+ fragment = <<PreviousData/binary, CurrentData/binary>>};
+%% No merge there is a gap
+merge_fragments(Previous, Current) ->
+ [Previous, Current].
+
+handshake_bin(#handshake_fragment{
+ type = Type,
+ length = Len,
+ message_seq = Seq,
+ fragment_length = Len,
+ fragment_offset = 0,
+ fragment = Fragment}) ->
+ handshake_bin(Type, Len, Seq, Fragment).
+
+handshake_bin(Type, Length, Seq, FragmentData) ->
+ <<?BYTE(Type), ?UINT24(Length),
+ ?UINT16(Seq), ?UINT24(0), ?UINT24(Length),
+ FragmentData:Length/binary>>.
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
index 0298fd3105..0a980c5f31 100644
--- a/lib/ssl/src/dtls_handshake.hrl
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -46,12 +46,13 @@
cookie
}).
--record(dtls_hs_state,
- {current_read_seq,
- starting_read_seq,
- highest_record_seq,
- fragments,
- completed
- }).
+-record(handshake_fragment, {
+ type,
+ length,
+ message_seq,
+ fragment_offset,
+ fragment_length,
+ fragment
+ }).
-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index 5387fcafa8..f447897d59 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,13 +30,15 @@
-include("ssl_cipher.hrl").
%% Handling of incoming data
--export([get_dtls_records/2]).
+-export([get_dtls_records/2, init_connection_states/2]).
%% Decoding
-export([decode_cipher_text/2]).
%% Encoding
--export([encode_plain_text/4, encode_tls_cipher_text/5, encode_change_cipher_spec/2]).
+-export([encode_handshake/4, encode_alert_record/3,
+ encode_change_cipher_spec/3, encode_data/3]).
+-export([encode_plain_text/5]).
%% Protocol version handling
-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
@@ -44,9 +46,9 @@
is_higher/2, supported_protocol_versions/0,
is_acceptable_version/2]).
-%% DTLS Epoch handling
--export([init_connection_state_seq/2, current_connection_state_epoch/2,
- set_connection_state_by_epoch/3, connection_state_by_epoch/3]).
+-export([save_current_connection_state/2, next_epoch/2]).
+
+-export([init_connection_state_seq/2, current_connection_state_epoch/2]).
-export_type([dtls_version/0, dtls_atom_version/0]).
@@ -58,6 +60,73 @@
%%====================================================================
%% Internal application API
%%====================================================================
+%%--------------------------------------------------------------------
+-spec init_connection_states(client | server, one_n_minus_one | zero_n | disabled) ->
+ ssl_record:connection_states().
+%% %
+ %
+%% Description: Creates a connection_states record with appropriate
+%% values for the initial SSL connection setup.
+%%--------------------------------------------------------------------
+init_connection_states(Role, BeastMitigation) ->
+ ConnectionEnd = ssl_record:record_protocol_role(Role),
+ Initial = initial_connection_state(ConnectionEnd, BeastMitigation),
+ Current = Initial#{epoch := 0},
+ InitialPending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
+ Pending = InitialPending#{epoch => undefined},
+ #{saved_read => Current,
+ current_read => Current,
+ pending_read => Pending,
+ saved_write => Current,
+ current_write => Current,
+ pending_write => Pending}.
+
+%%--------------------------------------------------------------------
+-spec save_current_connection_state(ssl_record:connection_states(), read | write) ->
+ ssl_record:connection_states().
+%%
+%% Description: Returns the instance of the connection_state map
+%% where the current read|write state has been copied to the save state.
+%%--------------------------------------------------------------------
+save_current_connection_state(#{current_read := Current} = States, read) ->
+ States#{saved_read := Current};
+
+save_current_connection_state(#{current_write := Current} = States, write) ->
+ States#{saved_write := Current}.
+
+next_epoch(#{pending_read := Pending,
+ current_read := #{epoch := Epoch}} = States, read) ->
+ States#{pending_read := Pending#{epoch := Epoch + 1}};
+
+next_epoch(#{pending_write := Pending,
+ current_write := #{epoch := Epoch}} = States, write) ->
+ States#{pending_write := Pending#{epoch := Epoch + 1}}.
+
+get_connection_state_by_epoch(Epoch, #{current_write := #{epoch := Epoch} = Current},
+ write) ->
+ Current;
+get_connection_state_by_epoch(Epoch, #{saved_write := #{epoch := Epoch} = Saved},
+ write) ->
+ Saved;
+get_connection_state_by_epoch(Epoch, #{current_read := #{epoch := Epoch} = Current},
+ read) ->
+ Current;
+get_connection_state_by_epoch(Epoch, #{saved_read := #{epoch := Epoch} = Saved},
+ read) ->
+ Saved.
+
+set_connection_state_by_epoch(WriteState, Epoch, #{current_write := #{epoch := Epoch}} = States,
+ write) ->
+ States#{current_write := WriteState};
+set_connection_state_by_epoch(WriteState, Epoch, #{saved_write := #{epoch := Epoch}} = States,
+ write) ->
+ States#{saved_write := WriteState};
+set_connection_state_by_epoch(ReadState, Epoch, #{current_read := #{epoch := Epoch}} = States,
+ read) ->
+ States#{current_read := ReadState};
+set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch}} = States,
+ read) ->
+ States#{saved_read := ReadState}.
%%--------------------------------------------------------------------
-spec get_dtls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}.
@@ -121,103 +190,57 @@ get_dtls_records_aux(Data, Acc) ->
?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
end.
-encode_plain_text(Type, Version, Data,
- #connection_states{current_write =
- #connection_state{
- epoch = Epoch,
- sequence_number = Seq,
- compression_state=CompS0,
- security_parameters=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm=CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#connection_state{compression_state = CompS1},
- AAD = calc_aad(Type, Version, Epoch, Seq),
- {CipherFragment, WriteState} = ssl_record:cipher_aead(dtls_v1:corresponding_tls_version(Version),
- Comp, WriteState1, AAD),
- CipherText = encode_tls_cipher_text(Type, Version, Epoch, Seq, CipherFragment),
- {CipherText, ConnectionStates#connection_states{current_write =
- WriteState#connection_state{sequence_number = Seq +1}}};
-
-encode_plain_text(Type, Version, Data,
- #connection_states{current_write=#connection_state{
- epoch = Epoch,
- sequence_number = Seq,
- compression_state=CompS0,
- security_parameters=
- #security_parameters{compression_algorithm=CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {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(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}}}.
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), dtls_version(), integer(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version, Epoch, ConnectionStates) ->
+ encode_plain_text(?HANDSHAKE, Version, Epoch, Frag, ConnectionStates).
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- epoch = Epoch,
- sequence_number = Seq,
- fragment = CipherFragment} = CipherText,
- #connection_states{current_read =
- #connection_state{
- compression_state = CompressionS0,
- security_parameters=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm=CompAlg}
- } = ReadState0}= ConnnectionStates0) ->
- AAD = calc_aad(Type, Version, Epoch, Seq),
- case ssl_record:decipher_aead(dtls_v1:corresponding_tls_version(Version),
- CipherFragment, ReadState0, AAD) of
- {PlainFragment, ReadState1} ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#connection_states{
- current_read = ReadState1#connection_state{
- compression_state = CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- #alert{} = Alert ->
- Alert
- end;
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- epoch = Epoch,
- sequence_number = Seq,
- fragment = CipherFragment} = CipherText,
- #connection_states{current_read =
- #connection_state{
- compression_state = CompressionS0,
- security_parameters=
- #security_parameters{
- compression_algorithm=CompAlg}
- } = ReadState0}= ConnnectionStates0) ->
- {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
- CipherFragment, ReadState0, true),
- 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(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#connection_states{
- current_read = ReadState1#connection_state{
- compression_state = CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end.
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, dtls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ Version, ConnectionStates) ->
+ #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
+ encode_plain_text(?ALERT, Version, Epoch, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_change_cipher_spec(dtls_version(), #connection_states{}) ->
- {iolist(), #connection_states{}}.
+-spec encode_change_cipher_spec(dtls_version(), integer(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record: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).
+encode_change_cipher_spec(Version, Epoch, ConnectionStates) ->
+ encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
+
+%%--------------------------------------------------------------------
+-spec encode_data(binary(), dtls_version(), ssl_record:connection_states()) ->
+ {iolist(),ssl_record:connection_states()}.
+%%
+%% Description: Encodes data to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_data(Data, Version, ConnectionStates) ->
+ #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
+ encode_plain_text(?APPLICATION_DATA, Version, Epoch, Data, ConnectionStates).
+
+encode_plain_text(Type, Version, Epoch, Data, ConnectionStates) ->
+ Write0 = get_connection_state_by_epoch(Epoch, ConnectionStates, write),
+ {CipherFragment, Write1} = encode_plain_text(Type, Version, Data, Write0),
+ {CipherText, Write} = encode_dtls_cipher_text(Type, Version, CipherFragment, Write1),
+ {CipherText, set_connection_state_by_epoch(Write, Epoch, ConnectionStates, write)}.
+
+
+decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) ->
+ ReadState = get_connection_state_by_epoch(Epoch, ConnnectionStates0, read),
+ decode_cipher_text(CipherText, ReadState, ConnnectionStates0).
%%--------------------------------------------------------------------
-spec protocol_version(dtls_atom_version() | dtls_version()) ->
@@ -352,92 +375,49 @@ is_acceptable_version(Version, Versions) ->
%%--------------------------------------------------------------------
--spec init_connection_state_seq(dtls_version(), #connection_states{}) ->
- #connection_state{}.
+-spec init_connection_state_seq(dtls_version(), ssl_record:connection_states()) ->
+ ssl_record:connection_state().
%%
%% Description: Copy the read sequence number to the write sequence number
%% This is only valid for DTLS in the first client_hello
%%--------------------------------------------------------------------
init_connection_state_seq({254, _},
- #connection_states{
- current_read = Read = #connection_state{epoch = 0},
- current_write = Write = #connection_state{epoch = 0}} = CS0) ->
- CS0#connection_states{current_write =
- Write#connection_state{
- sequence_number = Read#connection_state.sequence_number}};
-init_connection_state_seq(_, CS) ->
- CS.
+ #{current_read := #{epoch := 0, sequence_number := Seq},
+ current_write := #{epoch := 0} = Write} = ConnnectionStates0) ->
+ ConnnectionStates0#{current_write => Write#{sequence_number => Seq}};
+init_connection_state_seq(_, ConnnectionStates) ->
+ ConnnectionStates.
%%--------------------------------------------------------
--spec current_connection_state_epoch(#connection_states{}, read | write) ->
+-spec current_connection_state_epoch(ssl_record:connection_states(), read | write) ->
integer().
%%
%% Description: Returns the epoch the connection_state record
%% that is currently defined as the current conection state.
%%--------------------------------------------------------------------
-current_connection_state_epoch(#connection_states{current_read = Current},
+current_connection_state_epoch(#{current_read := #{epoch := Epoch}},
read) ->
- Current#connection_state.epoch;
-current_connection_state_epoch(#connection_states{current_write = Current},
+ Epoch;
+current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
write) ->
- Current#connection_state.epoch.
-
-%%--------------------------------------------------------------------
-
--spec connection_state_by_epoch(#connection_states{}, integer(), read | write) ->
- #connection_state{}.
-%%
-%% Description: Returns the instance of the connection_state record
-%% that is defined by the Epoch.
-%%--------------------------------------------------------------------
-connection_state_by_epoch(#connection_states{current_read = CS}, Epoch, read)
- when CS#connection_state.epoch == Epoch ->
- CS;
-connection_state_by_epoch(#connection_states{pending_read = CS}, Epoch, read)
- when CS#connection_state.epoch == Epoch ->
- CS;
-connection_state_by_epoch(#connection_states{current_write = CS}, Epoch, write)
- when CS#connection_state.epoch == Epoch ->
- CS;
-connection_state_by_epoch(#connection_states{pending_write = CS}, Epoch, write)
- when CS#connection_state.epoch == Epoch ->
- CS.
-%%--------------------------------------------------------------------
--spec set_connection_state_by_epoch(#connection_states{},
- #connection_state{}, read | write)
- -> #connection_states{}.
-%%
-%% Description: Returns the instance of the connection_state record
-%% that is defined by the Epoch.
-%%--------------------------------------------------------------------
-set_connection_state_by_epoch(ConnectionStates0 =
- #connection_states{current_read = CS},
- NewCS = #connection_state{epoch = Epoch}, read)
- when CS#connection_state.epoch == Epoch ->
- ConnectionStates0#connection_states{current_read = NewCS};
-
-set_connection_state_by_epoch(ConnectionStates0 =
- #connection_states{pending_read = CS},
- NewCS = #connection_state{epoch = Epoch}, read)
- when CS#connection_state.epoch == Epoch ->
- ConnectionStates0#connection_states{pending_read = NewCS};
-
-set_connection_state_by_epoch(ConnectionStates0 =
- #connection_states{current_write = CS},
- NewCS = #connection_state{epoch = Epoch}, write)
- when CS#connection_state.epoch == Epoch ->
- ConnectionStates0#connection_states{current_write = NewCS};
-
-set_connection_state_by_epoch(ConnectionStates0 =
- #connection_states{pending_write = CS},
- NewCS = #connection_state{epoch = Epoch}, write)
- when CS#connection_state.epoch == Epoch ->
- ConnectionStates0#connection_states{pending_write = NewCS}.
+ Epoch.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-
+initial_connection_state(ConnectionEnd, BeastMitigation) ->
+ #{security_parameters =>
+ ssl_record:initial_security_params(ConnectionEnd),
+ epoch => undefined,
+ sequence_number => 0,
+ beast_mitigation => BeastMitigation,
+ compression_state => undefined,
+ cipher_state => undefined,
+ mac_secret => undefined,
+ secure_renegotiation => undefined,
+ client_verify_data => undefined,
+ server_verify_data => undefined
+ }.
lowest_list_protocol_version(Ver, []) ->
Ver;
@@ -449,14 +429,85 @@ highest_list_protocol_version(Ver, []) ->
highest_list_protocol_version(Ver1, [Ver2 | Rest]) ->
highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
-encode_tls_cipher_text(Type, {MajVer, MinVer}, Epoch, Seq, Fragment) ->
+encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment,
+ #{epoch := Epoch, sequence_number := Seq} = WriteState) ->
Length = erlang:iolist_size(Fragment),
- [<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch),
- ?UINT48(Seq), ?UINT16(Length)>>, Fragment].
+ {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch),
+ ?UINT48(Seq), ?UINT16(Length)>>, Fragment],
+ WriteState#{sequence_number => Seq + 1}}.
+
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ epoch := Epoch,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}
+ } = WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ AAD = calc_aad(Type, Version, Epoch, Seq),
+ ssl_record:cipher_aead(dtls_v1:corresponding_tls_version(Version), Comp, WriteState1, AAD);
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ epoch := Epoch,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}
+ }= WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ MacHash = calc_mac_hash(Type, Version, WriteState1, Epoch, Seq, Comp),
+ ssl_record:cipher(dtls_v1:corresponding_tls_version(Version), Comp, WriteState1, MacHash).
+
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ epoch = Epoch,
+ sequence_number = Seq,
+ fragment = CipherFragment} = CipherText,
+ #{compression_state := CompressionS0,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}} = ReadState0,
+ ConnnectionStates0) ->
+ AAD = calc_aad(Type, Version, Epoch, Seq),
+ case ssl_record:decipher_aead(dtls_v1:corresponding_tls_version(Version),
+ CipherFragment, ReadState0, AAD) of
+ {PlainFragment, ReadState1} ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+ ReadState = ReadState1#{compression_state => CompressionS1},
+ ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ #alert{} = Alert ->
+ Alert
+ end;
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ epoch = Epoch,
+ sequence_number = Seq,
+ fragment = CipherFragment} = CipherText,
+ #{compression_state := CompressionS0,
+ security_parameters :=
+ #security_parameters{
+ compression_algorithm = CompAlg}} = ReadState0,
+ ConnnectionStates0) ->
+ {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
+ CipherFragment, ReadState0, true),
+ MacHash = calc_mac_hash(Type, Version, ReadState1, Epoch, Seq, PlainFragment),
+ case ssl_record:is_correct_mac(Mac, MacHash) of
+ true ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+
+ ReadState = ReadState1#{compression_state => CompressionS1},
+ ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end.
-calc_mac_hash(#connection_state{mac_secret = MacSecret,
- security_parameters = #security_parameters{mac_algorithm = MacAlg}},
- Type, Version, Epoch, SeqNo, Fragment) ->
+calc_mac_hash(Type, Version, #{mac_secret := MacSecret,
+ security_parameters := #security_parameters{mac_algorithm = MacAlg}},
+ Epoch, SeqNo, Fragment) ->
Length = erlang:iolist_size(Fragment),
NewSeq = (Epoch bsl 48) + SeqNo,
mac_hash(Version, MacAlg, MacSecret, NewSeq, Type,
diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl
index b9f84cbe7f..373481c3f8 100644
--- a/lib/ssl/src/dtls_record.hrl
+++ b/lib/ssl/src/dtls_record.hrl
@@ -34,11 +34,10 @@
-record(ssl_tls, {
type,
version,
- epoch,
- sequence_number,
- offset,
- length,
- fragment
+ %%length,
+ fragment,
+ epoch,
+ sequence_number
}).
-endif. % -ifdef(dtls_record).
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
new file mode 100644
index 0000000000..2a746d97f0
--- /dev/null
+++ b/lib/ssl/src/dtls_socket.erl
@@ -0,0 +1,155 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dtls_socket).
+
+-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
+
+-export([send/3, listen/3, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
+ peername/2, sockname/2, port/2, close/2]).
+-export([emulated_options/0, internal_inet_values/0, default_inet_values/0, default_cb_info/0]).
+
+send(Transport, {{IP,Port},Socket}, Data) ->
+ Transport:send(Socket, IP, Port, Data).
+
+listen(gen_udp = Transport, Port, #config{transport_info = {Transport, _, _, _},
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_user = Options} = Config) ->
+
+
+ case dtls_udp_sup:start_child([Port, emulated_socket_options(EmOpts, #socket_options{}),
+ Options ++ internal_inet_values(), SslOpts]) of
+ {ok, Pid} ->
+ {ok, #sslsocket{pid = {udp, Config#config{udp_handler = {Pid, Port}}}}};
+ Err = {error, _} ->
+ Err
+ end.
+
+accept(udp, #config{transport_info = {Transport = gen_udp,_,_,_},
+ connection_cb = ConnectionCb,
+ udp_handler = {Listner, _}}, _Timeout) ->
+ case dtls_udp_listener:accept(Listner, self()) of
+ {ok, Pid, Socket} ->
+ {ok, socket(Pid, Transport, {Listner, Socket}, ConnectionCb)};
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+connect(Address, Port, #config{transport_info = {Transport, _, _, _} = CbInfo,
+ connection_cb = ConnectionCb,
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_ssl = SocketOpts}, Timeout) ->
+ case Transport:open(0, SocketOpts ++ internal_inet_values()) of
+ {ok, Socket} ->
+ ssl_connection:connect(ConnectionCb, Address, Port, {{Address, Port},Socket},
+ {SslOpts,
+ emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout);
+ {error, _} = Error->
+ Error
+ end.
+
+close(gen_udp, {_Client, _Socket}) ->
+ ok.
+
+socket(Pid, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
+ #sslsocket{pid = Pid,
+ %% "The name "fd" is keept for backwards compatibility
+ fd = {Transport, Socket, ConnectionCb}};
+socket(Pid, Transport, Socket, ConnectionCb) ->
+ #sslsocket{pid = Pid,
+ %% "The name "fd" is keept for backwards compatibility
+ fd = {Transport, Socket, ConnectionCb}}.
+%% Vad göra med emulerade
+setopts(gen_udp, #sslsocket{pid = {Socket, _}}, Options) ->
+ {SockOpts, _} = tls_socket:split_options(Options),
+ inet:setopts(Socket, SockOpts);
+setopts(_, #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}, Options) ->
+ {SockOpts, _} = tls_socket:split_options(Options),
+ Transport:setopts(ListenSocket, SockOpts);
+%%% Following clauses will not be called for emulated options, they are handled in the connection process
+setopts(gen_udp, Socket, Options) ->
+ inet:setopts(Socket, Options);
+setopts(Transport, Socket, Options) ->
+ Transport:setopts(Socket, Options).
+
+getopts(gen_udp, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) ->
+ {SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
+ EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
+ SocketOpts = tls_socket:get_socket_opts(Socket, SockOptNames, inet),
+ {ok, EmulatedOpts ++ SocketOpts};
+getopts(Transport, #sslsocket{pid = {ListenSocket, #config{emulated = EmOpts}}}, Options) ->
+ {SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
+ EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
+ SocketOpts = tls_socket:get_socket_opts(ListenSocket, SockOptNames, Transport),
+ {ok, EmulatedOpts ++ SocketOpts};
+%%% Following clauses will not be called for emulated options, they are handled in the connection process
+getopts(gen_udp, {_,Socket}, Options) ->
+ inet:getopts(Socket, Options);
+getopts(Transport, Socket, Options) ->
+ Transport:getopts(Socket, Options).
+getstat(gen_udp, {_,Socket}, Options) ->
+ inet:getstat(Socket, Options);
+getstat(Transport, Socket, Options) ->
+ Transport:getstat(Socket, Options).
+peername(udp, _) ->
+ {error, enotconn};
+peername(gen_udp, {_, {Client, _Socket}}) ->
+ {ok, Client};
+peername(Transport, Socket) ->
+ Transport:peername(Socket).
+sockname(gen_udp, {_, {_,Socket}}) ->
+ inet:sockname(Socket);
+sockname(gen_udp, Socket) ->
+ inet:sockname(Socket);
+sockname(Transport, Socket) ->
+ Transport:sockname(Socket).
+
+port(gen_udp, {_,Socket}) ->
+ inet:port(Socket);
+port(Transport, Socket) ->
+ Transport:port(Socket).
+
+emulated_options() ->
+ [mode, active, packet, packet_size].
+
+internal_inet_values() ->
+ [{active, false}, {mode,binary}].
+
+default_inet_values() ->
+ [{active, true}, {mode, list}].
+
+default_cb_info() ->
+ {gen_udp, udp, udp_closed, udp_error}.
+
+get_emulated_opts(EmOpts, EmOptNames) ->
+ lists:map(fun(Name) -> {value, Value} = lists:keysearch(Name, 1, EmOpts),
+ Value end,
+ EmOptNames).
+
+emulated_socket_options(InetValues, #socket_options{
+ mode = Mode,
+ active = Active}) ->
+ #socket_options{
+ mode = proplists:get_value(mode, InetValues, Mode),
+ active = proplists:get_value(active, InetValues, Active)
+ }.
diff --git a/lib/ssl/src/dtls_udp_listener.erl b/lib/ssl/src/dtls_udp_listener.erl
new file mode 100644
index 0000000000..f0ace2d887
--- /dev/null
+++ b/lib/ssl/src/dtls_udp_listener.erl
@@ -0,0 +1,249 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
+%%
+%% The 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(dtls_udp_listener).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/4, active_once/3, accept/2, sockname/1, close/1,
+ get_all_opts/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-record(state,
+ {port,
+ listner,
+ dtls_options,
+ emulated_options,
+ dtls_msq_queues = kv_new(),
+ clients = set_new(),
+ dtls_processes = kv_new(),
+ accepters = queue:new(),
+ first,
+ close
+ }).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+start_link(Port, EmOpts, InetOptions, DTLSOptions) ->
+ gen_server:start_link(?MODULE, [Port, EmOpts, InetOptions, DTLSOptions], []).
+
+active_once(UDPConnection, Client, Pid) ->
+ gen_server:cast(UDPConnection, {active_once, Client, Pid}).
+
+accept(UDPConnection, Accepter) ->
+ call(UDPConnection, {accept, Accepter}).
+
+sockname(UDPConnection) ->
+ call(UDPConnection, sockname).
+close(UDPConnection) ->
+ call(UDPConnection, close).
+get_all_opts(UDPConnection) ->
+ call(UDPConnection, get_all_opts).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([Port, EmOpts, InetOptions, DTLSOptions]) ->
+ try
+ {ok, Socket} = gen_udp:open(Port, InetOptions),
+ {ok, #state{port = Port,
+ first = true,
+ dtls_options = DTLSOptions,
+ emulated_options = EmOpts,
+ listner = Socket,
+ close = false}}
+ catch _:_ ->
+ {error, closed}
+ end.
+handle_call({accept, _}, _, #state{close = true} = State) ->
+ {reply, {error, closed}, State};
+
+handle_call({accept, Accepter}, From, #state{first = true,
+ accepters = Accepters,
+ listner = Socket} = State0) ->
+ next_datagram(Socket),
+ State = State0#state{first = false,
+ accepters = queue:in({Accepter, From}, Accepters)},
+ {noreply, State};
+
+handle_call({accept, Accepter}, From, #state{accepters = Accepters} = State0) ->
+ State = State0#state{accepters = queue:in({Accepter, From}, Accepters)},
+ {noreply, State};
+handle_call(sockname, _, #state{listner = Socket} = State) ->
+ Reply = inet:sockname(Socket),
+ {reply, Reply, State};
+handle_call(close, _, #state{dtls_processes = Processes,
+ accepters = Accepters} = State) ->
+ case kv_empty(Processes) of
+ true ->
+ {stop, normal, ok, State#state{close=true}};
+ false ->
+ lists:foreach(fun({_, From}) ->
+ gen_server:reply(From, {error, closed})
+ end, queue:to_list(Accepters)),
+ {reply, ok, State#state{close = true, accepters = queue:new()}}
+ end;
+handle_call(get_all_opts, _, #state{dtls_options = DTLSOptions,
+ emulated_options = EmOpts} = State) ->
+ {reply, {ok, EmOpts, DTLSOptions}, State}.
+
+handle_cast({active_once, Client, Pid}, State0) ->
+ State = handle_active_once(Client, Pid, State0),
+ {noreply, State}.
+
+handle_info({udp, Socket, IP, InPortNo, _} = Msg, #state{listner = Socket} = State0) ->
+ State = handle_datagram({IP, InPortNo}, Msg, State0),
+ next_datagram(Socket),
+ {noreply, State};
+
+handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients,
+ dtls_processes = Processes0,
+ close = ListenClosed} = State) ->
+ Client = kv_get(Pid, Processes0),
+ Processes = kv_delete(Pid, Processes0),
+ case ListenClosed andalso kv_empty(Processes) of
+ true ->
+ {stop, normal, State};
+ false ->
+ {noreply, State#state{clients = set_delete(Client, Clients),
+ dtls_processes = Processes}}
+ end.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+handle_datagram(Client, Msg, #state{clients = Clients,
+ accepters = AcceptorsQueue0} = State) ->
+ case set_is_member(Client, Clients) of
+ false ->
+ case queue:out(AcceptorsQueue0) of
+ {{value, {UserPid, From}}, AcceptorsQueue} ->
+ setup_new_connection(UserPid, From, Client, Msg,
+ State#state{accepters = AcceptorsQueue});
+ {empty, _} ->
+ %% Drop packet client will resend
+ State
+ end;
+ true ->
+ dispatch(Client, Msg, State)
+ end.
+
+dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
+ case kv_lookup(Client, MsgQueues) of
+ {value, Queue0} ->
+ case queue:out(Queue0) of
+ {{value, Pid}, Queue} when is_pid(Pid) ->
+ Pid ! Msg,
+ State#state{dtls_msq_queues =
+ kv_update(Client, Queue, MsgQueues)};
+ {{value, _}, Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, queue:in(Msg, Queue), MsgQueues)};
+ {empty, Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, queue:in(Msg, Queue), MsgQueues)}
+ end
+ end.
+next_datagram(Socket) ->
+ inet:setopts(Socket, [{active, once}]).
+
+handle_active_once(Client, Pid, #state{dtls_msq_queues = MsgQueues} = State0) ->
+ Queue0 = kv_get(Client, MsgQueues),
+ case queue:out(Queue0) of
+ {{value, Pid}, _} when is_pid(Pid) ->
+ State0;
+ {{value, Msg}, Queue} ->
+ Pid ! Msg,
+ State0#state{dtls_msq_queues = kv_update(Client, Queue, MsgQueues)};
+ {empty, Queue0} ->
+ State0#state{dtls_msq_queues = kv_update(Client, queue:in(Pid, Queue0), MsgQueues)}
+ end.
+
+setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
+ clients = Clients,
+ dtls_msq_queues = MsgQueues,
+ dtls_options = DTLSOpts,
+ port = Port,
+ listner = Socket,
+ emulated_options = EmOpts} = State) ->
+ ConnArgs = [server, "localhost", Port, {self(), {Client, Socket}},
+ {DTLSOpts, EmOpts, udp_listner}, User, dtls_socket:default_cb_info()],
+ case dtls_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ erlang:monitor(process, Pid),
+ gen_server:reply(From, {ok, Pid, {Client, Socket}}),
+ Pid ! Msg,
+ State#state{clients = set_insert(Client, Clients),
+ dtls_msq_queues = kv_insert(Client, queue:new(), MsgQueues),
+ dtls_processes = kv_insert(Pid, Client, Processes)};
+ {error, Reason} ->
+ gen_server:reply(From, {error, Reason}),
+ State
+ end.
+
+kv_update(Key, Value, Store) ->
+ gb_trees:update(Key, Value, Store).
+kv_lookup(Key, Store) ->
+ gb_trees:lookup(Key, Store).
+kv_insert(Key, Value, Store) ->
+ gb_trees:insert(Key, Value, Store).
+kv_get(Key, Store) ->
+ gb_trees:get(Key, Store).
+kv_delete(Key, Store) ->
+ gb_trees:delete(Key, Store).
+kv_new() ->
+ gb_trees:empty().
+kv_empty(Store) ->
+ gb_trees:is_empty(Store).
+
+set_new() ->
+ gb_sets:empty().
+set_insert(Item, Set) ->
+ gb_sets:insert(Item, Set).
+set_delete(Item, Set) ->
+ gb_sets:delete(Item, Set).
+set_is_member(Item, Set) ->
+ gb_sets:is_member(Item, Set).
+
+call(Server, Msg) ->
+ try
+ gen_server:call(Server, Msg, infinity)
+ catch
+ exit:{noproc, _} ->
+ {error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{{shutdown, _},_} ->
+ {error, closed}
+ end.
diff --git a/lib/ssl/src/dtls_udp_sup.erl b/lib/ssl/src/dtls_udp_sup.erl
new file mode 100644
index 0000000000..197882e92f
--- /dev/null
+++ b/lib/ssl/src/dtls_udp_sup.erl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Supervisor for a procsses dispatching upd datagrams to
+%% correct DTLS handler
+%%----------------------------------------------------------------------
+-module(dtls_udp_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+-export([start_child/1]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+start_child(Args) ->
+ supervisor:start_child(?MODULE, Args).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+init(_O) ->
+ RestartStrategy = simple_one_for_one,
+ MaxR = 0,
+ MaxT = 3600,
+
+ Name = undefined, % As simple_one_for_one is used.
+ StartFunc = {dtls_udp_listener, start_link, []},
+ Restart = temporary, % E.g. should not be restarted
+ Shutdown = 4000,
+ Modules = [dtls_udp_listener],
+ Type = worker,
+
+ ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
+ {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 8c03bda513..7169477a82 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,15 +21,24 @@
-include("ssl_cipher.hrl").
--export([suites/1, mac_hash/7, ecc_curves/1, corresponding_tls_version/1]).
+-export([suites/1, all_suites/1, mac_hash/7, ecc_curves/1,
+ corresponding_tls_version/1, corresponding_dtls_version/1]).
-spec suites(Minor:: 253|255) -> [ssl_cipher:cipher_suite()].
suites(Minor) ->
- tls_v1:suites(corresponding_minor_tls_version(Minor)).
+ lists:filter(fun(Cipher) ->
+ is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ end,
+ tls_v1:suites(corresponding_minor_tls_version(Minor))).
+all_suites(Version) ->
+ lists:filter(fun(Cipher) ->
+ is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ end,
+ ssl_cipher:all_suites(corresponding_tls_version(Version))).
mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, corresponding_tls_version(Version),
+ tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
Length, Fragment).
ecc_curves({_Major, Minor}) ->
@@ -42,3 +51,13 @@ corresponding_minor_tls_version(255) ->
2;
corresponding_minor_tls_version(253) ->
3.
+
+corresponding_dtls_version({3, Minor}) ->
+ {254, corresponding_minor_dtls_version(Minor)}.
+
+corresponding_minor_dtls_version(2) ->
+ 255;
+corresponding_minor_dtls_version(3) ->
+ 253.
+is_acceptable_cipher(Suite) ->
+ not ssl_cipher:is_stream_ciphersuite(Suite).
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index b26efbd88f..064dcd6892 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -6,14 +6,20 @@
tls_connection,
tls_handshake,
tls_record,
+ tls_socket,
tls_v1,
ssl_v3,
ssl_v2,
+ tls_connection_sup,
%% DTLS
dtls_connection,
dtls_handshake,
dtls_record,
+ dtls_socket,
dtls_v1,
+ dtls_connection_sup,
+ dtls_udp_listener,
+ dtls_udp_sup,
%% API
ssl, %% Main API
tls, %% TLS specific
@@ -27,17 +33,19 @@
ssl_cipher,
ssl_srp_primes,
ssl_alert,
- ssl_socket,
- ssl_listen_tracker_sup,
+ ssl_listen_tracker_sup, %% may be used by DTLS over SCTP
%% Erlang Distribution over SSL/TLS
inet_tls_dist,
inet6_tls_dist,
ssl_tls_dist_proxy,
ssl_dist_sup,
- %% SSL/TLS session handling
+ ssl_dist_connection_sup,
+ ssl_dist_admin_sup,
+ %% SSL/TLS session and cert handling
ssl_session,
ssl_session_cache,
ssl_manager,
+ ssl_pem_cache,
ssl_pkix_db,
ssl_certificate,
%% CRL handling
@@ -48,14 +56,14 @@
%% App structure
ssl_app,
ssl_sup,
- tls_connection_sup,
- dtls_connection_sup
+ ssl_admin_sup,
+ ssl_connection_sup
]},
{registered, [ssl_sup, ssl_manager]},
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
{mod, {ssl_app, []}},
- {runtime_dependencies, ["stdlib-3.0","public_key-1.2","kernel-3.0",
+ {runtime_dependencies, ["stdlib-3.2","public_key-1.2","kernel-3.0",
"erts-7.0","crypto-3.3", "inets-5.10.7"]}]}.
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 11728128c4..bfdd0c205b 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
{<<"5\\..*">>, [{restart_application, ssl}]},
@@ -8,6 +9,7 @@
{<<"3\\..*">>, [{restart_application, ssl}]}
],
[
+ {<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
{<<"5\\..*">>, [{restart_application, ssl}]},
@@ -15,4 +17,3 @@
{<<"3\\..*">>, [{restart_application, ssl}]}
]
}.
-
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index d2aeb3258f..9a106f9742 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,12 +38,12 @@
getopts/2, setopts/2, getstat/1, getstat/2
]).
%% SSL/TLS protocol handling
--export([cipher_suites/0, cipher_suites/1,
+-export([cipher_suites/0, cipher_suites/1, eccs/0, eccs/1,
connection_info/1, versions/0, session_info/1, format_error/1,
renegotiate/1, prf/5, negotiated_protocol/1, negotiated_next_protocol/1,
connection_information/1, connection_information/2]).
%% Misc
--export([handle_options/2]).
+-export([handle_options/2, tls_version/1]).
-deprecated({negotiated_next_protocol, 1, next_major_release}).
-deprecated({connection_info, 1, next_major_release}).
@@ -101,33 +101,27 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
{Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
{gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = ssl_socket:emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ EmulatedOptions = tls_socket:emulated_options(),
+ {ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
try handle_options(SslOptions0 ++ SocketValues, client) of
- {ok, #config{transport_info = CbInfo, ssl = SslOptions, emulated = EmOpts,
- connection_cb = ConnectionCb}} ->
-
- ok = ssl_socket:setopts(Transport, Socket, ssl_socket:internal_inet_values()),
- case ssl_socket:peername(Transport, Socket) of
- {ok, {Address, Port}} ->
- ssl_connection:connect(ConnectionCb, Address, Port, Socket,
- {SslOptions, emulated_socket_options(EmOpts, #socket_options{}), undefined},
- self(), CbInfo, Timeout);
- {error, Error} ->
- {error, Error}
- end
+ {ok, Config} ->
+ tls_socket:upgrade(Socket, Config, Timeout)
catch
_:{error, Reason} ->
{error, Reason}
end;
-
connect(Host, Port, Options) ->
connect(Host, Port, Options, infinity).
connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- try handle_options(Options, client) of
- {ok, Config} ->
- do_connect(Host,Port,Config,Timeout)
+ try
+ {ok, Config} = handle_options(Options, client),
+ case Config#config.connection_cb of
+ tls_connection ->
+ tls_socket:connect(Host,Port,Config,Timeout);
+ dtls_connection ->
+ dtls_socket:connect(Host,Port,Config,Timeout)
+ end
catch
throw:Error ->
Error
@@ -144,17 +138,7 @@ listen(_Port, []) ->
listen(Port, Options0) ->
try
{ok, Config} = handle_options(Options0, server),
- ConnectionCb = connection_cb(Options0),
- #config{transport_info = {Transport, _, _, _}, inet_user = Options, connection_cb = ConnectionCb,
- ssl = SslOpts, emulated = EmOpts} = Config,
- case Transport:listen(Port, Options) of
- {ok, ListenSocket} ->
- ok = ssl_socket:setopts(Transport, ListenSocket, ssl_socket:internal_inet_values()),
- {ok, Tracker} = ssl_socket:inherit_tracker(ListenSocket, EmOpts, SslOpts),
- {ok, #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}}};
- Err = {error, _} ->
- Err
- end
+ do_listen(Port, Config, connection_cb(Options0))
catch
Error = {error, _} ->
Error
@@ -171,27 +155,15 @@ transport_accept(ListenSocket) ->
transport_accept(ListenSocket, infinity).
transport_accept(#sslsocket{pid = {ListenSocket,
- #config{transport_info = {Transport,_,_, _} =CbInfo,
- connection_cb = ConnectionCb,
- ssl = SslOpts,
- emulated = Tracker}}}, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- case Transport:accept(ListenSocket, Timeout) of
- {ok, Socket} ->
- {ok, EmOpts} = ssl_socket:get_emulated_opts(Tracker),
- {ok, Port} = ssl_socket:port(Transport, Socket),
- ConnArgs = [server, "localhost", Port, Socket,
- {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Tracker}, self(), CbInfo],
- ConnectionSup = connection_sup(ConnectionCb),
- case ConnectionSup:start_child(ConnArgs) of
- {ok, Pid} ->
- ssl_connection:socket_control(ConnectionCb, Socket, Pid, Transport, Tracker);
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
+ #config{connection_cb = ConnectionCb} = Config}}, Timeout)
+ when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ case ConnectionCb of
+ tls_connection ->
+ tls_socket:accept(ListenSocket, Config, Timeout);
+ dtls_connection ->
+ dtls_socket:accept(ListenSocket, Config, Timeout)
end.
-
+
%%--------------------------------------------------------------------
-spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
@@ -214,13 +186,22 @@ ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
ssl_accept(ListenSocket, SslOptions, infinity).
ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
- ssl_accept(#sslsocket{} = Socket, Timeout);
-ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts0, Timeout) when
+ ssl_accept(Socket, Timeout);
+ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
- {ok, EmOpts, InheritedSslOpts} = ssl_socket:get_all_opts(Tracker),
- SslOpts = handle_options(SslOpts0, InheritedSslOpts),
- ssl_connection:handshake(Socket, {SslOpts, emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
+ {ok, EmOpts, _} = tls_socket:get_all_opts(Tracker),
+ ssl_connection:handshake(Socket, {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
+ catch
+ Error = {error, _Reason} -> Error
+ end;
+ssl_accept(#sslsocket{pid = Pid, fd = {_, _, _}} = Socket, SslOpts, Timeout) when
+ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
+ try
+ {ok, EmOpts, _} = dtls_udp_listener:get_all_opts(Pid),
+ ssl_connection:handshake(Socket, {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
catch
Error = {error, _Reason} -> Error
end;
@@ -228,20 +209,20 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
{Transport,_,_,_} =
proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = ssl_socket:emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ EmulatedOptions = tls_socket:emulated_options(),
+ {ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
ConnetionCb = connection_cb(SslOptions),
try handle_options(SslOptions ++ SocketValues, server) of
{ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
- ok = ssl_socket:setopts(Transport, Socket, ssl_socket:internal_inet_values()),
- {ok, Port} = ssl_socket:port(Transport, Socket),
+ ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()),
+ {ok, Port} = tls_socket:port(Transport, Socket),
ssl_connection:ssl_accept(ConnetionCb, Port, Socket,
- {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{}), undefined},
self(), CbInfo, Timeout)
catch
Error = {error, _Reason} -> Error
end.
-
%%--------------------------------------------------------------------
-spec close(#sslsocket{}) -> term().
%%
@@ -249,6 +230,8 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
%%--------------------------------------------------------------------
close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
+close(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
+ dtls_udp_listener:close(Pid);
close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) ->
Transport:close(ListenSocket).
@@ -275,6 +258,10 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
%%--------------------------------------------------------------------
send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
+send(#sslsocket{pid = {_, #config{transport_info={gen_udp, _, _, _}}}}, _) ->
+ {error,enotconn}; %% Emulate connection behaviour
+send(#sslsocket{pid = {udp,_}}, _) ->
+ {error,enotconn};
send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
Transport:send(ListenSocket, Data). %% {error,enotconn}
@@ -289,6 +276,8 @@ recv(Socket, Length) ->
recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
ssl_connection:recv(Pid, Length, Timeout);
+recv(#sslsocket{pid = {udp,_}}, _, _) ->
+ {error,enotconn};
recv(#sslsocket{pid = {Listen,
#config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)->
Transport:recv(Listen, 0). %% {error,enotconn}
@@ -301,10 +290,14 @@ recv(#sslsocket{pid = {Listen,
%%--------------------------------------------------------------------
controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
ssl_connection:new_user(Pid, NewOwner);
+controlling_process(#sslsocket{pid = {udp, _}},
+ NewOwner) when is_pid(NewOwner) ->
+ ok; %% Meaningless but let it be allowed to conform with TLS
controlling_process(#sslsocket{pid = {Listen,
#config{transport_info = {Transport, _, _, _}}}},
NewOwner) when is_port(Listen),
is_pid(NewOwner) ->
+ %% Meaningless but let it be allowed to conform with normal sockets
Transport:controlling_process(Listen, NewOwner).
@@ -321,7 +314,9 @@ connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
Error
end;
connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
- {error, enotconn}.
+ {error, enotconn};
+connection_information(#sslsocket{pid = {udp,_}}) ->
+ {error,enotconn}.
%%--------------------------------------------------------------------
-spec connection_information(#sslsocket{}, [atom()]) -> {ok, list()} | {error, reason()}.
@@ -357,10 +352,18 @@ connection_info(#sslsocket{} = SSLSocket) ->
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
+peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid)->
+ dtls_socket:peername(Transport, Socket);
peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
- ssl_socket:peername(Transport, Socket);
+ tls_socket:peername(Transport, Socket);
+peername(#sslsocket{pid = {udp = Transport, #config{udp_handler = {_Pid, _}}}}) ->
+ dtls_socket:peername(Transport, undefined);
+peername(#sslsocket{pid = Pid, fd = {gen_udp= Transport, Socket, _, _}}) when is_pid(Pid) ->
+ dtls_socket:peername(Transport, Socket);
peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
- ssl_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
+ tls_socket:peername(Transport, ListenSocket); %% Will return {error, enotconn}
+peername(#sslsocket{pid = {udp,_}}) ->
+ {error,enotconn}.
%%--------------------------------------------------------------------
-spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
@@ -374,6 +377,8 @@ peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
Result ->
Result
end;
+peercert(#sslsocket{pid = {udp, _}}) ->
+ {error, enotconn};
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
@@ -420,6 +425,33 @@ cipher_suites(all) ->
[ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all)].
%%--------------------------------------------------------------------
+-spec eccs() -> tls_v1:curves().
+%% Description: returns all supported curves across all versions
+%%--------------------------------------------------------------------
+eccs() ->
+ Curves = tls_v1:ecc_curves(all), % only tls_v1 has named curves right now
+ eccs_filter_supported(Curves).
+
+%%--------------------------------------------------------------------
+-spec eccs(tls_record:tls_version() | tls_record:tls_atom_version()) ->
+ tls_v1:curves().
+%% Description: returns the curves supported for a given version of
+%% ssl/tls.
+%%--------------------------------------------------------------------
+eccs({3,0}) ->
+ [];
+eccs({3,_}) ->
+ Curves = tls_v1:ecc_curves(all),
+ eccs_filter_supported(Curves);
+eccs(AtomVersion) when is_atom(AtomVersion) ->
+ eccs(tls_record:protocol_version(AtomVersion)).
+
+eccs_filter_supported(Curves) ->
+ CryptoCurves = crypto:ec_curves(),
+ lists:filter(fun(Curve) -> proplists:get_bool(Curve, CryptoCurves) end,
+ Curves).
+
+%%--------------------------------------------------------------------
-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
{ok, [gen_tcp:option()]} | {error, reason()}.
%%
@@ -429,7 +461,7 @@ getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags)
ssl_connection:get_opts(Pid, OptionTags);
getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket,
OptionTags) when is_list(OptionTags) ->
- try ssl_socket:getopts(Transport, ListenSocket, OptionTags) of
+ try tls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
{error, InetError} ->
@@ -457,7 +489,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
end;
setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
- try ssl_socket:setopts(Transport, ListenSocket, Options) of
+ try tls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
{error, InetError} ->
@@ -490,10 +522,10 @@ getstat(Socket) ->
%% Description: Get one or more statistic options for a socket.
%%--------------------------------------------------------------------
getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) ->
- ssl_socket:getstat(Transport, Listen, Options);
+ tls_socket:getstat(Transport, Listen, Options);
getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
- ssl_socket:getstat(Transport, Socket, Options).
+ tls_socket:getstat(Transport, Socket, Options).
%%---------------------------------------------------------------
-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
@@ -503,6 +535,8 @@ getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_
shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}}},
How) when is_port(Listen) ->
Transport:shutdown(Listen, How);
+shutdown(#sslsocket{pid = {udp,_}},_) ->
+ {error, enotconn};
shutdown(#sslsocket{pid = Pid}, How) ->
ssl_connection:shutdown(Pid, How).
@@ -512,10 +546,13 @@ shutdown(#sslsocket{pid = Pid}, How) ->
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
- ssl_socket:sockname(Transport, Listen);
-
+ tls_socket:sockname(Transport, Listen);
+sockname(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
+ dtls_udp_listener:sockname(Pid);
+sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid) ->
+ dtls_socket:sockname(Transport, Socket);
sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
- ssl_socket:sockname(Transport, Socket).
+ tls_socket:sockname(Transport, Socket).
%%---------------------------------------------------------------
-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
@@ -525,6 +562,8 @@ sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)
%%--------------------------------------------------------------------
session_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:session_info(Pid);
+session_info(#sslsocket{pid = {udp,_}}) ->
+ {error, enotconn};
session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
@@ -549,6 +588,8 @@ versions() ->
%%--------------------------------------------------------------------
renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:renegotiation(Pid);
+renegotiate(#sslsocket{pid = {udp,_}}) ->
+ {error, enotconn};
renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
@@ -562,6 +603,8 @@ renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
prf(#sslsocket{pid = Pid},
Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
+prf(#sslsocket{pid = {udp,_}}, _,_,_,_) ->
+ {error, enotconn};
prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
{error, enotconn}.
@@ -571,7 +614,7 @@ prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
%% Description: Clear the PEM cache
%%--------------------------------------------------------------------
clear_pem_cache() ->
- ssl_manager:clear_pem_cache().
+ ssl_pem_cache:clear().
%%---------------------------------------------------------------
-spec format_error({error, term()}) -> list().
@@ -607,6 +650,11 @@ format_error(Error) ->
Other
end.
+tls_version({3, _} = Version) ->
+ Version;
+tls_version({254, _} = Version) ->
+ dtls_v1:corresponding_tls_version(Version).
+
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
@@ -620,28 +668,15 @@ available_suites(all) ->
Version = tls_record:highest_protocol_version([]),
ssl_cipher:filter_suites(ssl_cipher:all_suites(Version)).
-do_connect(Address, Port,
- #config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
- emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
- Timeout) ->
- {Transport, _, _, _} = CbInfo,
- try Transport:connect(Address, Port, SocketOpts, Timeout) of
- {ok, Socket} ->
- ssl_connection:connect(ConnetionCb, Address, Port, Socket,
- {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), undefined},
- self(), CbInfo, Timeout);
- {error, Reason} ->
- {error, Reason}
- catch
- exit:{function_clause, _} ->
- {error, {options, {cb_info, CbInfo}}};
- exit:badarg ->
- {error, {options, {socket_options, UserOpts}}};
- exit:{badarg, _} ->
- {error, {options, {socket_options, UserOpts}}}
- end.
+do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
+ tls_socket:listen(Transport, Port, Config);
+do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, dtls_connection) ->
+ dtls_socket:listen(Transport, Port, Config).
+
%% Handle extra ssl options given to ssl_accept
+-spec handle_options([any()], #ssl_options{}) -> #ssl_options{}
+ ; ([any()], client | server) -> {ok, #config{}}.
handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0,
cacertfile = CaCertFile0} = InheritedSslOpts) ->
RecordCB = record_cb(Protocol),
@@ -698,6 +733,8 @@ handle_options(Opts0, Role) ->
[RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
end,
+ Protocol = handle_option(protocol, Opts, tls),
+
SSLOptions = #ssl_options{
versions = Versions,
verify = validate_option(verify, Verify),
@@ -720,10 +757,12 @@ handle_options(Opts0, Role) ->
srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_cipher_option(proplists:get_value(ciphers, Opts, []),
RecordCb:highest_protocol_version(Versions)),
+ eccs = handle_eccs_option(proplists:get_value(eccs, Opts, eccs()),
+ RecordCb:highest_protocol_version(Versions)),
signature_algs = handle_hashsigns_option(proplists:get_value(signature_algs, Opts,
default_option_role(server,
tls_v1:default_signature_algs(Versions), Role)),
- RecordCb:highest_protocol_version(Versions)),
+ tls_version(RecordCb:highest_protocol_version(Versions))),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
reuse_sessions = handle_option(reuse_sessions, Opts, true),
@@ -750,7 +789,10 @@ handle_options(Opts0, Role) ->
honor_cipher_order = handle_option(honor_cipher_order, Opts,
default_option_role(server, false, Role),
server, Role),
- protocol = proplists:get_value(protocol, Opts, tls),
+ honor_ecc_order = handle_option(honor_ecc_order, Opts,
+ default_option_role(server, false, Role),
+ server, Role),
+ protocol = Protocol,
padding_check = proplists:get_value(padding_check, Opts, true),
beast_mitigation = handle_option(beast_mitigation, Opts, one_n_minus_one),
fallback = handle_option(fallback, Opts,
@@ -760,10 +802,11 @@ handle_options(Opts0, Role) ->
client, Role),
crl_check = handle_option(crl_check, Opts, false),
crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
- v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false)
+ v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false),
+ max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE)
},
- CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
SslOptions = [protocol, versions, verify, verify_fun, partial_chain,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
@@ -775,13 +818,14 @@ handle_options(Opts0, Role) ->
alpn_preferred_protocols, next_protocols_advertised,
client_preferred_next_protocols, log_alert,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
- fallback, signature_algs, beast_mitigation, v2_hello_compatible],
+ fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation, v2_hello_compatible,
+ max_handshake_size],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
end, Opts, SslOptions),
- {Sock, Emulated} = emulated_options(SockOpts),
+ {Sock, Emulated} = emulated_options(Protocol, SockOpts),
ConnetionCb = connection_cb(Opts),
{ok, #config{ssl = SSLOptions, emulated = Emulated, inet_ssl = Sock,
@@ -1005,6 +1049,8 @@ validate_option(sni_fun, Fun) when is_function(Fun) ->
Fun;
validate_option(honor_cipher_order, Value) when is_boolean(Value) ->
Value;
+validate_option(honor_ecc_order, Value) when is_boolean(Value) ->
+ Value;
validate_option(padding_check, Value) when is_boolean(Value) ->
Value;
validate_option(fallback, Value) when is_boolean(Value) ->
@@ -1021,6 +1067,12 @@ validate_option(beast_mitigation, Value) when Value == one_n_minus_one orelse
Value;
validate_option(v2_hello_compatible, Value) when is_boolean(Value) ->
Value;
+validate_option(max_handshake_size, Value) when is_integer(Value) andalso Value =< ?MAX_UNIT24 ->
+ Value;
+validate_option(protocol, Value = tls) ->
+ Value;
+validate_option(protocol, Value = dtls) ->
+ Value;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
@@ -1058,17 +1110,37 @@ validate_binary_list(Opt, List) ->
(Bin) ->
throw({error, {options, {Opt, {invalid_protocol, Bin}}}})
end, List).
-
validate_versions([], Versions) ->
Versions;
validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
Version == 'tlsv1.1';
Version == tlsv1;
Version == sslv3 ->
- validate_versions(Rest, Versions);
+ tls_validate_versions(Rest, Versions);
+validate_versions([Version | Rest], Versions) when Version == 'dtlsv1';
+ Version == 'dtlsv2'->
+ dtls_validate_versions(Rest, Versions);
validate_versions([Ver| _], Versions) ->
throw({error, {options, {Ver, {versions, Versions}}}}).
+tls_validate_versions([], Versions) ->
+ Versions;
+tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
+ tls_validate_versions(Rest, Versions);
+tls_validate_versions([Ver| _], Versions) ->
+ throw({error, {options, {Ver, {versions, Versions}}}}).
+
+dtls_validate_versions([], Versions) ->
+ Versions;
+dtls_validate_versions([Version | Rest], Versions) when Version == 'dtlsv1';
+ Version == 'dtlsv2'->
+ dtls_validate_versions(Rest, Versions);
+dtls_validate_versions([Ver| _], Versions) ->
+ throw({error, {options, {Ver, {versions, Versions}}}}).
+
validate_inet_option(mode, Value)
when Value =/= list, Value =/= binary ->
throw({error, {options, {mode,Value}}});
@@ -1098,8 +1170,13 @@ ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
%% some trusted certs.
ca_cert_default(verify_peer, undefined, _) ->
"".
-emulated_options(Opts) ->
- emulated_options(Opts, ssl_socket:internal_inet_values(), ssl_socket:default_inet_values()).
+emulated_options(Protocol, Opts) ->
+ case Protocol of
+ tls ->
+ emulated_options(Opts, tls_socket:internal_inet_values(), tls_socket:default_inet_values());
+ dtls ->
+ emulated_options(Opts, dtls_socket:internal_inet_values(), dtls_socket:default_inet_values())
+ end.
emulated_options([{mode, Value} = Opt |Opts], Inet, Emulated) ->
validate_inet_option(mode, Value),
@@ -1135,18 +1212,18 @@ handle_cipher_option(Value, Version) when is_list(Value) ->
binary_cipher_suites(Version, []) ->
%% Defaults to all supported suites that does
%% not require explicit configuration
- ssl_cipher:filter_suites(ssl_cipher:suites(Version));
+ ssl_cipher:filter_suites(ssl_cipher:suites(tls_version(Version)));
binary_cipher_suites(Version, [Tuple|_] = Ciphers0) when is_tuple(Tuple) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- All = ssl_cipher:all_suites(Version),
+ All = ssl_cipher:all_suites(tls_version(Version)),
case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, All)] of
[] ->
%% Defaults to all supported suites that does
%% not require explicit configuration
- ssl_cipher:filter_suites(ssl_cipher:suites(Version));
+ ssl_cipher:filter_suites(ssl_cipher:suites(tls_version(Version)));
Ciphers ->
Ciphers
end;
@@ -1159,6 +1236,15 @@ binary_cipher_suites(Version, Ciphers0) ->
Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:tokens(Ciphers0, ":")],
binary_cipher_suites(Version, Ciphers).
+handle_eccs_option(Value, Version) when is_list(Value) ->
+ {_Major, Minor} = tls_version(Version),
+ try tls_v1:ecc_curves(Minor, Value) of
+ Curves -> #elliptic_curves{elliptic_curve_list = Curves}
+ catch
+ exit:_ -> throw({error, {options, {eccs, Value}}});
+ error:_ -> throw({error, {options, {eccs, Value}}})
+ end.
+
unexpected_format(Error) ->
lists:flatten(io_lib:format("Unexpected error: ~p", [Error])).
@@ -1232,11 +1318,6 @@ record_cb(dtls) ->
record_cb(Opts) ->
record_cb(proplists:get_value(protocol, Opts, tls)).
-connection_sup(tls_connection) ->
- tls_connection_sup;
-connection_sup(dtls_connection) ->
- dtls_connection_sup.
-
binary_filename(FileName) ->
Enc = file:native_name_encoding(),
unicode:characters_to_binary(FileName, unicode, Enc).
@@ -1255,20 +1336,6 @@ assert_proplist([inet6 | Rest]) ->
assert_proplist([Value | _]) ->
throw({option_not_a_key_value_tuple, Value}).
-emulated_socket_options(InetValues, #socket_options{
- mode = Mode,
- header = Header,
- active = Active,
- packet = Packet,
- packet_size = Size}) ->
- #socket_options{
- mode = proplists:get_value(mode, InetValues, Mode),
- header = proplists:get_value(header, InetValues, Header),
- active = proplists:get_value(active, InetValues, Active),
- packet = proplists:get_value(packet, InetValues, Packet),
- packet_size = proplists:get_value(packet_size, InetValues, Size)
- }.
-
new_ssl_options([], #ssl_options{} = Opts, _) ->
Opts;
new_ssl_options([{verify_client_once, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
@@ -1329,13 +1396,24 @@ new_ssl_options([{server_name_indication, Value} | Rest], #ssl_options{} = Opts,
new_ssl_options(Rest, Opts#ssl_options{server_name_indication = validate_option(server_name_indication, Value)}, RecordCB);
new_ssl_options([{honor_cipher_order, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{honor_cipher_order = validate_option(honor_cipher_order, Value)}, RecordCB);
+new_ssl_options([{honor_ecc_order, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{honor_ecc_order = validate_option(honor_ecc_order, Value)}, RecordCB);
+new_ssl_options([{eccs, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest,
+ Opts#ssl_options{eccs =
+ handle_eccs_option(Value, RecordCB:highest_protocol_version())
+ },
+ RecordCB);
new_ssl_options([{signature_algs, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest,
Opts#ssl_options{signature_algs =
handle_hashsigns_option(Value,
- RecordCB:highest_protocol_version())},
+ tls_version(RecordCB:highest_protocol_version()))},
RecordCB);
-
+new_ssl_options([{protocol, dtls = Value} | Rest], #ssl_options{} = Opts, dtls_record = RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{protocol = Value}, RecordCB);
+new_ssl_options([{protocol, tls = Value} | Rest], #ssl_options{} = Opts, tls_record = RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{protocol = Value}, RecordCB);
new_ssl_options([{Key, Value} | _Rest], #ssl_options{}, _) ->
throw({error, {options, {Key, Value}}}).
@@ -1397,3 +1475,8 @@ default_option_role(Role, Value, Role) ->
Value;
default_option_role(_,_,_) ->
undefined.
+
+default_cb_info(tls) ->
+ {gen_tcp, tcp, tcp_closed, tcp_error};
+default_cb_info(dtls) ->
+ {gen_udp, udp, udp_closed, udp_error}.
diff --git a/lib/ssl/src/ssl_admin_sup.erl b/lib/ssl/src/ssl_admin_sup.erl
new file mode 100644
index 0000000000..9c96435753
--- /dev/null
+++ b/lib/ssl/src/ssl_admin_sup.erl
@@ -0,0 +1,95 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_admin_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0, manager_opts/0]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+
+init([]) ->
+ PEMCache = pem_cache_child_spec(),
+ SessionCertManager = session_and_cert_manager_child_spec(),
+ {ok, {{rest_for_one, 10, 3600}, [PEMCache, SessionCertManager]}}.
+
+manager_opts() ->
+ CbOpts = case application:get_env(ssl, session_cb) of
+ {ok, Cb} when is_atom(Cb) ->
+ InitArgs = session_cb_init_args(),
+ [{session_cb, Cb}, {session_cb_init_args, InitArgs}];
+ _ ->
+ []
+ end,
+ case application:get_env(ssl, session_lifetime) of
+ {ok, Time} when is_integer(Time) ->
+ [{session_lifetime, Time}| CbOpts];
+ _ ->
+ CbOpts
+ end.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+pem_cache_child_spec() ->
+ Name = ssl_pem_cache,
+ StartFunc = {ssl_pem_cache, start_link, [[]]},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_pem_cache],
+ Type = worker,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+session_and_cert_manager_child_spec() ->
+ Opts = manager_opts(),
+ Name = ssl_manager,
+ StartFunc = {ssl_manager, start_link, [Opts]},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_manager],
+ Type = worker,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+session_cb_init_args() ->
+ case application:get_env(ssl, session_cb_init_args) of
+ {ok, Args} when is_list(Args) ->
+ Args;
+ _ ->
+ []
+ end.
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index db71b16d80..696a55e4b9 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,22 +32,13 @@
-include("ssl_record.hrl").
-include("ssl_internal.hrl").
--export([encode/3, decode/1, alert_txt/1, reason_code/2]).
+-export([decode/1, alert_txt/1, reason_code/2]).
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec encode(#alert{}, ssl_record:ssl_version(), #connection_states{}) ->
- {iolist(), #connection_states{}}.
-%%
-%% Description: Encodes an alert
-%%--------------------------------------------------------------------
-encode(#alert{} = Alert, Version, ConnectionStates) ->
- ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
-
-%%--------------------------------------------------------------------
-spec decode(binary()) -> [#alert{}] | #alert{}.
%%
%% Description: Decode alert(s), will return a singel own alert if peer
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 38facb964f..f3743ba0f0 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 3ec3f50e05..2046ec75b3 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016 All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017 All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,7 +64,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
{self, IssuerId};
false ->
- other_issuer(OtpCert, BinCert, CertDbHandle)
+ other_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef)
end,
case SignedAndIssuerID of
@@ -125,21 +125,21 @@ file_to_crls(File, DbHandle) ->
%% Description: Validates ssl/tls specific extensions
%%--------------------------------------------------------------------
validate(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
- extnValue = KeyUse}}, {Role, _,_, _, _}) ->
+ extnValue = KeyUse}}, UserState = {Role, _,_, _, _}) ->
case is_valid_extkey_usage(KeyUse, Role) of
true ->
- {valid, Role};
+ {valid, UserState};
false ->
{fail, {bad_cert, invalid_ext_key_usage}}
end;
-validate(_, {extension, _}, Role) ->
- {unknown, Role};
+validate(_, {extension, _}, UserState) ->
+ {unknown, UserState};
validate(_, {bad_cert, _} = Reason, _) ->
{fail, Reason};
-validate(_, valid, Role) ->
- {valid, Role};
-validate(_, valid_peer, Role) ->
- {valid, Role}.
+validate(_, valid, UserState) ->
+ {valid, UserState};
+validate(_, valid_peer, UserState) ->
+ {valid, UserState}.
%%--------------------------------------------------------------------
-spec is_valid_key_usage(list(), term()) -> boolean().
@@ -200,7 +200,7 @@ certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
{_, true = SelfSigned} ->
certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned);
{{error, issuer_not_found}, SelfSigned} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) of
{ok, {SerialNr, Issuer}} ->
certificate_chain(CertDbHandle, CertsDbRef, Chain,
SerialNr, Issuer, SelfSigned);
@@ -232,7 +232,7 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned
{ok, undefined, lists:reverse(Chain)}
end.
-find_issuer(OtpCert, BinCert, CertDbHandle) ->
+find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) ->
IsIssuerFun =
fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) ->
case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
@@ -250,12 +250,24 @@ find_issuer(OtpCert, BinCert, CertDbHandle) ->
Acc
end,
- try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _IssuerId} = Return ->
- Return
+ if is_reference(CertsDbRef) -> % actual DB exists
+ try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _IssuerId} = Return ->
+ Return
+ end;
+ is_tuple(CertsDbRef), element(1,CertsDbRef) =:= extracted -> % cache bypass byproduct
+ {extracted, CertsData} = CertsDbRef,
+ DB = [Entry || {decoded, Entry} <- CertsData],
+ try lists:foldl(IsIssuerFun, issuer_not_found, DB) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _IssuerId} = Return ->
+ Return
+ end
end.
is_valid_extkey_usage(KeyUse, client) ->
@@ -281,12 +293,12 @@ public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorith
subjectPublicKey = Key}) ->
{Key, Params}.
-other_issuer(OtpCert, BinCert, CertDbHandle) ->
+other_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) ->
case public_key:pkix_issuer_id(OtpCert, other) of
{ok, IssuerId} ->
{other, IssuerId};
{error, issuer_not_found} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) of
{ok, IssuerId} ->
{other, IssuerId};
Other ->
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index e935c033c7..32f05628bb 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,15 +40,16 @@
ec_keyed_suites/0, anonymous_suites/1, psk_suites/1, srp_suites/0,
rc4_suites/1, des_suites/1, openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
- random_bytes/1]).
+ random_bytes/1, calc_aad/3, calc_mac_hash/4,
+ is_stream_ciphersuite/1]).
-export_type([cipher_suite/0,
erl_cipher_suite/0, openssl_cipher_suite/0,
hash/0, key_algo/0, sign_algo/0]).
--type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
+-type cipher() :: null |rc4_128 | des_cbc | '3des_ede_cbc'
| aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305.
--type hash() :: null | sha | md5 | sha224 | sha256 | sha384 | sha512.
+-type hash() :: null | md5 | sha | sha224 | sha256 | sha384 | sha512.
-type sign_algo() :: rsa | dsa | ecdsa.
-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.
@@ -310,16 +311,21 @@ aead_decipher(Type, #cipher_state{key = Key, iv = IV} = CipherState,
%%--------------------------------------------------------------------
suites({3, 0}) ->
ssl_v3:suites();
-suites({3, N}) ->
- tls_v1:suites(N).
+suites({3, Minor}) ->
+ tls_v1:suites(Minor);
+suites({_, Minor}) ->
+ dtls_v1:suites(Minor).
-all_suites(Version) ->
+all_suites({3, _} = Version) ->
suites(Version)
++ anonymous_suites(Version)
++ psk_suites(Version)
++ srp_suites()
++ rc4_suites(Version)
- ++ des_suites(Version).
+ ++ des_suites(Version);
+all_suites(Version) ->
+ dtls_v1:all_suites(Version).
+
%%--------------------------------------------------------------------
-spec anonymous_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
%%
@@ -333,21 +339,27 @@ anonymous_suites({3, N}) ->
anonymous_suites(N)
when N >= 3 ->
[?TLS_DH_anon_WITH_AES_128_GCM_SHA256,
- ?TLS_DH_anon_WITH_AES_256_GCM_SHA384
- ] ++ anonymous_suites(0);
-
-anonymous_suites(_) ->
- [?TLS_DH_anon_WITH_RC4_128_MD5,
- ?TLS_DH_anon_WITH_DES_CBC_SHA,
- ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DH_anon_WITH_AES_128_CBC_SHA,
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA,
+ ?TLS_DH_anon_WITH_AES_256_GCM_SHA384,
?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
?TLS_DH_anon_WITH_AES_256_CBC_SHA256,
- ?TLS_ECDH_anon_WITH_RC4_128_SHA,
- ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
- ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DH_anon_WITH_RC4_128_MD5];
+
+anonymous_suites(2) ->
+ [?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DH_anon_WITH_DES_CBC_SHA,
+ ?TLS_DH_anon_WITH_RC4_128_MD5];
+
+anonymous_suites(N) when N == 0;
+ N == 1 ->
+ [?TLS_DH_anon_WITH_RC4_128_MD5,
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DH_anon_WITH_DES_CBC_SHA
+ ].
%%--------------------------------------------------------------------
-spec psk_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
@@ -1441,25 +1453,60 @@ filter_suites(Suites) ->
is_acceptable_prf(Prf, Hashs)
end, Suites).
-is_acceptable_keyexchange(KeyExchange, Algos)
- when KeyExchange == ecdh_ecdsa;
- KeyExchange == ecdhe_ecdsa;
- KeyExchange == ecdh_rsa;
- KeyExchange == ecdhe_rsa;
- KeyExchange == ecdh_anon ->
+is_acceptable_keyexchange(KeyExchange, _Algos) when KeyExchange == psk;
+ KeyExchange == null ->
+ true;
+is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == dh_anon;
+ KeyExchange == dhe_psk ->
+ proplists:get_bool(dh, Algos);
+is_acceptable_keyexchange(dhe_dss, Algos) ->
+ proplists:get_bool(dh, Algos) andalso
+ proplists:get_bool(dss, Algos);
+is_acceptable_keyexchange(dhe_rsa, Algos) ->
+ proplists:get_bool(dh, Algos) andalso
+ proplists:get_bool(rsa, Algos);
+is_acceptable_keyexchange(ecdh_anon, Algos) ->
proplists:get_bool(ecdh, Algos);
-is_acceptable_keyexchange(_, _) ->
- true.
-
+is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdhe_ecdsa ->
+ proplists:get_bool(ecdh, Algos) andalso
+ proplists:get_bool(ecdsa, Algos);
+is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_rsa;
+ KeyExchange == ecdhe_rsa ->
+ proplists:get_bool(ecdh, Algos) andalso
+ proplists:get_bool(rsa, Algos);
+is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == rsa;
+ KeyExchange == rsa_psk ->
+ proplists:get_bool(rsa, Algos);
+is_acceptable_keyexchange(srp_anon, Algos) ->
+ proplists:get_bool(srp, Algos);
+is_acceptable_keyexchange(srp_dss, Algos) ->
+ proplists:get_bool(srp, Algos) andalso
+ proplists:get_bool(dss, Algos);
+is_acceptable_keyexchange(srp_rsa, Algos) ->
+ proplists:get_bool(srp, Algos) andalso
+ proplists:get_bool(rsa, Algos);
+is_acceptable_keyexchange(_KeyExchange, _Algos) ->
+ false.
+
+is_acceptable_cipher(null, _Algos) ->
+ true;
+is_acceptable_cipher(rc4_128, Algos) ->
+ proplists:get_bool(rc4, Algos);
+is_acceptable_cipher(des_cbc, Algos) ->
+ proplists:get_bool(des_cbc, Algos);
+is_acceptable_cipher('3des_ede_cbc', Algos) ->
+ proplists:get_bool(des3_cbc, Algos);
+is_acceptable_cipher(aes_128_cbc, Algos) ->
+ proplists:get_bool(aes_cbc128, Algos);
+is_acceptable_cipher(aes_256_cbc, Algos) ->
+ proplists:get_bool(aes_cbc256, Algos);
is_acceptable_cipher(Cipher, Algos)
when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
proplists:get_bool(aes_gcm, Algos);
-is_acceptable_cipher(Cipher, Algos)
- when Cipher == chacha20_poly1305 ->
- proplists:get_bool(Cipher, Algos);
-is_acceptable_cipher(_, _) ->
- true.
+is_acceptable_cipher(Cipher, Algos) ->
+ proplists:get_bool(Cipher, Algos).
is_acceptable_hash(null, _Algos) ->
true;
@@ -1484,9 +1531,36 @@ is_fallback(CipherSuites)->
random_bytes(N) ->
crypto:strong_rand_bytes(N).
+calc_aad(Type, {MajVer, MinVer},
+ #{sequence_number := SeqNo}) ->
+ <<SeqNo:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
+
+calc_mac_hash(Type, Version,
+ PlainFragment, #{sequence_number := SeqNo,
+ mac_secret := MacSecret,
+ security_parameters:=
+ SecPars}) ->
+ Length = erlang:iolist_size(PlainFragment),
+ mac_hash(Version, SecPars#security_parameters.mac_algorithm,
+ MacSecret, SeqNo, Type,
+ Length, PlainFragment).
+
+is_stream_ciphersuite({_, rc4_128, _, _}) ->
+ true;
+is_stream_ciphersuite(_) ->
+ false.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
+ _Length, _Fragment) ->
+ <<>>;
+mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
+ ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
+mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
+ when N =:= 1; N =:= 2; N =:= 3 ->
+ tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
+ Length, Fragment).
bulk_cipher_algorithm(null) ->
?NULL;
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 0652d029c3..e4611995ec 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,18 +32,20 @@ init(SslOpts, Role) ->
init_manager_name(SslOpts#ssl_options.erl_dist),
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbHandle, OwnCert}
+ {ok, #{pem_cache := PemCache} = Config}
= init_certificates(SslOpts, Role),
PrivateKey =
- init_private_key(PemCacheHandle, SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
+ init_private_key(PemCache, SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
SslOpts#ssl_options.password, Role),
- DHParams = init_diffie_hellman(PemCacheHandle, SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
- {ok, CertDbRef, CertDbHandle, FileRefHandle, CacheHandle, CRLDbHandle, OwnCert, PrivateKey, DHParams}.
+ DHParams = init_diffie_hellman(PemCache, SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
+ {ok, Config#{private_key => PrivateKey, dh_params => DHParams}}.
init_manager_name(false) ->
- put(ssl_manager, ssl_manager:manager_name(normal));
+ put(ssl_manager, ssl_manager:name(normal)),
+ put(ssl_pem_cache, ssl_pem_cache:name(normal));
init_manager_name(true) ->
- put(ssl_manager, ssl_manager:manager_name(dist)).
+ put(ssl_manager, ssl_manager:name(dist)),
+ put(ssl_pem_cache, ssl_pem_cache:name(dist)).
init_certificates(#ssl_options{cacerts = CaCerts,
cacertfile = CACertFile,
@@ -51,7 +53,7 @@ init_certificates(#ssl_options{cacerts = CaCerts,
cert = Cert,
crl_cache = CRLCache
}, Role) ->
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo} =
+ {ok, Config} =
try
Certs = case CaCerts of
undefined ->
@@ -59,41 +61,37 @@ init_certificates(#ssl_options{cacerts = CaCerts,
_ ->
{der, CaCerts}
end,
- {ok, _, _, _, _, _, _} = ssl_manager:connection_init(Certs, Role, CRLCache)
+ {ok,_} = ssl_manager:connection_init(Certs, Role, CRLCache)
catch
_:Reason ->
file_error(CACertFile, {cacertfile, Reason})
end,
- init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle,
- CacheHandle, CRLDbInfo, CertFile, Role).
+ init_certificates(Cert, Config, CertFile, Role).
-init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle,
- CRLDbInfo, <<>>, _) ->
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo, undefined};
+init_certificates(undefined, Config, <<>>, _) ->
+ {ok, Config#{own_certificate => undefined}};
-init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle,
- CacheHandle, CRLDbInfo, CertFile, client) ->
+init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, client) ->
try
%% Ignoring potential proxy-certificates see:
%% http://dev.globus.org/wiki/Security/ProxyFileFormat
- [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo, OwnCert}
+ [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCache),
+ {ok, Config#{own_certificate => OwnCert}}
catch _Error:_Reason ->
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo, undefined}
- end;
+ {ok, Config#{own_certificate => undefined}}
+ end;
-init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle,
- PemCacheHandle, CacheRef, CRLDbInfo, CertFile, server) ->
+init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server) ->
try
- [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CRLDbInfo, OwnCert}
+ [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCache),
+ {ok, Config#{own_certificate => OwnCert}}
catch
_:Reason ->
file_error(CertFile, {certfile, Reason})
end;
-init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CRLDbInfo, _, _) ->
- {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CRLDbInfo, Cert}.
-
+init_certificates(Cert, Config, _, _) ->
+ {ok, Config#{own_certificate => Cert}}.
+
init_private_key(_, undefined, <<>>, _Password, _Client) ->
undefined;
init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
@@ -135,6 +133,8 @@ file_error(File, Throw) ->
case Throw of
{Opt,{badmatch, {error, {badmatch, Error}}}} ->
throw({options, {Opt, binary_to_list(File), Error}});
+ {Opt, {badmatch, Error}} ->
+ throw({options, {Opt, binary_to_list(File), Error}});
_ ->
throw(Throw)
end.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 53282998d0..2db9172d50 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@
-export([send/2, recv/3, close/2, shutdown/2,
new_user/2, get_opts/2, set_opts/2, session_info/1,
peer_certificate/1, renegotiation/1, negotiated_protocol/1, prf/5,
- connection_information/1
+ connection_information/1, handle_common_event/5
]).
%% General gen_statem state functions with extra callback argument
@@ -58,13 +58,21 @@
-export([handle_info/3, handle_call/5, handle_session/7, ssl_config/3,
prepare_connection/2, hibernate_after/3]).
+%% Alert and close handling
+-export([handle_own_alert/4,handle_alert/3,
+ handle_normal_shutdown/3
+ ]).
+
+%% Data handling
+-export([write_application_data/3, read_application_data/2]).
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
-spec connect(tls_connection | dtls_connection,
- host(), inet:port_number(), port(),
+ host(), inet:port_number(),
+ port() | {tuple(), port()}, %% TLS | DTLS
{#ssl_options{}, #socket_options{},
%% Tracker only needed on server side
undefined},
@@ -138,14 +146,24 @@ socket_control(Connection, Socket, Pid, Transport) ->
-spec socket_control(tls_connection | dtls_connection, port(), pid(), atom(), pid()| undefined) ->
{ok, #sslsocket{}} | {error, reason()}.
%%--------------------------------------------------------------------
-socket_control(Connection, Socket, Pid, Transport, ListenTracker) ->
+socket_control(Connection, Socket, Pid, Transport, udp_listner) ->
+ %% dtls listner process must have the socket control
+ {ok, Connection:socket(Pid, Transport, Socket, Connection, undefined)};
+
+socket_control(tls_connection = Connection, Socket, Pid, Transport, ListenTracker) ->
+ case Transport:controlling_process(Socket, Pid) of
+ ok ->
+ {ok, Connection:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+socket_control(dtls_connection = Connection, {_, Socket}, Pid, Transport, ListenTracker) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, ssl_socket:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {ok, Connection:socket(Pid, Transport, Socket, Connection, ListenTracker)};
{error, Reason} ->
{error, Reason}
end.
-
%%--------------------------------------------------------------------
-spec send(pid(), iodata()) -> ok | {error, reason()}.
%%
@@ -264,7 +282,7 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
%%--------------------------------------------------------------------
-spec handle_session(#server_hello{}, ssl_record:ssl_version(),
- binary(), #connection_states{}, _,_, #state{}) ->
+ binary(), ssl_record:connection_states(), _,_, #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
handle_session(#server_hello{cipher_suite = CipherSuite,
@@ -272,19 +290,21 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
Version, NewId, ConnectionStates, ProtoExt, Protocol0,
#state{session = #session{session_id = OldId},
negotiated_version = ReqVersion,
- negotiated_protocol = CurrentProtocol} = State0) ->
+ negotiated_protocol = CurrentProtocol} = State0) ->
{KeyAlgorithm, _, _, _} =
ssl_cipher:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
- {ExpectNPN, Protocol} = case Protocol0 of
- undefined -> {false, CurrentProtocol};
- _ -> {ProtoExt =:= npn, Protocol0}
- end,
+ {ExpectNPN, Protocol} = case Protocol0 of
+ undefined ->
+ {false, CurrentProtocol};
+ _ ->
+ {ProtoExt =:= npn, Protocol0}
+ end,
State = State0#state{key_algorithm = KeyAlgorithm,
- negotiated_version = Version,
+ negotiated_version = Version,
connection_states = ConnectionStates,
premaster_secret = PremasterSecret,
expecting_next_protocol_negotiation = ExpectNPN,
@@ -303,8 +323,14 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
-spec ssl_config(#ssl_options{}, client | server, #state{}) -> #state{}.
%%--------------------------------------------------------------------
ssl_config(Opts, Role, State) ->
- {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbInfo,
- OwnCert, Key, DHParams} =
+ {ok, #{cert_db_ref := Ref,
+ cert_db_handle := CertDbHandle,
+ fileref_db_handle := FileRefHandle,
+ session_cache := CacheHandle,
+ crl_db_info := CRLDbHandle,
+ private_key := Key,
+ dh_params := DHParams,
+ own_certificate := OwnCert}} =
ssl_config:init(Opts, Role),
Handshake = ssl_handshake:init_handshake_history(),
TimeStamp = erlang:monotonic_time(),
@@ -315,7 +341,7 @@ ssl_config(Opts, Role, State) ->
file_ref_db = FileRefHandle,
cert_db_ref = Ref,
cert_db = CertDbHandle,
- crl_db = CRLDbInfo,
+ crl_db = CRLDbHandle,
session_cache = CacheHandle,
private_key = Key,
diffie_hellman_params = DHParams,
@@ -337,11 +363,13 @@ init({call, From}, {start, Timeout}, State0, Connection) ->
timer = Timer}),
Connection:next_event(hello, Record, State);
init({call, From}, {start, {Opts, EmOpts}, Timeout},
- #state{role = Role} = State0, Connection) ->
+ #state{role = Role, ssl_options = OrigSSLOptions,
+ socket_options = SockOpts} = State0, Connection) ->
try
- State = ssl_config(Opts, Role, State0),
+ SslOpts = ssl:handle_options(Opts, OrigSSLOptions),
+ State = ssl_config(SslOpts, Role, State0),
init({call, From}, {start, Timeout},
- State#state{ssl_options = Opts, socket_options = EmOpts}, Connection)
+ State#state{ssl_options = SslOpts, socket_options = new_emulated(EmOpts, SockOpts)}, Connection)
catch throw:Error ->
{stop_and_reply, normal, {reply, From, {error, Error}}}
end;
@@ -382,7 +410,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished,
session = #session{master_secret = MasterSecret},
connection_states = ConnectionStates0} =
State0, Connection) ->
- case ssl_handshake:verify_connection(Version, Finished, client,
+ case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, client,
get_current_prf(ConnectionStates0, write),
MasterSecret, Handshake) of
verified ->
@@ -392,7 +420,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished,
expecting_finished = false}, Connection),
Connection:next_event(connection, Record, State);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, abbreviated, State0)
+ handle_own_alert(Alert, Version, abbreviated, State0)
end;
abbreviated(internal, #finished{verify_data = Data} = Finished,
@@ -400,19 +428,19 @@ abbreviated(internal, #finished{verify_data = Data} = Finished,
session = #session{master_secret = MasterSecret},
negotiated_version = Version,
connection_states = ConnectionStates0} = State0, Connection) ->
- case ssl_handshake:verify_connection(Version, Finished, server,
+ case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, server,
get_pending_prf(ConnectionStates0, write),
MasterSecret, Handshake0) of
verified ->
ConnectionStates1 =
ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0),
- State1 =
+ {State1, Actions} =
finalize_handshake(State0#state{connection_states = ConnectionStates1},
abbreviated, Connection),
{Record, State} = prepare_connection(State1#state{expecting_finished = false}, Connection),
- Connection:next_event(connection, Record, State);
+ Connection:next_event(connection, Record, State, Actions);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, abbreviated, State0)
+ handle_own_alert(Alert, Version, abbreviated, State0)
end;
%% only allowed to send next_protocol message after change cipher spec
@@ -452,9 +480,9 @@ certify(internal, #certificate{asn1_certificates = []},
#state{role = server, negotiated_version = Version,
ssl_options = #ssl_options{verify = verify_peer,
fail_if_no_peer_cert = true}} =
- State, Connection) ->
+ State, _) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
- Connection:handle_own_alert(Alert, Version, certify, State);
+ handle_own_alert(Alert, Version, certify, State);
certify(internal, #certificate{asn1_certificates = []},
#state{role = server,
@@ -469,9 +497,9 @@ certify(internal, #certificate{},
#state{role = server,
negotiated_version = Version,
ssl_options = #ssl_options{verify = verify_none}} =
- State, Connection) ->
+ State, _) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate),
- Connection:handle_own_alert(Alert, Version, certify, State);
+ handle_own_alert(Alert, Version, certify, State);
certify(internal, #certificate{} = Cert,
#state{negotiated_version = Version,
@@ -492,7 +520,7 @@ certify(internal, #certificate{} = Cert,
handle_peer_cert(Role, PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false}, Connection);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State)
+ handle_own_alert(Alert, Version, certify, State)
end;
certify(internal, #server_key_exchange{exchange_keys = Keys},
@@ -506,10 +534,10 @@ certify(internal, #server_key_exchange{exchange_keys = Keys},
Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
- Params = ssl_handshake:decode_server_key(Keys, Alg, Version),
+ Params = ssl_handshake:decode_server_key(Keys, Alg, ssl:tls_version(Version)),
%% Use negotiated value if TLS-1.2 otherwhise return default
- HashSign = negotiated_hashsign(Params#server_key_params.hashsign, Alg, PubKeyInfo, Version),
+ HashSign = negotiated_hashsign(Params#server_key_params.hashsign, Alg, PubKeyInfo, ssl:tls_version(Version)),
case is_anonymous(Alg) of
true ->
@@ -517,26 +545,25 @@ certify(internal, #server_key_exchange{exchange_keys = Keys},
State#state{hashsign_algorithm = HashSign}, Connection);
false ->
case ssl_handshake:verify_server_key(Params, HashSign,
- ConnectionStates, Version, PubKeyInfo) of
+ ConnectionStates, ssl:tls_version(Version), PubKeyInfo) of
true ->
calculate_secret(Params#server_key_params.params,
State#state{hashsign_algorithm = HashSign},
Connection);
false ->
- Connection:handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR),
+ handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR),
Version, certify, State)
end
end;
-certify(internal, #certificate_request{hashsign_algorithms = HashSigns},
+certify(internal, #certificate_request{} = CertRequest,
#state{session = #session{own_certificate = Cert},
- key_algorithm = KeyExAlg,
+ role = client,
ssl_options = #ssl_options{signature_algs = SupportedHashSigns},
negotiated_version = Version} = State0, Connection) ->
-
- case ssl_handshake:select_hashsign(HashSigns, Cert, KeyExAlg, SupportedHashSigns, Version) of
+ case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of
#alert {} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0);
+ handle_own_alert(Alert, Version, certify, State0);
NegotiatedHashSign ->
{Record, State} = Connection:next_record(State0#state{client_certificate_requested = true}),
Connection:next_event(certify, Record,
@@ -555,7 +582,7 @@ certify(internal, #server_hello_done{},
when Alg == psk ->
case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup) of
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0);
+ handle_own_alert(Alert, Version, certify, State0);
PremasterSecret ->
State = master_secret(PremasterSecret,
State0#state{premaster_secret = PremasterSecret}),
@@ -576,7 +603,7 @@ certify(internal, #server_hello_done{},
case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup,
RSAPremasterSecret) of
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0);
+ handle_own_alert(Alert, Version, certify, State0);
PremasterSecret ->
State = master_secret(PremasterSecret,
State0#state{premaster_secret = RSAPremasterSecret}),
@@ -590,13 +617,13 @@ certify(internal, #server_hello_done{},
negotiated_version = Version,
premaster_secret = undefined,
role = client} = State0, Connection) ->
- case ssl_handshake:master_secret(record_cb(Connection), Version, Session,
+ case ssl_handshake:master_secret(ssl:tls_version(Version), Session,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
State = State0#state{connection_states = ConnectionStates},
client_certify_and_key_exchange(State, Connection);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0)
+ handle_own_alert(Alert, Version, certify, State0)
end;
%% Master secret is calculated from premaster_secret
@@ -606,7 +633,7 @@ certify(internal, #server_hello_done{},
negotiated_version = Version,
premaster_secret = PremasterSecret,
role = client} = State0, Connection) ->
- case ssl_handshake:master_secret(record_cb(Connection), Version, PremasterSecret,
+ case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
@@ -614,7 +641,7 @@ certify(internal, #server_hello_done{},
session = Session},
client_certify_and_key_exchange(State, Connection);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0)
+ handle_own_alert(Alert, Version, certify, State0)
end;
certify(internal = Type, #client_key_exchange{} = Msg,
@@ -628,11 +655,11 @@ certify(internal = Type, #client_key_exchange{} = Msg,
certify(internal, #client_key_exchange{exchange_keys = Keys},
State = #state{key_algorithm = KeyAlg, negotiated_version = Version}, Connection) ->
try
- certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version),
+ certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, ssl:tls_version(Version)),
State, Connection)
catch
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State)
+ handle_own_alert(Alert, Version, certify, State)
end;
certify(Type, Msg, State, Connection) ->
@@ -663,21 +690,21 @@ cipher(internal, #certificate_verify{signature = Signature,
%% Use negotiated value if TLS-1.2 otherwhise return default
HashSign = negotiated_hashsign(CertHashSign, KexAlg, PublicKeyInfo, Version),
case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
- Version, HashSign, MasterSecret, Handshake) of
+ ssl:tls_version(Version), HashSign, MasterSecret, Handshake) of
valid ->
{Record, State} = Connection:next_record(State0),
Connection:next_event(cipher, Record,
State#state{cert_hashsign_algorithm = HashSign});
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, cipher, State0)
+ handle_own_alert(Alert, Version, cipher, State0)
end;
%% client must send a next protocol message if we are expecting it
cipher(internal, #finished{},
#state{role = server, expecting_next_protocol_negotiation = true,
negotiated_protocol = undefined, negotiated_version = Version} = State0,
- Connection) ->
- Connection:handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, cipher, State0);
+ _Connection) ->
+ handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, cipher, State0);
cipher(internal, #finished{verify_data = Data} = Finished,
#state{negotiated_version = Version,
@@ -689,7 +716,7 @@ cipher(internal, #finished{verify_data = Data} = Finished,
= Session0,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State, Connection) ->
- case ssl_handshake:verify_connection(Version, Finished,
+ case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished,
opposite_role(Role),
get_current_prf(ConnectionStates0, read),
MasterSecret, Handshake0) of
@@ -698,7 +725,7 @@ cipher(internal, #finished{verify_data = Data} = Finished,
cipher_role(Role, Data, Session,
State#state{expecting_finished = false}, Connection);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, cipher, State)
+ handle_own_alert(Alert, Version, cipher, State)
end;
%% only allowed to send next_protocol message after change cipher spec
@@ -731,7 +758,7 @@ connection({call, From}, {application_data, Data},
%% parallize send and receive decoding and not block the receiver
%% if sending is overloading the socket.
try
- Connection:write_application_data(Data, From, State)
+ write_application_data(Data, From, State)
catch throw:Error ->
hibernate_after(connection, State, [{reply, From, Error}])
end;
@@ -780,7 +807,7 @@ connection(Type, Msg, State, Connection) ->
downgrade(internal, #alert{description = ?CLOSE_NOTIFY},
#state{transport_cb = Transport, socket = Socket,
downgrade = {Pid, From}} = State, _) ->
- ssl_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]),
+ tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]),
Transport:controlling_process(Socket, Pid),
gen_statem:reply(From, {ok, Socket}),
{stop, normal, State};
@@ -802,35 +829,37 @@ handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName, #st
when StateName =/= connection ->
{keep_state_and_data};
handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName,
- #state{tls_handshake_history = Hs0} = State0, Connection) ->
+ #state{tls_handshake_history = Hs0,
+ ssl_options = #ssl_options{v2_hello_compatible = V2HComp}} = State0,
+ Connection) ->
+
+ PossibleSNI = Connection:select_sni_extension(Handshake),
%% This function handles client SNI hello extension when Handshake is
%% a client_hello, which needs to be determined by the connection callback.
%% In other cases this is a noop
- State = Connection:handle_sni_extension(Handshake, State0),
- HsHist = ssl_handshake:update_handshake_history(Hs0, Raw),
+ State = handle_sni_extension(PossibleSNI, State0),
+ HsHist = ssl_handshake:update_handshake_history(Hs0, iolist_to_binary(Raw), V2HComp),
{next_state, StateName, State#state{tls_handshake_history = HsHist},
[{next_event, internal, Handshake}]};
-handle_common_event(internal, {tls_record, TLSRecord}, StateName, State, Connection) ->
- Connection:handle_common_event(internal, TLSRecord, StateName, State);
+handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, State, Connection) ->
+ Connection:handle_common_event(internal, TLSorDTLSRecord, StateName, State);
handle_common_event(timeout, hibernate, _, _, _) ->
{keep_state_and_data, [hibernate]};
handle_common_event(internal, {application_data, Data}, StateName, State0, Connection) ->
- case Connection:read_application_data(Data, State0) of
+ case read_application_data(Data, State0) of
{stop, Reason, State} ->
{stop, Reason, State};
{Record, State} ->
Connection:next_event(StateName, Record, State)
end;
handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName,
- #state{negotiated_version = Version} = State, Connection) ->
- Connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version,
+ #state{negotiated_version = Version} = State, _) ->
+ handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version,
StateName, State);
-handle_common_event(internal, _, _, _, _) ->
- {keep_state_and_data, [postpone]};
handle_common_event(_Type, Msg, StateName, #state{negotiated_version = Version} = State,
- Connection) ->
- Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
- Connection:handle_own_alert(Alert, Version, {StateName, Msg}, State).
+ _) ->
+ Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, {unexpected_msg, Msg}),
+ handle_own_alert(Alert, Version, StateName, State).
handle_call({application_data, _Data}, _, _, _, _) ->
%% In renegotiation priorities handshake, send data when handshake is finished
@@ -843,24 +872,24 @@ handle_call({close, {Pid, Timeout}}, From, StateName, State0, Connection) when i
%% When downgrading an TLS connection to a transport connection
%% we must recive the close alert from the peer before releasing the
%% transport socket.
- {next_state, downgrade, State, [{timeout, Timeout, downgrade}]};
+ {next_state, downgrade, State#state{terminated = true}, [{timeout, Timeout, downgrade}]};
handle_call({close, _} = Close, From, StateName, State, Connection) ->
%% Run terminate before returning so that the reuseaddr
- %% inet-option
- Result = Connection:terminate(Close, StateName, State),
+ %% inet-option works properly
+ Result = Connection:terminate(Close, StateName, State#state{terminated = true}),
{stop_and_reply, {shutdown, normal},
{reply, From, Result}, State};
handle_call({shutdown, How0}, From, _,
#state{transport_cb = Transport,
negotiated_version = Version,
connection_states = ConnectionStates,
- socket = Socket}, _) ->
+ socket = Socket}, Connection) ->
case How0 of
How when How == write; How == both ->
Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
{BinMsg, _} =
- ssl_alert:encode(Alert, Version, ConnectionStates),
- Transport:send(Socket, BinMsg);
+ Connection:encode_alert(Alert, Version, ConnectionStates),
+ Connection:send(Transport, Socket, BinMsg);
_ ->
ok
end,
@@ -908,9 +937,8 @@ handle_call(renegotiate, From, StateName, _, _) when StateName =/= connection ->
handle_call({prf, Secret, Label, Seed, WantedLength}, From, _,
#state{connection_states = ConnectionStates,
negotiated_version = Version}, _) ->
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:current_connection_state(ConnectionStates, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{master_secret = MasterSecret,
client_random = ClientRandom,
server_random = ServerRandom,
@@ -925,7 +953,7 @@ handle_call({prf, Secret, Label, Seed, WantedLength}, From, _,
(client_random, Acc) -> [ClientRandom|Acc];
(server_random, Acc) -> [ServerRandom|Acc]
end, [], Seed)),
- ssl_handshake:prf(Version, PRFAlgorithm, SecretToUse, Label, SeedToUse, WantedLength)
+ ssl_handshake:prf(ssl:tls_version(Version), PRFAlgorithm, SecretToUse, Label, SeedToUse, WantedLength)
catch
exit:_ -> {error, badarg};
error:Reason -> {error, Reason}
@@ -936,20 +964,19 @@ handle_call(_,_,_,_,_) ->
handle_info({ErrorTag, Socket, econnaborted}, StateName,
#state{socket = Socket, transport_cb = Transport,
- start_or_recv_from = StartFrom, role = Role,
protocol_cb = Connection,
+ start_or_recv_from = StartFrom, role = Role,
error_tag = ErrorTag,
tracker = Tracker} = State) when StateName =/= connection ->
- Connection:alert_user(Transport, Tracker,Socket,
- StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role),
+ alert_user(Transport, Tracker,Socket,
+ StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection),
{stop, normal, State};
handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
- protocol_cb = Connection,
error_tag = ErrorTag} = State) ->
Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]),
error_logger:info_report(Report),
- Connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
{stop, normal, State};
handle_info({'DOWN', MonitorRef, _, _, _}, _,
@@ -991,7 +1018,10 @@ handle_info(Msg, StateName, #state{socket = Socket, error_tag = Tag} = State) ->
terminate(_, _, #state{terminated = true}) ->
%% Happens when user closes the connection using ssl:close/1
%% we want to guarantee that Transport:close has been called
- %% when ssl:close/1 returns.
+ %% when ssl:close/1 returns unless it is a downgrade where
+ %% we want to guarantee that close alert is recived before
+ %% returning. In both cases terminate has been run manually
+ %% before run by gen_statem which will end up here
ok;
terminate({shutdown, transport_closed} = Reason,
@@ -1017,8 +1047,8 @@ terminate(Reason, connection, #state{negotiated_version = Version,
transport_cb = Transport, socket = Socket
} = State) ->
handle_trusted_certs_db(State),
- {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0),
- Transport:send(Socket, BinAlert),
+ {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0, Connection),
+ Connection:send(Transport, Socket, BinAlert),
Connection:close(Reason, Socket, Transport, ConnectionStates, Check);
terminate(Reason, _StateName, #state{transport_cb = Transport, protocol_cb = Connection,
@@ -1052,15 +1082,135 @@ format_status(terminate, [_, StateName, State]) ->
ssl_options = NewOptions,
flight_buffer = ?SECRET_PRINTOUT}
}}]}].
+
+%%--------------------------------------------------------------------
+%%%
+%%--------------------------------------------------------------------
+write_application_data(Data0, From,
+ #state{socket = Socket,
+ negotiated_version = Version,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0,
+ socket_options = SockOpts,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State) ->
+ Data = encode_packet(Data0, SockOpts),
+
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ Connection:renegotiate(State#state{renegotiation = {true, internal}},
+ [{next_event, {call, From}, {application_data, Data0}}]);
+ false ->
+ {Msgs, ConnectionStates} = Connection:encode_data(Data, Version, ConnectionStates0),
+ Result = Connection:send(Transport, Socket, Msgs),
+ ssl_connection:hibernate_after(connection, State#state{connection_states = ConnectionStates},
+ [{reply, From, Result}])
+ end.
+
+read_application_data(Data, #state{user_application = {_Mon, Pid},
+ socket = Socket,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ socket_options = SOpts,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ timer = Timer,
+ user_data_buffer = Buffer0,
+ tracker = Tracker} = State0) ->
+ Buffer1 = if
+ Buffer0 =:= <<>> -> Data;
+ Data =:= <<>> -> Buffer0;
+ true -> <<Buffer0/binary, Data/binary>>
+ end,
+ case get_data(SOpts, BytesToRead, Buffer1) of
+ {ok, ClientData, Buffer} -> % Send data
+ SocketOpt = deliver_app_data(Transport, Socket, SOpts,
+ ClientData, Pid, RecvFrom, Tracker, Connection),
+ cancel_timer(Timer),
+ State = State0#state{user_data_buffer = Buffer,
+ start_or_recv_from = undefined,
+ timer = undefined,
+ bytes_to_read = undefined,
+ socket_options = SocketOpt
+ },
+ if
+ SocketOpt#socket_options.active =:= false; Buffer =:= <<>> ->
+ %% Passive mode, wait for active once or recv
+ %% Active and empty, get more data
+ Connection:next_record_if_active(State);
+ true -> %% We have more data
+ read_application_data(<<>>, State)
+ end;
+ {more, Buffer} -> % no reply, we need more data
+ Connection:next_record(State0#state{user_data_buffer = Buffer});
+ {passive, Buffer} ->
+ Connection:next_record_if_active(State0#state{user_data_buffer = Buffer});
+ {error,_Reason} -> %% Invalid packet in packet mode
+ deliver_packet_error(Transport, Socket, SOpts, Buffer1, Pid, RecvFrom, Tracker, Connection),
+ {stop, normal, State0}
+ end.
+%%--------------------------------------------------------------------
+%%%
+%%--------------------------------------------------------------------
+handle_alert(#alert{level = ?FATAL} = Alert, StateName,
+ #state{socket = Socket, transport_cb = Transport,
+ protocol_cb = Connection,
+ ssl_options = SslOpts, start_or_recv_from = From, host = Host,
+ port = Port, session = Session, user_application = {_Mon, Pid},
+ role = Role, socket_options = Opts, tracker = Tracker}) ->
+ invalidate_session(Role, Host, Port, Session),
+ log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
+ alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, Connection),
+ {stop, normal};
+
+handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
+ StateName, State) ->
+ handle_normal_shutdown(Alert, StateName, State),
+ {stop, {shutdown, peer_close}};
+
+handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
+ #state{ssl_options = SslOpts, renegotiation = {true, internal}} = State) ->
+ log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
+ handle_normal_shutdown(Alert, StateName, State),
+ {stop, {shutdown, peer_close}};
+
+handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
+ #state{ssl_options = SslOpts, renegotiation = {true, From},
+ protocol_cb = Connection} = State0) ->
+ log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
+ gen_statem:reply(From, {error, renegotiation_rejected}),
+ {Record, State} = Connection:next_record(State0),
+ %% Go back to connection!
+ Connection:next_event(connection, Record, State);
+
+%% Gracefully log and ignore all other warning alerts
+handle_alert(#alert{level = ?WARNING} = Alert, StateName,
+ #state{ssl_options = SslOpts, protocol_cb = Connection} = State0) ->
+ log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
+ {Record, State} = Connection:next_record(State0),
+ Connection:next_event(StateName, Record, State).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
connection_info(#state{sni_hostname = SNIHostname,
- session = #session{cipher_suite = CipherSuite},
- negotiated_version = Version, ssl_options = Opts}) ->
- [{protocol, tls_record:protocol_version(Version)},
- {cipher_suite, ssl_cipher:erl_suite_definition(CipherSuite)},
- {sni_hostname, SNIHostname}] ++ ssl_options_list(Opts).
+ session = #session{cipher_suite = CipherSuite, ecc = ECCCurve},
+ protocol_cb = Connection,
+ negotiated_version = {_,_} = Version,
+ ssl_options = Opts}) ->
+ RecordCB = record_cb(Connection),
+ CipherSuiteDef = ssl_cipher:erl_suite_definition(CipherSuite),
+ IsNamedCurveSuite = lists:member(element(1,CipherSuiteDef),
+ [ecdh_ecdsa, ecdhe_ecdsa, ecdh_anon]),
+ CurveInfo = case ECCCurve of
+ {namedCurve, Curve} when IsNamedCurveSuite ->
+ [{ecc, {named_curve, pubkey_cert_records:namedCurves(Curve)}}];
+ _ ->
+ []
+ end,
+ [{protocol, RecordCB:protocol_version(Version)},
+ {cipher_suite, CipherSuiteDef},
+ {sni_hostname, SNIHostname} | CurveInfo] ++ ssl_options_list(Opts).
do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocols} =
ServerHelloExt,
@@ -1070,7 +1220,7 @@ do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocol
= State0, Connection) when is_atom(Type) ->
ServerHello =
- ssl_handshake:server_hello(SessId, Version, ConnectionStates0, ServerHelloExt),
+ ssl_handshake:server_hello(SessId, ssl:tls_version(Version), ConnectionStates0, ServerHelloExt),
State = server_hello(ServerHello,
State0#state{expecting_next_protocol_negotiation =
NextProtocols =/= undefined}, Connection),
@@ -1088,33 +1238,33 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite,
negotiated_version = Version} = State0, Connection) ->
try server_certify_and_key_exchange(State0, Connection) of
#state{} = State1 ->
- State2 = server_hello_done(State1, Connection),
+ {State2, Actions} = server_hello_done(State1, Connection),
Session =
Session0#session{session_id = SessionId,
cipher_suite = CipherSuite,
compression_method = Compression},
{Record, State} = Connection:next_record(State2#state{session = Session}),
- Connection:next_event(certify, Record, State)
+ Connection:next_event(certify, Record, State, Actions)
catch
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, hello, State0)
+ handle_own_alert(Alert, Version, hello, State0)
end.
resumed_server_hello(#state{session = Session,
connection_states = ConnectionStates0,
negotiated_version = Version} = State0, Connection) ->
- case ssl_handshake:master_secret(record_cb(Connection), Version, Session,
+ case ssl_handshake:master_secret(ssl:tls_version(Version), Session,
ConnectionStates0, server) of
{_, ConnectionStates1} ->
State1 = State0#state{connection_states = ConnectionStates1,
session = Session},
- State2 =
+ {State2, Actions} =
finalize_handshake(State1, abbreviated, Connection),
{Record, State} = Connection:next_record(State2),
- Connection:next_event(abbreviated, Record, State);
+ Connection:next_event(abbreviated, Record, State, Actions);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, hello, State0)
+ handle_own_alert(Alert, Version, hello, State0)
end.
server_hello(ServerHello, State0, Connection) ->
@@ -1180,7 +1330,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
tls_handshake_history = Handshake0} = State, Connection) ->
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
- Version, HashSign, PrivateKey, Handshake0) of
+ ssl:tls_version(Version), HashSign, PrivateKey, Handshake0) of
#certificate_verify{} = Verified ->
Connection:queue_handshake(Verified, State);
ignore ->
@@ -1195,15 +1345,15 @@ client_certify_and_key_exchange(#state{negotiated_version = Version} =
State0, Connection) ->
try do_client_certify_and_key_exchange(State0, Connection) of
State1 = #state{} ->
- State2 = finalize_handshake(State1, certify, Connection),
+ {State2, Actions} = finalize_handshake(State1, certify, Connection),
State3 = State2#state{
%% Reinitialize
client_certificate_requested = false},
{Record, State} = Connection:next_record(State3),
- Connection:next_event(cipher, Record, State)
+ Connection:next_event(cipher, Record, State, Actions)
catch
throw:#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0)
+ handle_own_alert(Alert, Version, certify, State0)
end.
do_client_certify_and_key_exchange(State0, Connection) ->
@@ -1217,8 +1367,25 @@ server_certify_and_key_exchange(State0, Connection) ->
request_client_cert(State2, Connection).
certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS},
- #state{private_key = Key} = State, Connection) ->
- PremasterSecret = ssl_handshake:premaster_secret(EncPMS, Key),
+ #state{private_key = Key, client_hello_version = {Major, Minor} = Version} = State, Connection) ->
+
+ %% Countermeasure for Bleichenbacher attack always provide some kind of premaster secret
+ %% and fail handshake later.RFC 5246 section 7.4.7.1.
+ PremasterSecret =
+ try ssl_handshake:premaster_secret(EncPMS, Key) of
+ Secret when erlang:byte_size(Secret) == ?NUM_OF_PREMASTERSECRET_BYTES ->
+ case Secret of
+ <<?BYTE(Major), ?BYTE(Minor), _/binary>> -> %% Correct
+ Secret;
+ <<?BYTE(_), ?BYTE(_), Rest/binary>> -> %% Version mismatch
+ <<?BYTE(Major), ?BYTE(Minor), Rest/binary>>
+ end;
+ _ -> %% erlang:byte_size(Secret) =/= ?NUM_OF_PREMASTERSECRET_BYTES
+ make_premaster_secret(Version, rsa)
+ catch
+ #alert{description = ?DECRYPT_ERROR} ->
+ make_premaster_secret(Version, rsa)
+ end,
calculate_master_secret(PremasterSecret, State, Connection, certify, cipher);
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
@@ -1294,12 +1461,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Algo == dhe_rsa;
Algo == dh_anon ->
DHKeys = public_key:generate_key(Params),
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version), {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1312,22 +1478,23 @@ key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = St
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
private_key = PrivateKey,
+ session = #session{ecc = ECCCurve},
connection_states = ConnectionStates0,
negotiated_version = Version
} = State0, Connection)
when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
Algo == ecdh_anon ->
- ECDHKeys = public_key:generate_key(select_curve(State0)),
- ConnectionState =
+ ECDHKeys = public_key:generate_key(ECCCurve),
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
- HashSignAlgo, ClientRandom,
- ServerRandom,
- PrivateKey}),
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version),
+ {ecdh, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
State = Connection:queue_handshake(Msg, State0),
State#state{diffie_hellman_keys = ECDHKeys};
@@ -1341,14 +1508,14 @@ key_exchange(#state{role = server, key_algorithm = psk,
connection_states = ConnectionStates0,
negotiated_version = Version
} = State0, Connection) ->
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
- HashSignAlgo, ClientRandom,
- ServerRandom,
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version),
+ {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
PrivateKey}),
Connection:queue_handshake(Msg, State0);
@@ -1361,16 +1528,16 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
negotiated_version = Version
} = State0, Connection) ->
DHKeys = public_key:generate_key(Params),
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk,
- PskIdentityHint, DHKeys, Params,
- HashSignAlgo, ClientRandom,
- ServerRandom,
- PrivateKey}),
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version),
+ {dhe_psk,
+ PskIdentityHint, DHKeys, Params,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
State = Connection:queue_handshake(Msg, State0),
State#state{diffie_hellman_keys = DHKeys};
@@ -1384,15 +1551,15 @@ key_exchange(#state{role = server, key_algorithm = rsa_psk,
connection_states = ConnectionStates0,
negotiated_version = Version
} = State0, Connection) ->
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
- HashSignAlgo, ClientRandom,
- ServerRandom,
- PrivateKey}),
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version),
+ {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
Connection:queue_handshake(Msg, State0);
key_exchange(#state{role = server, key_algorithm = Algo,
@@ -1413,15 +1580,15 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Keys0 = {_,_} ->
Keys0
end,
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
- HashSignAlgo, ClientRandom,
- ServerRandom,
- PrivateKey}),
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version),
+ {srp, Keys, SrpParams,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
State = Connection:queue_handshake(Msg, State0),
State#state{srp_params = SrpParams,
srp_keys = Keys};
@@ -1431,7 +1598,7 @@ key_exchange(#state{role = client,
public_key_info = PublicKeyInfo,
negotiated_version = Version,
premaster_secret = PremasterSecret} = State0, Connection) ->
- Msg = rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo),
+ Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo),
Connection:queue_handshake(Msg, State0);
key_exchange(#state{role = client,
@@ -1442,7 +1609,7 @@ key_exchange(#state{role = client,
when Algorithm == dhe_dss;
Algorithm == dhe_rsa;
Algorithm == dh_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {dh, DhPubKey}),
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dh, DhPubKey}),
Connection:queue_handshake(Msg, State0);
key_exchange(#state{role = client,
@@ -1452,14 +1619,14 @@ key_exchange(#state{role = client,
when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
Algorithm == ecdh_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Keys}),
Connection:queue_handshake(Msg, State0);
key_exchange(#state{role = client,
ssl_options = SslOpts,
key_algorithm = psk,
negotiated_version = Version} = State0, Connection) ->
- Msg = ssl_handshake:key_exchange(client, Version,
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version),
{psk, SslOpts#ssl_options.psk_identity}),
Connection:queue_handshake(Msg, State0);
@@ -1468,7 +1635,7 @@ key_exchange(#state{role = client,
key_algorithm = dhe_psk,
negotiated_version = Version,
diffie_hellman_keys = {DhPubKey, _}} = State0, Connection) ->
- Msg = ssl_handshake:key_exchange(client, Version,
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version),
{dhe_psk,
SslOpts#ssl_options.psk_identity, DhPubKey}),
Connection:queue_handshake(Msg, State0);
@@ -1479,7 +1646,7 @@ key_exchange(#state{role = client,
negotiated_version = Version,
premaster_secret = PremasterSecret}
= State0, Connection) ->
- Msg = rsa_psk_key_exchange(Version, SslOpts#ssl_options.psk_identity,
+ Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity,
PremasterSecret, PublicKeyInfo),
Connection:queue_handshake(Msg, State0);
@@ -1491,7 +1658,7 @@ key_exchange(#state{role = client,
when Algorithm == srp_dss;
Algorithm == srp_rsa;
Algorithm == srp_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {srp, ClientPubKey}),
Connection:queue_handshake(Msg, State0).
rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
@@ -1504,7 +1671,7 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
Algorithm == ?sha384WithRSAEncryption;
Algorithm == ?sha512WithRSAEncryption
->
- ssl_handshake:key_exchange(client, Version,
+ ssl_handshake:key_exchange(client, ssl:tls_version(Version),
{premaster_secret, PremasterSecret,
PublicKeyInfo});
rsa_key_exchange(_, _, _) ->
@@ -1521,7 +1688,7 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret,
Algorithm == ?sha384WithRSAEncryption;
Algorithm == ?sha512WithRSAEncryption
->
- ssl_handshake:key_exchange(client, Version,
+ ssl_handshake:key_exchange(client, ssl:tls_version(Version),
{psk_premaster_secret, PskIdentity, PremasterSecret,
PublicKeyInfo});
rsa_psk_key_exchange(_, _, _, _) ->
@@ -1533,12 +1700,14 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
negotiated_version = Version} = State0, Connection) ->
- #connection_state{security_parameters =
- #security_parameters{cipher_suite = CipherSuite}} =
+ #{security_parameters :=
+ #security_parameters{cipher_suite = CipherSuite}} =
ssl_record:pending_connection_state(ConnectionStates0, read),
- HashSigns = ssl_handshake:available_signature_algs(SupportedHashSigns, Version, [Version]),
+ TLSVersion = ssl:tls_version(Version),
+ HashSigns = ssl_handshake:available_signature_algs(SupportedHashSigns,
+ TLSVersion, [TLSVersion]),
Msg = ssl_handshake:certificate_request(CipherSuite, CertDbHandle, CertDbRef,
- HashSigns, Version),
+ HashSigns, TLSVersion),
State = Connection:queue_handshake(Msg, State0),
State#state{client_certificate_requested = true};
@@ -1551,7 +1720,7 @@ calculate_master_secret(PremasterSecret,
connection_states = ConnectionStates0,
session = Session0} = State0, Connection,
_Current, Next) ->
- case ssl_handshake:master_secret(record_cb(Connection), Version, PremasterSecret,
+ case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret,
ConnectionStates0, server) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
@@ -1560,7 +1729,7 @@ calculate_master_secret(PremasterSecret,
{Record, State} = Connection:next_record(State1),
Connection:next_event(Next, Record, State);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, certify, State0)
+ handle_own_alert(Alert, Version, certify, State0)
end.
finalize_handshake(State0, StateName, Connection) ->
@@ -1593,7 +1762,7 @@ finished(#state{role = Role, negotiated_version = Version,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State0, StateName, Connection) ->
MasterSecret = Session#session.master_secret,
- Finished = ssl_handshake:finished(Version, Role,
+ Finished = ssl_handshake:finished(ssl:tls_version(Version), Role,
get_current_prf(ConnectionStates0, write),
MasterSecret, Handshake0),
ConnectionStates = save_verify_data(Role, Finished, ConnectionStates0, StateName),
@@ -1620,12 +1789,13 @@ calculate_secret(#server_dh_params{dh_p = Prime, dh_g = Base,
Connection, certify, certify);
calculate_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
- State, Connection) ->
+ State=#state{session=Session}, Connection) ->
ECDHKeys = public_key:generate_key(ECCurve),
PremasterSecret =
ssl_handshake:premaster_secret(#'ECPoint'{point = ECServerPubKey}, ECDHKeys),
calculate_master_secret(PremasterSecret,
- State#state{diffie_hellman_keys = ECDHKeys},
+ State#state{diffie_hellman_keys = ECDHKeys,
+ session = Session#session{ecc = ECCurve}},
Connection, certify, certify);
calculate_secret(#server_psk_params{
@@ -1658,7 +1828,7 @@ master_secret(#alert{} = Alert, _) ->
master_secret(PremasterSecret, #state{session = Session,
negotiated_version = Version, role = Role,
connection_states = ConnectionStates0} = State) ->
- case ssl_handshake:master_secret(tls_record, Version, PremasterSecret,
+ case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret,
ConnectionStates0, Role) of
{MasterSecret, ConnectionStates} ->
State#state{
@@ -1719,16 +1889,11 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0
Connection) ->
ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data,
ConnectionStates0),
- State1 =
+ {State1, Actions} =
finalize_handshake(State0#state{connection_states = ConnectionStates1,
session = Session}, cipher, Connection),
{Record, State} = prepare_connection(State1, Connection),
- Connection:next_event(connection, Record, State).
-
-select_curve(#state{client_ecc = {[Curve|_], _}}) ->
- {namedCurve, Curve};
-select_curve(_) ->
- {namedCurve, ?secp256r1}.
+ Connection:next_event(connection, Record, State, Actions).
is_anonymous(Algo) when Algo == dh_anon;
Algo == ecdh_anon;
@@ -1741,11 +1906,11 @@ is_anonymous(_) ->
false.
get_current_prf(CStates, Direction) ->
- CS = ssl_record:current_connection_state(CStates, Direction),
- CS#connection_state.security_parameters#security_parameters.prf_algorithm.
+ #{security_parameters := SecParams} = ssl_record:current_connection_state(CStates, Direction),
+ SecParams#security_parameters.prf_algorithm.
get_pending_prf(CStates, Direction) ->
- CS = ssl_record:pending_connection_state(CStates, Direction),
- CS#connection_state.security_parameters#security_parameters.prf_algorithm.
+ #{security_parameters := SecParams} = ssl_record:pending_connection_state(CStates, Direction),
+ SecParams#security_parameters.prf_algorithm.
opposite_role(client) ->
server;
@@ -1787,7 +1952,7 @@ get_socket_opts(Transport, Socket, [active | Tags], SockOpts, Acc) ->
get_socket_opts(Transport, Socket, Tags, SockOpts,
[{active, SockOpts#socket_options.active} | Acc]);
get_socket_opts(Transport, Socket, [Tag | Tags], SockOpts, Acc) ->
- try ssl_socket:getopts(Transport, Socket, [Tag]) of
+ try tls_socket:getopts(Transport, Socket, [Tag]) of
{ok, [Opt]} ->
get_socket_opts(Transport, Socket, Tags, SockOpts, [Opt | Acc]);
{error, Error} ->
@@ -1803,7 +1968,7 @@ set_socket_opts(_,_, [], SockOpts, []) ->
{ok, SockOpts};
set_socket_opts(Transport, Socket, [], SockOpts, Other) ->
%% Set non emulated options
- try ssl_socket:setopts(Transport, Socket, Other) of
+ try tls_socket:setopts(Transport, Socket, Other) of
ok ->
{ok, SockOpts};
{error, InetError} ->
@@ -1869,17 +2034,17 @@ hibernate_after(connection = StateName,
hibernate_after(StateName, State, Actions) ->
{next_state, StateName, State, Actions}.
-terminate_alert(normal, Version, ConnectionStates) ->
- ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+terminate_alert(normal, Version, ConnectionStates, Connection) ->
+ Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
Version, ConnectionStates);
-terminate_alert({Reason, _}, Version, ConnectionStates) when Reason == close;
- Reason == shutdown ->
- ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+terminate_alert({Reason, _}, Version, ConnectionStates, Connection) when Reason == close;
+ Reason == shutdown ->
+ Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
Version, ConnectionStates);
-terminate_alert(_, Version, ConnectionStates) ->
- {BinAlert, _} = ssl_alert:encode(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
- Version, ConnectionStates),
+terminate_alert(_, Version, ConnectionStates, Connection) ->
+ {BinAlert, _} = Connection:encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
+ Version, ConnectionStates),
BinAlert.
handle_trusted_certs_db(#state{ssl_options =
@@ -1967,7 +2132,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
session_cache = Cache,
session_cache_cb = CacheCb} = State0) ->
Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
- case ssl_handshake:master_secret(tls_record, Version, Session,
+ case ssl_handshake:master_secret(ssl:tls_version(Version), Session,
ConnectionStates0, client) of
{_, ConnectionStates} ->
{Record, State} =
@@ -1976,7 +2141,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
session = Session}),
Connection:next_event(abbreviated, Record, State);
#alert{} = Alert ->
- Connection:handle_own_alert(Alert, Version, hello, State0)
+ handle_own_alert(Alert, Version, hello, State0)
end.
make_premaster_secret({MajVer, MinVer}, rsa) ->
@@ -2043,7 +2208,7 @@ handle_active_option(_, StateName, To, Reply, #state{user_data_buffer = <<>>} =
%% user_data_buffer =/= <<>>
handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection} = State0) ->
- case Connection:read_application_data(<<>>, State0) of
+ case read_application_data(<<>>, State0) of
{stop, Reason, State} ->
{stop, Reason, State};
{Record, State1} ->
@@ -2057,3 +2222,277 @@ handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection}
Stop
end
end.
+
+encode_packet(Data, #socket_options{packet=Packet}) ->
+ case Packet of
+ 1 -> encode_size_packet(Data, 8, (1 bsl 8) - 1);
+ 2 -> encode_size_packet(Data, 16, (1 bsl 16) - 1);
+ 4 -> encode_size_packet(Data, 32, (1 bsl 32) - 1);
+ _ -> Data
+ end.
+
+encode_size_packet(Bin, Size, Max) ->
+ Len = erlang:byte_size(Bin),
+ case Len > Max of
+ true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
+ false -> <<Len:Size, Bin/binary>>
+ end.
+
+time_to_renegotiate(_Data,
+ #{current_write := #{sequence_number := Num}},
+ RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt),
+ %% but we chose to have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
+
+
+%% Picks ClientData
+get_data(_, _, <<>>) ->
+ {more, <<>>};
+%% Recv timed out save buffer data until next recv
+get_data(#socket_options{active=false}, undefined, Buffer) ->
+ {passive, Buffer};
+get_data(#socket_options{active=Active, packet=Raw}, BytesToRead, Buffer)
+ when Raw =:= raw; Raw =:= 0 -> %% Raw Mode
+ if
+ Active =/= false orelse BytesToRead =:= 0 ->
+ %% Active true or once, or passive mode recv(0)
+ {ok, Buffer, <<>>};
+ byte_size(Buffer) >= BytesToRead ->
+ %% Passive Mode, recv(Bytes)
+ <<Data:BytesToRead/binary, Rest/binary>> = Buffer,
+ {ok, Data, Rest};
+ true ->
+ %% Passive Mode not enough data
+ {more, Buffer}
+ end;
+get_data(#socket_options{packet=Type, packet_size=Size}, _, Buffer) ->
+ PacketOpts = [{packet_size, Size}],
+ case decode_packet(Type, Buffer, PacketOpts) of
+ {more, _} ->
+ {more, Buffer};
+ Decoded ->
+ Decoded
+ end.
+
+decode_packet({http, headers}, Buffer, PacketOpts) ->
+ decode_packet(httph, Buffer, PacketOpts);
+decode_packet({http_bin, headers}, Buffer, PacketOpts) ->
+ decode_packet(httph_bin, Buffer, PacketOpts);
+decode_packet(Type, Buffer, PacketOpts) ->
+ erlang:decode_packet(Type, Buffer, PacketOpts).
+
+%% Just like with gen_tcp sockets, an ssl socket that has been configured with
+%% {packet, http} (or {packet, http_bin}) will automatically switch to expect
+%% HTTP headers after it sees a HTTP Request or HTTP Response line. We
+%% represent the current state as follows:
+%% #socket_options.packet =:= http: Expect a HTTP Request/Response line
+%% #socket_options.packet =:= {http, headers}: Expect HTTP Headers
+%% Note that if the user has explicitly configured the socket to expect
+%% HTTP headers using the {packet, httph} option, we don't do any automatic
+%% switching of states.
+deliver_app_data(Transport, Socket, SOpts = #socket_options{active=Active, packet=Type},
+ Data, Pid, From, Tracker, Connection) ->
+ send_or_reply(Active, Pid, From, format_reply(Transport, Socket, SOpts, Data, Tracker, Connection)),
+ SO = case Data of
+ {P, _, _, _} when ((P =:= http_request) or (P =:= http_response)),
+ ((Type =:= http) or (Type =:= http_bin)) ->
+ SOpts#socket_options{packet={Type, headers}};
+ http_eoh when tuple_size(Type) =:= 2 ->
+ % End of headers - expect another Request/Response line
+ {Type1, headers} = Type,
+ SOpts#socket_options{packet=Type1};
+ _ ->
+ SOpts
+ end,
+ case Active of
+ once ->
+ SO#socket_options{active=false};
+ _ ->
+ SO
+ end.
+
+format_reply(_, _,#socket_options{active = false, mode = Mode, packet = Packet,
+ header = Header}, Data, _, _) ->
+ {ok, do_format_reply(Mode, Packet, Header, Data)};
+format_reply(Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
+ header = Header}, Data, Tracker, Connection) ->
+ {ssl, Connection:socket(self(), Transport, Socket, Connection, Tracker),
+ do_format_reply(Mode, Packet, Header, Data)}.
+
+deliver_packet_error(Transport, Socket, SO= #socket_options{active = Active}, Data, Pid, From, Tracker, Connection) ->
+ send_or_reply(Active, Pid, From, format_packet_error(Transport, Socket, SO, Data, Tracker, Connection)).
+
+format_packet_error(_, _,#socket_options{active = false, mode = Mode}, Data, _, _) ->
+ {error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}};
+format_packet_error(Transport, Socket, #socket_options{active = _, mode = Mode}, Data, Tracker, Connection) ->
+ {ssl_error, Connection:socket(self(), Transport, Socket, Connection, Tracker),
+ {invalid_packet, do_format_reply(Mode, raw, 0, Data)}}.
+
+do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode
+ header(N, Data);
+do_format_reply(binary, _, _, Data) ->
+ Data;
+do_format_reply(list, Packet, _, Data)
+ when Packet == http; Packet == {http, headers};
+ Packet == http_bin; Packet == {http_bin, headers};
+ Packet == httph; Packet == httph_bin ->
+ Data;
+do_format_reply(list, _,_, Data) ->
+ binary_to_list(Data).
+
+header(0, <<>>) ->
+ <<>>;
+header(_, <<>>) ->
+ [];
+header(0, Binary) ->
+ Binary;
+header(N, Binary) ->
+ <<?BYTE(ByteN), NewBinary/binary>> = Binary,
+ [ByteN | header(N-1, NewBinary)].
+
+send_or_reply(false, _Pid, From, Data) when From =/= undefined ->
+ gen_statem:reply(From, Data);
+%% Can happen when handling own alert or tcp error/close and there is
+%% no outstanding gen_fsm sync events
+send_or_reply(false, no_pid, _, _) ->
+ ok;
+send_or_reply(_, Pid, _From, Data) ->
+ send_user(Pid, Data).
+
+send_user(Pid, Msg) ->
+ Pid ! Msg.
+
+alert_user(Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
+ alert_user(Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
+alert_user(Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
+ alert_user(Transport, Tracker, Socket, From, Alert, Role, Connection).
+
+alert_user(Transport, Tracker, Socket, From, Alert, Role, Connection) ->
+ alert_user(Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
+
+alert_user(_, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
+ %% If there is an outstanding ssl_accept | recv
+ %% From will be defined and send_or_reply will
+ %% send the appropriate error message.
+ ReasonCode = ssl_alert:reason_code(Alert, Role),
+ send_or_reply(Active, Pid, From, {error, ReasonCode});
+alert_user(Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
+ case ssl_alert:reason_code(Alert, Role) of
+ closed ->
+ send_or_reply(Active, Pid, From,
+ {ssl_closed, Connection:socket(self(),
+ Transport, Socket, Connection, Tracker)});
+ ReasonCode ->
+ send_or_reply(Active, Pid, From,
+ {ssl_error, Connection:socket(self(),
+ Transport, Socket, Connection, Tracker), ReasonCode})
+ end.
+
+log_alert(true, Info, Alert) ->
+ Txt = ssl_alert:alert_txt(Alert),
+ error_logger:format("SSL: ~p: ~s\n", [Info, Txt]);
+log_alert(false, _, _) ->
+ ok.
+
+handle_own_alert(Alert, Version, StateName,
+ #state{transport_cb = Transport,
+ socket = Socket,
+ protocol_cb = Connection,
+ connection_states = ConnectionStates,
+ ssl_options = SslOpts} = State) ->
+ try %% Try to tell the other side
+ {BinMsg, _} =
+ Connection:encode_alert(Alert, Version, ConnectionStates),
+ Connection:send(Transport, Socket, BinMsg)
+ catch _:_ -> %% Can crash if we are in a uninitialized state
+ ignore
+ end,
+ try %% Try to tell the local user
+ log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
+ handle_normal_shutdown(Alert,StateName, State)
+ catch _:_ ->
+ ok
+ end,
+ {stop, {shutdown, own_alert}}.
+
+handle_normal_shutdown(Alert, _, #state{socket = Socket,
+ transport_cb = Transport,
+ protocol_cb = Connection,
+ start_or_recv_from = StartFrom,
+ tracker = Tracker,
+ role = Role, renegotiation = {false, first}}) ->
+ alert_user(Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
+
+handle_normal_shutdown(Alert, StateName, #state{socket = Socket,
+ socket_options = Opts,
+ transport_cb = Transport,
+ protocol_cb = Connection,
+ user_application = {_Mon, Pid},
+ tracker = Tracker,
+ start_or_recv_from = RecvFrom, role = Role}) ->
+ alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
+
+invalidate_session(client, Host, Port, Session) ->
+ ssl_manager:invalidate_session(Host, Port, Session);
+invalidate_session(server, _, Port, Session) ->
+ ssl_manager:invalidate_session(Port, Session).
+
+handle_sni_extension(undefined, State) ->
+ State;
+handle_sni_extension(#sni{hostname = Hostname}, State0) ->
+ NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
+ case NewOptions of
+ undefined ->
+ State0;
+ _ ->
+ {ok, #{cert_db_ref := Ref,
+ cert_db_handle := CertDbHandle,
+ fileref_db_handle := FileRefHandle,
+ session_cache := CacheHandle,
+ crl_db_info := CRLDbHandle,
+ private_key := Key,
+ dh_params := DHParams,
+ own_certificate := OwnCert}} =
+ ssl_config:init(NewOptions, State0#state.role),
+ State0#state{
+ session = State0#state.session#session{own_certificate = OwnCert},
+ file_ref_db = FileRefHandle,
+ cert_db_ref = Ref,
+ cert_db = CertDbHandle,
+ crl_db = CRLDbHandle,
+ session_cache = CacheHandle,
+ private_key = Key,
+ diffie_hellman_params = DHParams,
+ ssl_options = NewOptions,
+ sni_hostname = Hostname
+ }
+ end.
+
+update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) ->
+ SSLOption =
+ case OrigSSLOptions#ssl_options.sni_fun of
+ undefined ->
+ proplists:get_value(SNIHostname,
+ OrigSSLOptions#ssl_options.sni_hosts);
+ SNIFun ->
+ SNIFun(SNIHostname)
+ end,
+ case SSLOption of
+ undefined ->
+ undefined;
+ _ ->
+ ssl:handle_options(SSLOption, OrigSSLOptions)
+ end.
+
+new_emulated([], EmOpts) ->
+ EmOpts;
+new_emulated(NewEmOpts, _) ->
+ NewEmOpts.
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 4b54943ddf..016cc4b525 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,11 +43,12 @@
error_tag :: atom(), % ex tcp_error
host :: string() | inet:ip_address(),
port :: integer(),
- socket :: port(),
+ socket :: port() | tuple(), %% TODO: dtls socket
ssl_options :: #ssl_options{},
socket_options :: #socket_options{},
- connection_states :: #connection_states{} | secret_printout(),
+ connection_states :: ssl_record:connection_states() | secret_printout(),
protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hrl
+ unprocessed_handshake_events = 0 :: integer(),
tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout()
| 'undefined',
cert_db :: reference() | 'undefined',
@@ -56,6 +57,7 @@
session_cache_cb :: atom(),
crl_db :: term(),
negotiated_version :: ssl_record:ssl_version() | 'undefined',
+ client_hello_version :: ssl_record:ssl_version() | 'undefined',
client_certificate_requested = false :: boolean(),
key_algorithm :: ssl_cipher:key_algo(),
hashsign_algorithm = {undefined, undefined},
@@ -80,18 +82,18 @@
allow_renegotiate = true ::boolean(),
expecting_next_protocol_negotiation = false ::boolean(),
expecting_finished = false ::boolean(),
- negotiated_protocol = undefined :: undefined | binary(),
- client_ecc, % {Curves, PointFmt}
+ next_protocol = undefined :: undefined | binary(),
+ negotiated_protocol,
tracker :: pid() | 'undefined', %% Tracker process for listen socket
sni_hostname = undefined,
downgrade,
- flight_buffer = [] :: list() %% Buffer of TLS/DTLS records, used during the TLS handshake
- %% to when possible pack more than on TLS record into the
- %% underlaying packet format. Introduced by DTLS - RFC 4347.
- %% The mecahnism is also usefull in TLS although we do not
- %% need to worry about packet loss in TLS.
+ flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake
+ %% to when possible pack more than on TLS record into the
+ %% underlaying packet format. Introduced by DTLS - RFC 4347.
+ %% The mecahnism is also usefull in TLS although we do not
+ %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr
+ flight_state = reliable %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp.
}).
-
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
#'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
new file mode 100644
index 0000000000..1a1f43e683
--- /dev/null
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -0,0 +1,101 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_connection_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+
+init([]) ->
+
+ TLSConnetionManager = tls_connection_manager_child_spec(),
+ %% Handles emulated options so that they inherited by the accept
+ %% socket, even when setopts is performed on the listen socket
+ ListenOptionsTracker = listen_options_tracker_child_spec(),
+
+ DTLSConnetionManager = dtls_connection_manager_child_spec(),
+ DTLSUdpListeners = dtls_udp_listeners_spec(),
+
+ {ok, {{one_for_one, 10, 3600}, [TLSConnetionManager,
+ ListenOptionsTracker,
+ DTLSConnetionManager,
+ DTLSUdpListeners
+ ]}}.
+
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+tls_connection_manager_child_spec() ->
+ Name = tls_connection,
+ StartFunc = {tls_connection_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [tls_connection_sup],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+dtls_connection_manager_child_spec() ->
+ Name = dtls_connection,
+ StartFunc = {dtls_connection_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [dtls_connection_sup],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+listen_options_tracker_child_spec() ->
+ Name = tls_socket,
+ StartFunc = {ssl_listen_tracker_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [tls_socket],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+dtls_udp_listeners_spec() ->
+ Name = dtls_udp_listener,
+ StartFunc = {dtls_udp_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl
index d9f21e04ac..888a75bfd6 100644
--- a/lib/ssl/src/ssl_crl.erl
+++ b/lib/ssl/src/ssl_crl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
-export([trusted_cert_and_path/3]).
-trusted_cert_and_path(CRL, {SerialNumber, Issuer},{Db, DbRef} = DbHandle) ->
+trusted_cert_and_path(CRL, {SerialNumber, Issuer},{_, {Db, DbRef}} = DbHandle) ->
case ssl_pkix_db:lookup_trusted_cert(Db, DbRef, SerialNumber, Issuer) of
undefined ->
trusted_cert_and_path(CRL, issuer_not_found, DbHandle);
@@ -37,17 +37,34 @@ trusted_cert_and_path(CRL, {SerialNumber, Issuer},{Db, DbRef} = DbHandle) ->
{ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef),
{ok, Root, lists:reverse(Chain)}
end;
-
-trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef} = DbHandle) ->
- case find_issuer(CRL, DbHandle) of
+trusted_cert_and_path(CRL, issuer_not_found, {CertPath, {Db, DbRef}}) ->
+ case find_issuer(CRL, {certpath,
+ [{Der, public_key:pkix_decode_cert(Der,otp)} || Der <- CertPath]}) of
{ok, OtpCert} ->
{ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef),
{ok, Root, lists:reverse(Chain)};
{error, issuer_not_found} ->
- {ok, unknown_crl_ca, []}
- end.
+ trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef})
+ end;
+trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef} = DbInfo) ->
+ case find_issuer(CRL, DbInfo) of
+ {ok, OtpCert} ->
+ {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef),
+ {ok, Root, lists:reverse(Chain)};
+ {error, issuer_not_found} ->
+ {error, unknown_ca}
+ end.
-find_issuer(CRL, {Db,_}) ->
+find_issuer(CRL, {certpath = Db, DbRef}) ->
+ Issuer = public_key:pkix_normalize_name(public_key:pkix_crl_issuer(CRL)),
+ IsIssuerFun =
+ fun({_Der,ErlCertCandidate}, Acc) ->
+ verify_crl_issuer(CRL, ErlCertCandidate, Issuer, Acc);
+ (_, Acc) ->
+ Acc
+ end,
+ find_issuer(IsIssuerFun, Db, DbRef);
+find_issuer(CRL, {Db, DbRef}) ->
Issuer = public_key:pkix_normalize_name(public_key:pkix_crl_issuer(CRL)),
IsIssuerFun =
fun({_Key, {_Der,ErlCertCandidate}}, Acc) ->
@@ -55,13 +72,32 @@ find_issuer(CRL, {Db,_}) ->
(_, Acc) ->
Acc
end,
-
+ find_issuer(IsIssuerFun, Db, DbRef).
+
+find_issuer(IsIssuerFun, certpath, Certs) ->
+ try lists:foldl(IsIssuerFun, issuer_not_found, Certs) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _} = Result ->
+ Result
+ end;
+find_issuer(IsIssuerFun, extracted, CertsData) ->
+ Certs = [Entry || {decoded, Entry} <- CertsData],
+ try lists:foldl(IsIssuerFun, issuer_not_found, Certs) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _} = Result ->
+ Result
+ end;
+find_issuer(IsIssuerFun, Db, _) ->
try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, Db) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _} = Result ->
- Result
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _} = Result ->
+ Result
end.
verify_crl_issuer(CRL, ErlCertCandidate, Issuer, NotIssuer) ->
diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl
index 647e0465fe..86c0207515 100644
--- a/lib/ssl/src/ssl_crl_cache.erl
+++ b/lib/ssl/src/ssl_crl_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_crl_cache_api.erl b/lib/ssl/src/ssl_crl_cache_api.erl
index c3a57e2f49..d5380583e7 100644
--- a/lib/ssl/src/ssl_crl_cache_api.erl
+++ b/lib/ssl/src/ssl_crl_cache_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_dist_admin_sup.erl b/lib/ssl/src/ssl_dist_admin_sup.erl
new file mode 100644
index 0000000000..f60806c4cb
--- /dev/null
+++ b/lib/ssl/src/ssl_dist_admin_sup.erl
@@ -0,0 +1,74 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_dist_admin_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+
+init([]) ->
+ PEMCache = pem_cache_child_spec(),
+ SessionCertManager = session_and_cert_manager_child_spec(),
+ {ok, {{rest_for_one, 10, 3600}, [PEMCache, SessionCertManager]}}.
+
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+pem_cache_child_spec() ->
+ Name = ssl_pem_cache_dist,
+ StartFunc = {ssl_pem_cache, start_link_dist, [[]]},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_pem_cache],
+ Type = worker,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+session_and_cert_manager_child_spec() ->
+ Opts = ssl_admin_sup:manager_opts(),
+ Name = ssl_dist_manager,
+ StartFunc = {ssl_manager, start_link_dist, [Opts]},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_manager],
+ Type = worker,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
diff --git a/lib/ssl/src/ssl_dist_connection_sup.erl b/lib/ssl/src/ssl_dist_connection_sup.erl
new file mode 100644
index 0000000000..e5842c866e
--- /dev/null
+++ b/lib/ssl/src/ssl_dist_connection_sup.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_dist_connection_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+
+init([]) ->
+
+ TLSConnetionManager = tls_connection_manager_child_spec(),
+ %% Handles emulated options so that they inherited by the accept
+ %% socket, even when setopts is performed on the listen socket
+ ListenOptionsTracker = listen_options_tracker_child_spec(),
+
+ {ok, {{one_for_one, 10, 3600}, [TLSConnetionManager,
+ ListenOptionsTracker
+ ]}}.
+
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+tls_connection_manager_child_spec() ->
+ Name = dist_tls_connection,
+ StartFunc = {tls_connection_sup, start_link_dist, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [tls_connection_sup],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+listen_options_tracker_child_spec() ->
+ Name = dist_tls_socket,
+ StartFunc = {ssl_listen_tracker_sup, start_link_dist, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [tls_socket],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl
index a6eb1be1f6..690b896919 100644
--- a/lib/ssl/src/ssl_dist_sup.erl
+++ b/lib/ssl/src/ssl_dist_sup.erl
@@ -44,34 +44,29 @@ start_link() ->
%%%=========================================================================
init([]) ->
- SessionCertManager = session_and_cert_manager_child_spec(),
- ConnetionManager = connection_manager_child_spec(),
- ListenOptionsTracker = listen_options_tracker_child_spec(),
+ AdminSup = ssl_admin_child_spec(),
+ ConnectionSup = ssl_connection_sup(),
ProxyServer = proxy_server_child_spec(),
-
- {ok, {{one_for_all, 10, 3600}, [SessionCertManager, ConnetionManager,
- ListenOptionsTracker,
- ProxyServer]}}.
+ {ok, {{one_for_all, 10, 3600}, [AdminSup, ProxyServer, ConnectionSup]}}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-session_and_cert_manager_child_spec() ->
- Opts = ssl_sup:manager_opts(),
- Name = ssl_manager_dist,
- StartFunc = {ssl_manager, start_link_dist, [Opts]},
+ssl_admin_child_spec() ->
+ Name = ssl_dist_admin_sup,
+ StartFunc = {ssl_dist_admin_sup, start_link , []},
Restart = permanent,
Shutdown = 4000,
- Modules = [ssl_manager],
- Type = worker,
+ Modules = [ssl_admin_sup],
+ Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-connection_manager_child_spec() ->
- Name = ssl_connection_dist,
- StartFunc = {tls_connection_sup, start_link_dist, []},
- Restart = permanent,
- Shutdown = infinity,
- Modules = [tls_connection_sup],
+ssl_connection_sup() ->
+ Name = ssl_dist_connection_sup,
+ StartFunc = {ssl_dist_connection_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_connection_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
@@ -83,12 +78,3 @@ proxy_server_child_spec() ->
Modules = [ssl_tls_dist_proxy],
Type = worker,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-listen_options_tracker_child_spec() ->
- Name = ssl_socket_dist,
- StartFunc = {ssl_listen_tracker_sup, start_link_dist, []},
- Restart = permanent,
- Shutdown = 4000,
- Modules = [ssl_socket],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 9c3fe9d73b..e84473f215 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,8 +51,8 @@
%% Handle handshake messages
-export([certify/10, client_certificate_verify/6, certificate_verify/6, verify_signature/5,
- master_secret/5, server_key_exchange_hash/2, verify_connection/6,
- init_handshake_history/0, update_handshake_history/2, verify_server_key/5
+ master_secret/4, server_key_exchange_hash/2, verify_connection/6,
+ init_handshake_history/0, update_handshake_history/3, verify_server_key/5
]).
%% Encode/Decode
@@ -70,11 +70,11 @@
%% Extensions handling
-export([client_hello_extensions/6,
handle_client_hello_extensions/9, %% Returns server hello extensions
- handle_server_hello_extensions/9, select_curve/2
+ handle_server_hello_extensions/9, select_curve/2, select_curve/3
]).
%% MISC
--export([select_version/3, prf/6, select_hashsign/5,
+-export([select_version/3, prf/6, select_hashsign/4, select_hashsign/5,
select_hashsign_algs/3,
premaster_secret/2, premaster_secret/3, premaster_secret/4]).
@@ -94,15 +94,14 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
--spec server_hello(#session{}, ssl_record:ssl_version(), #connection_states{},
+-spec server_hello(#session{}, ssl_record:ssl_version(), ssl_record:connection_states(),
#hello_extensions{}) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
server_hello(SessionId, Version, ConnectionStates, Extensions) ->
- Pending = ssl_record:pending_connection_state(ConnectionStates, read),
- SecParams = Pending#connection_state.security_parameters,
-
+ #{security_parameters := SecParams} =
+ ssl_record:pending_connection_state(ConnectionStates, read),
#server_hello{server_version = Version,
cipher_suite = SecParams#security_parameters.cipher_suite,
compression_method =
@@ -121,11 +120,13 @@ server_hello_done() ->
#server_hello_done{}.
client_hello_extensions(Host, Version, CipherSuites,
- #ssl_options{signature_algs = SupportedHashSigns, versions = AllVersions} = SslOpts, ConnectionStates, Renegotiation) ->
+ #ssl_options{signature_algs = SupportedHashSigns,
+ eccs = SupportedECCs,
+ versions = AllVersions} = SslOpts, ConnectionStates, Renegotiation) ->
{EcPointFormats, EllipticCurves} =
case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
true ->
- client_ecc_extensions(tls_v1, Version);
+ client_ecc_extensions(SupportedECCs);
false ->
{undefined, undefined}
end,
@@ -335,9 +336,8 @@ verify_server_key(#server_key_params{params_bin = EncParams,
signature = Signature},
HashSign = {HashAlgo, _},
ConnectionStates, Version, PubKeyInfo) ->
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
- SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
Hash = server_key_exchange_hash(HashAlgo,
@@ -397,14 +397,13 @@ verify_signature(_, Hash, {HashAlgo, _SignAlg}, Signature,
%%--------------------------------------------------------------------
certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
MaxPathLen, _Verify, ValidationFunAndState0, PartialChain, CRLCheck, CRLDbHandle, Role) ->
- [PeerCert | _] = ASN1Certs,
-
- ValidationFunAndState = validation_fun_and_state(ValidationFunAndState0, Role,
- CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle),
-
+ [PeerCert | _] = ASN1Certs,
try
{TrustedCert, CertPath} =
ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef, PartialChain),
+ ValidationFunAndState = validation_fun_and_state(ValidationFunAndState0, Role,
+ CertDbHandle, CertDbRef,
+ CRLCheck, CRLDbHandle, CertPath),
case public_key:pkix_path_validation(TrustedCert,
CertPath,
[{max_path_length, MaxPathLen},
@@ -447,7 +446,7 @@ init_handshake_history() ->
{[], []}.
%%--------------------------------------------------------------------
--spec update_handshake_history(ssl_handshake:ssl_handshake_history(), Data ::term()) ->
+-spec update_handshake_history(ssl_handshake:ssl_handshake_history(), Data ::term(), boolean()) ->
ssl_handshake:ssl_handshake_history().
%%
%% Description: Update the handshake history buffer with Data.
@@ -457,14 +456,14 @@ update_handshake_history(Handshake, % special-case SSL2 client hello
?UINT16(CSLength), ?UINT16(0),
?UINT16(CDLength),
CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>) ->
+ ChallengeData:CDLength/binary>>, true) ->
update_handshake_history(Handshake,
<<?CLIENT_HELLO, ?BYTE(Major), ?BYTE(Minor),
?UINT16(CSLength), ?UINT16(0),
?UINT16(CDLength),
CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>);
-update_handshake_history({Handshake0, _Prev}, Data) ->
+ ChallengeData:CDLength/binary>>, true);
+update_handshake_history({Handshake0, _Prev}, Data, _) ->
{[Data|Handshake0], Handshake0}.
%% %%--------------------------------------------------------------------
@@ -581,7 +580,7 @@ prf({3,_N}, PRFAlgo, Secret, Label, Seed, WantedLength) ->
{atom(), atom()} | undefined | #alert{}.
%%
-%% Description: Handles signature_algorithms extension
+%% Description: Handles signature_algorithms hello extension (server)
%%--------------------------------------------------------------------
select_hashsign(_, undefined, _, _, _Version) ->
{null, anon};
@@ -593,14 +592,17 @@ select_hashsign(HashSigns, Cert, KeyExAlgo,
select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, KeyExAlgo, SupportedHashSigns,
{Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
#'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- Sign = cert_sign(Algo),
- case lists:filter(fun({sha, dsa = S}) when S == Sign ->
- true;
- ({_, dsa}) ->
- false;
- ({_, _} = Algos) ->
- is_acceptable_hash_sign(Algos, Sign, KeyExAlgo, SupportedHashSigns);
+ #'OTPCertificate'{tbsCertificate = TBSCert,
+ signatureAlgorithm = {_,SignAlgo, _}} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
+ TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+
+ Sign = sign_algo(SignAlgo),
+ SubSing = sign_algo(SubjAlgo),
+
+ case lists:filter(fun({_, S} = Algos) when S == Sign ->
+ is_acceptable_hash_sign(Algos, Sign,
+ SubSing, KeyExAlgo, SupportedHashSigns);
(_) ->
false
end, HashSigns) of
@@ -613,6 +615,49 @@ select_hashsign(_, Cert, _, _, Version) ->
#'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
#'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
select_hashsign_algs(undefined, Algo, Version).
+%%--------------------------------------------------------------------
+-spec select_hashsign(#certificate_request{}, binary(),
+ [atom()], ssl_record:ssl_version()) ->
+ {atom(), atom()} | #alert{}.
+
+%%
+%% Description: Handles signature algorithms selection for certificate requests (client)
+%%--------------------------------------------------------------------
+select_hashsign(#certificate_request{}, undefined, _, {Major, Minor}) when Major >= 3 andalso Minor >= 3->
+ %% There client does not have a certificate and will send an empty reply, the server may fail
+ %% or accept the connection by its own preference. No signature algorihms needed as there is
+ %% no certificate to verify.
+ {undefined, undefined};
+
+select_hashsign(#certificate_request{hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSigns},
+ certificate_types = Types}, Cert, SupportedHashSigns,
+ {Major, Minor}) when Major >= 3 andalso Minor >= 3->
+ #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPCertificate'{tbsCertificate = TBSCert,
+ signatureAlgorithm = {_,SignAlgo, _}} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
+ TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+
+ Sign = sign_algo(SignAlgo),
+ SubSign = sign_algo(SubjAlgo),
+
+ case is_acceptable_cert_type(SubSign, HashSigns, Types) andalso is_supported_sign(Sign, HashSigns) of
+ true ->
+ case lists:filter(fun({_, S} = Algos) when S == SubSign ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+ (_) ->
+ false
+ end, HashSigns) of
+ [] ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm);
+ [HashSign | _] ->
+ HashSign
+ end;
+ false ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
+ end;
+select_hashsign(#certificate_request{}, Cert, _, Version) ->
+ select_hashsign(undefined, Cert, undefined, [], Version).
%%--------------------------------------------------------------------
-spec select_hashsign_algs({atom(), atom()}| undefined, oid(), ssl_record:ssl_version()) ->
@@ -648,34 +693,34 @@ select_hashsign_algs(undefined, ?rsaEncryption, _) ->
select_hashsign_algs(undefined, ?'id-dsa', _) ->
{sha, dsa}.
+
%%--------------------------------------------------------------------
--spec master_secret(atom(), ssl_record:ssl_version(), #session{} | binary(), #connection_states{},
- client | server) -> {binary(), #connection_states{}} | #alert{}.
+-spec master_secret(ssl_record:ssl_version(), #session{} | binary(), ssl_record:connection_states(),
+ client | server) -> {binary(), ssl_record:connection_states()} | #alert{}.
%%
%% Description: Sets or calculates the master secret and calculate keys,
%% updating the pending connection states. The Mastersecret and the update
%% connection states are returned or an alert if the calculation fails.
%%-------------------------------------------------------------------
-master_secret(RecordCB, Version, #session{master_secret = Mastersecret},
+master_secret(Version, #session{master_secret = Mastersecret},
ConnectionStates, Role) ->
- ConnectionState =
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
- SecParams = ConnectionState#connection_state.security_parameters,
- try master_secret(RecordCB, Version, Mastersecret, SecParams,
+ try master_secret(Version, Mastersecret, SecParams,
ConnectionStates, Role)
catch
exit:_ ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, key_calculation_failure)
end;
-master_secret(RecordCB, Version, PremasterSecret, ConnectionStates, Role) ->
- ConnectionState =
+master_secret(Version, PremasterSecret, ConnectionStates, Role) ->
+ #{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
- SecParams = ConnectionState#connection_state.security_parameters,
+
#security_parameters{prf_algorithm = PrfAlgo,
client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- try master_secret(RecordCB, Version,
+ try master_secret(Version,
calc_master_secret(Version,PrfAlgo,PremasterSecret,
ClientRandom, ServerRandom),
SecParams, ConnectionStates, Role)
@@ -1125,8 +1170,9 @@ select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, Port,
{resumed, Resumed}
end.
-supported_ecc({Major, Minor} = Version) when ((Major == 3) and (Minor >= 1)) orelse (Major > 3) ->
- Curves = tls_v1:ecc_curves(Version),
+%% Deprecated?
+supported_ecc({Major, Minor}) when ((Major == 3) and (Minor >= 1)) orelse (Major > 3) ->
+ Curves = tls_v1:ecc_curves(Minor),
#elliptic_curves{elliptic_curve_list = Curves};
supported_ecc(_) ->
#elliptic_curves{elliptic_curve_list = []}.
@@ -1143,11 +1189,13 @@ certificate_types(_, {N, M}) when N >= 3 andalso M >= 3 ->
end;
certificate_types({KeyExchange, _, _, _}, _) when KeyExchange == rsa;
+ KeyExchange == dh_rsa;
KeyExchange == dhe_rsa;
KeyExchange == ecdhe_rsa ->
<<?BYTE(?RSA_SIGN)>>;
-certificate_types({KeyExchange, _, _, _}, _) when KeyExchange == dhe_dss;
+certificate_types({KeyExchange, _, _, _}, _) when KeyExchange == dh_dss;
+ KeyExchange == dhe_dss;
KeyExchange == srp_dss ->
<<?BYTE(?DSS_SIGN)>>;
@@ -1170,13 +1218,18 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
end,
list_to_binary([Enc(Cert) || {_, Cert} <- Authorities]).
-certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
+certificate_authorities_from_db(CertDbHandle, CertDbRef) when is_reference(CertDbRef) ->
ConnectionCerts = fun({{Ref, _, _}, Cert}, Acc) when Ref == CertDbRef ->
[Cert | Acc];
(_, Acc) ->
Acc
end,
- ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle).
+ ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle);
+certificate_authorities_from_db(_CertDbHandle, {extracted, CertDbData}) ->
+ %% Cache disabled, Ref contains data
+ lists:foldl(fun({decoded, {_Key,Cert}}, Acc) -> [Cert | Acc] end,
+ [], CertDbData).
+
%%-------------Extension handling --------------------------------
@@ -1256,35 +1309,67 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
end.
select_version(RecordCB, ClientVersion, Versions) ->
- ServerVersion = RecordCB:highest_protocol_version(Versions),
- RecordCB:lowest_protocol_version(ClientVersion, ServerVersion).
+ do_select_version(RecordCB, ClientVersion, Versions).
+
+do_select_version(_, ClientVersion, []) ->
+ ClientVersion;
+do_select_version(RecordCB, ClientVersion, [Version | Versions]) ->
+ case RecordCB:is_higher(Version, ClientVersion) of
+ true ->
+ %% Version too high for client - keep looking
+ do_select_version(RecordCB, ClientVersion, Versions);
+ false ->
+ %% Version ok for client - look for a higher
+ do_select_version(RecordCB, ClientVersion, Versions, Version)
+ end.
+%%
+do_select_version(_, _, [], GoodVersion) ->
+ GoodVersion;
+do_select_version(
+ RecordCB, ClientVersion, [Version | Versions], GoodVersion) ->
+ BetterVersion =
+ case RecordCB:is_higher(Version, ClientVersion) of
+ true ->
+ %% Version too high for client
+ GoodVersion;
+ false ->
+ %% Version ok for client
+ case RecordCB:is_higher(Version, GoodVersion) of
+ true ->
+ %% Use higher version
+ Version;
+ false ->
+ GoodVersion
+ end
+ end,
+ do_select_version(RecordCB, ClientVersion, Versions, BetterVersion).
renegotiation_info(_, client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(_RecordCB, server, ConnectionStates, false) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
- case CS#connection_state.secure_renegotiation of
+ ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
+ case maps:get(secure_renegotiation, ConnectionState) of
true ->
#renegotiation_info{renegotiated_connection = ?byte(0)};
false ->
#renegotiation_info{renegotiated_connection = undefined}
end;
renegotiation_info(_RecordCB, client, ConnectionStates, true) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
- case CS#connection_state.secure_renegotiation of
+ ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
+ case maps:get(secure_renegotiation, ConnectionState) of
true ->
- Data = CS#connection_state.client_verify_data,
+ Data = maps:get(client_verify_data, ConnectionState),
#renegotiation_info{renegotiated_connection = Data};
false ->
#renegotiation_info{renegotiated_connection = undefined}
end;
renegotiation_info(_RecordCB, server, ConnectionStates, true) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
- case CS#connection_state.secure_renegotiation of
+ ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
+ case maps:get(secure_renegotiation, ConnectionState) of
true ->
- CData = CS#connection_state.client_verify_data,
- SData =CS#connection_state.server_verify_data,
+ CData = maps:get(client_verify_data, ConnectionState),
+ SData = maps:get(server_verify_data, ConnectionState),
#renegotiation_info{renegotiated_connection = <<CData/binary, SData/binary>>};
false ->
#renegotiation_info{renegotiated_connection = undefined}
@@ -1307,9 +1392,9 @@ handle_renegotiation_info(_RecordCB, _, undefined, ConnectionStates, false, _, _
handle_renegotiation_info(_RecordCB, client, #renegotiation_info{renegotiated_connection = ClientServerVerify},
ConnectionStates, true, _, _) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
- CData = CS#connection_state.client_verify_data,
- SData = CS#connection_state.server_verify_data,
+ ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
+ CData = maps:get(client_verify_data, ConnectionState),
+ SData = maps:get(server_verify_data, ConnectionState),
case <<CData/binary, SData/binary>> == ClientServerVerify of
true ->
{ok, ConnectionStates};
@@ -1323,8 +1408,8 @@ handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_co
true ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv});
false ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
- Data = CS#connection_state.client_verify_data,
+ ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
+ Data = maps:get(client_verify_data, ConnectionState),
case Data == ClientVerify of
true ->
{ok, ConnectionStates};
@@ -1345,8 +1430,8 @@ handle_renegotiation_info(RecordCB, server, undefined, ConnectionStates, true, S
end.
handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
- case {SecureRenegotation, CS#connection_state.secure_renegotiation} of
+ ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
+ case {SecureRenegotation, maps:get(secure_renegotiation, ConnectionState)} of
{_, true} ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure);
{true, false} ->
@@ -1371,12 +1456,12 @@ srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
srp_user(_) ->
undefined.
-client_ecc_extensions(Module, Version) ->
+client_ecc_extensions(SupportedECCs) ->
CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
case proplists:get_bool(ecdh, CryptoSupport) of
true ->
EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
- EllipticCurves = #elliptic_curves{elliptic_curve_list = Module:ecc_curves(Version)},
+ EllipticCurves = SupportedECCs,
{EcPointFormats, EllipticCurves};
_ ->
{undefined, undefined}
@@ -1410,22 +1495,34 @@ advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
true;
advertises_ec_ciphers([_| Rest]) ->
advertises_ec_ciphers(Rest).
-select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves},
- #elliptic_curves{elliptic_curve_list = ServerCurves}) ->
- select_curve(ClientCurves, ServerCurves);
-select_curve(undefined, _) ->
+
+select_curve(Client, Server) ->
+ select_curve(Client, Server, false).
+
+select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves},
+ #elliptic_curves{elliptic_curve_list = ServerCurves},
+ ServerOrder) ->
+ case ServerOrder of
+ false ->
+ select_shared_curve(ClientCurves, ServerCurves);
+ true ->
+ select_shared_curve(ServerCurves, ClientCurves)
+ end;
+select_curve(undefined, _, _) ->
%% Client did not send ECC extension use default curve if
%% ECC cipher is negotiated
- {namedCurve, ?secp256r1};
-select_curve(_, []) ->
+ {namedCurve, ?secp256r1}.
+
+select_shared_curve([], _) ->
no_curve;
-select_curve(Curves, [Curve| Rest]) ->
+select_shared_curve([Curve | Rest], Curves) ->
case lists:member(Curve, Curves) of
true ->
{namedCurve, Curve};
false ->
- select_curve(Curves, Rest)
+ select_shared_curve(Rest, Curves)
end.
+
%% RFC 6066, Section 3: Currently, the only server names supported are
%% DNS hostnames
sni(_, disable) ->
@@ -1443,7 +1540,8 @@ sni1(Hostname) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle) ->
+validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
+ CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
case ssl_certificate:validate(OtpCert,
Extension,
@@ -1452,22 +1550,25 @@ validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef, CRLC
{valid, {NewSslState, UserState}};
{fail, Reason} ->
apply_user_fun(Fun, OtpCert, Reason, UserState,
- SslState);
+ SslState, CertPath);
{unknown, _} ->
apply_user_fun(Fun, OtpCert,
- Extension, UserState, SslState)
+ Extension, UserState, SslState, CertPath)
end;
(OtpCert, VerifyResult, {SslState, UserState}) ->
apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
- SslState)
+ SslState, CertPath)
end, {{Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle}, UserState0}};
-validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle) ->
+validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
+ CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, SslState) ->
ssl_certificate:validate(OtpCert,
Extension,
SslState);
- (OtpCert, VerifyResult, SslState) when (VerifyResult == valid) or (VerifyResult == valid_peer) ->
- case crl_check(OtpCert, CRLCheck, CertDbHandle, CertDbRef, CRLDbHandle, VerifyResult) of
+ (OtpCert, VerifyResult, SslState) when (VerifyResult == valid) or
+ (VerifyResult == valid_peer) ->
+ case crl_check(OtpCert, CRLCheck, CertDbHandle, CertDbRef,
+ CRLDbHandle, VerifyResult, CertPath) of
valid ->
{VerifyResult, SslState};
Reason ->
@@ -1480,20 +1581,21 @@ validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef, CRLCheck, CRL
end, {Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle}}.
apply_user_fun(Fun, OtpCert, VerifyResult, UserState0,
- {_, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle} = SslState) when
+ {_, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle} = SslState, CertPath) when
(VerifyResult == valid) or (VerifyResult == valid_peer) ->
case Fun(OtpCert, VerifyResult, UserState0) of
{Valid, UserState} when (Valid == valid) or (Valid == valid_peer) ->
- case crl_check(OtpCert, CRLCheck, CertDbHandle, CertDbRef, CRLDbHandle, VerifyResult) of
+ case crl_check(OtpCert, CRLCheck, CertDbHandle, CertDbRef,
+ CRLDbHandle, VerifyResult, CertPath) of
valid ->
{Valid, {SslState, UserState}};
Result ->
- apply_user_fun(Fun, OtpCert, Result, UserState, SslState)
+ apply_user_fun(Fun, OtpCert, Result, UserState, SslState, CertPath)
end;
{fail, _} = Fail ->
Fail
end;
-apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
+apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath) ->
case Fun(OtpCert, ExtensionOrError, UserState0) of
{Valid, UserState} when (Valid == valid) or (Valid == valid_peer)->
{Valid, {SslState, UserState}};
@@ -1564,7 +1666,7 @@ calc_finished({3, 0}, Role, _PrfAlgo, MasterSecret, Handshake) ->
calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake) ->
tls_v1:finished(Role, N, PrfAlgo, MasterSecret, lists:reverse(Handshake)).
-master_secret(_RecordCB, Version, MasterSecret,
+master_secret(Version, MasterSecret,
#security_parameters{
bulk_cipher_algorithm = BCA,
client_random = ClientRandom,
@@ -1647,18 +1749,16 @@ hello_pending_connection_states(_RecordCB, Role, Version, CipherSuite, Random, C
NewWriteSecParams,
ConnectionStates).
-hello_security_parameters(client, Version, ConnectionState, CipherSuite, Random,
+hello_security_parameters(client, Version, #{security_parameters := SecParams}, CipherSuite, Random,
Compression) ->
- SecParams = ConnectionState#connection_state.security_parameters,
NewSecParams = ssl_cipher:security_parameters(Version, CipherSuite, SecParams),
NewSecParams#security_parameters{
server_random = Random,
compression_algorithm = Compression
};
-hello_security_parameters(server, Version, ConnectionState, CipherSuite, Random,
+hello_security_parameters(server, Version, #{security_parameters := SecParams}, CipherSuite, Random,
Compression) ->
- SecParams = ConnectionState#connection_state.security_parameters,
NewSecParams = ssl_cipher:security_parameters(Version, CipherSuite, SecParams),
NewSecParams#security_parameters{
client_random = Random,
@@ -2091,13 +2191,14 @@ handle_psk_identity(_PSKIdentity, LookupFun)
handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
Fun(psk, PSKIdentity, UserState).
-crl_check(_, false, _,_,_, _) ->
+crl_check(_, false, _,_,_, _, _) ->
valid;
-crl_check(_, peer, _, _,_, valid) -> %% Do not check CAs with this option.
+crl_check(_, peer, _, _,_, valid, _) -> %% Do not check CAs with this option.
valid;
-crl_check(OtpCert, Check, CertDbHandle, CertDbRef, {Callback, CRLDbHandle}, _) ->
+crl_check(OtpCert, Check, CertDbHandle, CertDbRef, {Callback, CRLDbHandle}, _, CertPath) ->
Options = [{issuer_fun, {fun(_DP, CRL, Issuer, DBInfo) ->
- ssl_crl:trusted_cert_and_path(CRL, Issuer, DBInfo)
+ ssl_crl:trusted_cert_and_path(CRL, Issuer, {CertPath,
+ DBInfo})
end, {CertDbHandle, CertDbRef}}},
{update_crl, fun(DP, CRL) -> Callback:fresh_crl(DP, CRL) end}
],
@@ -2133,7 +2234,8 @@ dps_and_crls(OtpCert, Callback, CRLDbHandle, ext) ->
no_dps;
DistPoints ->
Issuer = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer,
- distpoints_lookup(DistPoints, Issuer, Callback, CRLDbHandle)
+ CRLs = distpoints_lookup(DistPoints, Issuer, Callback, CRLDbHandle),
+ dps_and_crls(DistPoints, CRLs, [])
end;
dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer) ->
@@ -2146,7 +2248,13 @@ dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer) ->
end, GenNames),
[{DP, {CRL, public_key:der_decode('CertificateList', CRL)}} || CRL <- CRLs].
-distpoints_lookup([], _, _, _) ->
+dps_and_crls([], _, Acc) ->
+ Acc;
+dps_and_crls([DP | Rest], CRLs, Acc) ->
+ DpCRL = [{DP, {CRL, public_key:der_decode('CertificateList', CRL)}} || CRL <- CRLs],
+ dps_and_crls(Rest, CRLs, DpCRL ++ Acc).
+
+distpoints_lookup([],_, _, _) ->
[];
distpoints_lookup([DistPoint | Rest], Issuer, Callback, CRLDbHandle) ->
Result =
@@ -2161,30 +2269,76 @@ distpoints_lookup([DistPoint | Rest], Issuer, Callback, CRLDbHandle) ->
not_available ->
distpoints_lookup(Rest, Issuer, Callback, CRLDbHandle);
CRLs ->
- [{DistPoint, {CRL, public_key:der_decode('CertificateList', CRL)}} || CRL <- CRLs]
+ CRLs
end.
-cert_sign(?rsaEncryption) ->
+sign_algo(?rsaEncryption) ->
rsa;
-cert_sign(?'id-ecPublicKey') ->
+sign_algo(?'id-ecPublicKey') ->
ecdsa;
-cert_sign(?'id-dsa') ->
+sign_algo(?'id-dsa') ->
dsa;
-cert_sign(Alg) ->
+sign_algo(Alg) ->
{_, Sign} =public_key:pkix_sign_types(Alg),
Sign.
-is_acceptable_hash_sign({_, Sign} = Algos, Sign, _, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign(Algos,_, KeyExAlgo, SupportedHashSigns) when KeyExAlgo == dh_ecdsa;
- KeyExAlgo == ecdh_rsa;
- KeyExAlgo == ecdh_ecdsa ->
+is_acceptable_hash_sign(Algos, _, _, KeyExAlgo, SupportedHashSigns) when
+ KeyExAlgo == dh_dss;
+ KeyExAlgo == dh_rsa;
+ KeyExAlgo == dh_ecdsa ->
+ %% dh_* could be called only dh in TLS-1.2
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign(Algos, rsa, ecdsa, ecdh_rsa, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, dhe_rsa, SupportedHashSigns) ->
is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign(_,_,_,_) ->
- false.
+is_acceptable_hash_sign({_, rsa} = Algos, rsa, rsa, ecdhe_rsa, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, rsa} = Algos, rsa, rsa, rsa, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, srp_rsa, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, rsa_psk, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, dsa} = Algos, dsa, _, dhe_dss, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, dsa} = Algos, dsa, _, srp_dss, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, _, dhe_ecdsa, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, ecdsa, ecdhe_ecdsa, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns);
+is_acceptable_hash_sign(_, _, _, KeyExAlgo, _) when
+ KeyExAlgo == psk;
+ KeyExAlgo == dhe_psk;
+ KeyExAlgo == srp_anon;
+ KeyExAlgo == dh_anon;
+ KeyExAlgo == ecdhe_anon
+ ->
+ true;
+is_acceptable_hash_sign(_,_, _,_,_) ->
+ false.
+
is_acceptable_hash_sign(Algos, SupportedHashSigns) ->
lists:member(Algos, SupportedHashSigns).
+is_acceptable_cert_type(Sign, _HashSigns, Types) ->
+ lists:member(sign_type(Sign), binary_to_list(Types)).
+
+is_supported_sign(Sign, HashSigns) ->
+ [] =/= lists:dropwhile(fun({_, S}) when S =/= Sign ->
+ true;
+ (_)->
+ false
+ end, HashSigns).
+sign_type(rsa) ->
+ ?RSA_SIGN;
+sign_type(dsa) ->
+ ?DSS_SIGN;
+sign_type(ecdsa) ->
+ ?ECDSA_SIGN.
+
+
bad_key(#'DSAPrivateKey'{}) ->
unacceptable_dsa_key;
bad_key(#'RSAPrivateKey'{}) ->
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index fde92035a2..324b7dbde3 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -80,6 +80,9 @@
-define(CLIENT_KEY_EXCHANGE, 16).
-define(FINISHED, 20).
+-define(MAX_UNIT24, 8388607).
+-define(DEFAULT_MAX_HANDSHAKE_SIZE, (256*1024)).
+
-record(random, {
gmt_unix_time, % uint32
random_bytes % opaque random_bytes[28]
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index c19c1787ff..ac212a56d8 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,7 +76,7 @@
-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1]).
-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1]).
-define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
--define(MIN_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
+-define(MIN_DATAGRAM_SUPPORTED_VERSIONS, [dtlsv1]).
-define('24H_in_msec', 86400000).
-define('24H_in_sec', 86400).
@@ -140,7 +140,10 @@
crl_check :: boolean() | peer | best_effort,
crl_cache,
signature_algs,
- v2_hello_compatible :: boolean()
+ eccs,
+ honor_ecc_order :: boolean(),
+ v2_hello_compatible :: boolean(),
+ max_handshake_size :: integer()
}).
-record(socket_options,
@@ -154,7 +157,8 @@
-record(config, {ssl, %% SSL parameters
inet_user, %% User set inet options
- emulated, %% Emulated option list or "inherit_tracker" pid
+ emulated, %% Emulated option list or "inherit_tracker" pid
+ udp_handler,
inet_ssl, %% inet options for internal ssl socket
transport_info, %% Callback info
connection_cb
diff --git a/lib/ssl/src/ssl_listen_tracker_sup.erl b/lib/ssl/src/ssl_listen_tracker_sup.erl
index 7f685a2ead..f7e97bcb76 100644
--- a/lib/ssl/src/ssl_listen_tracker_sup.erl
+++ b/lib/ssl/src/ssl_listen_tracker_sup.erl
@@ -57,10 +57,10 @@ init(_O) ->
MaxT = 3600,
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssl_socket, start_link, []},
+ StartFunc = {tls_socket, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [ssl_socket],
+ Modules = [tls_socket],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index c7dcbaabe9..ca9aaf4660 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,10 +32,9 @@
new_session_id/1, clean_cert_db/2,
register_session/2, register_session/3, invalidate_session/2,
insert_crls/2, insert_crls/3, delete_crls/1, delete_crls/2,
- invalidate_session/3, invalidate_pem/1, clear_pem_cache/0, manager_name/1]).
+ invalidate_session/3, name/1]).
-% Spawn export
--export([init_session_validator/1, init_pem_cache_validator/1]).
+-export([init_session_validator/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -52,9 +51,7 @@
session_lifetime :: integer(),
certificate_db :: db_handle(),
session_validation_timer :: reference(),
- last_delay_timer = {undefined, undefined},%% Keep for testing purposes
- last_pem_check :: erlang:timestamp(),
- clear_pem_cache :: integer(),
+ last_delay_timer = {undefined, undefined},%% Keep for testing purposes
session_cache_client_max :: integer(),
session_cache_server_max :: integer(),
session_server_invalidator :: undefined | pid(),
@@ -63,7 +60,6 @@
-define(GEN_UNIQUE_ID_MAX_TRIES, 10).
-define(SESSION_VALIDATION_INTERVAL, 60000).
--define(CLEAR_PEM_CACHE, 120000).
-define(CLEAN_SESSION_DB, 60000).
-define(CLEAN_CERT_DB, 500).
-define(DEFAULT_MAX_SESSION_CACHE, 1000).
@@ -74,14 +70,14 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec manager_name(normal | dist) -> atom().
+-spec name(normal | dist) -> atom().
%%
%% Description: Returns the registered name of the ssl manager process
%% in the operation modes 'normal' and 'dist'.
%%--------------------------------------------------------------------
-manager_name(normal) ->
+name(normal) ->
?MODULE;
-manager_name(dist) ->
+name(dist) ->
list_to_atom(atom_to_list(?MODULE) ++ "dist").
%%--------------------------------------------------------------------
@@ -91,9 +87,10 @@ manager_name(dist) ->
%% and certificate caching.
%%--------------------------------------------------------------------
start_link(Opts) ->
- DistMangerName = manager_name(normal),
- gen_server:start_link({local, DistMangerName},
- ?MODULE, [DistMangerName, Opts], []).
+ MangerName = name(normal),
+ CacheName = ssl_pem_cache:name(normal),
+ gen_server:start_link({local, MangerName},
+ ?MODULE, [MangerName, CacheName, Opts], []).
%%--------------------------------------------------------------------
-spec start_link_dist(list()) -> {ok, pid()} | ignore | {error, term()}.
@@ -102,24 +99,21 @@ start_link(Opts) ->
%% be used by the erlang distribution. Note disables soft upgrade!
%%--------------------------------------------------------------------
start_link_dist(Opts) ->
- DistMangerName = manager_name(dist),
+ DistMangerName = name(dist),
+ DistCacheName = ssl_pem_cache:name(dist),
gen_server:start_link({local, DistMangerName},
- ?MODULE, [DistMangerName, Opts], []).
+ ?MODULE, [DistMangerName, DistCacheName, Opts], []).
%%--------------------------------------------------------------------
-spec connection_init(binary()| {der, list()}, client | server,
{Cb :: atom(), Handle:: term()}) ->
- {ok, certdb_ref(), db_handle(), db_handle(),
- db_handle(), db_handle(), CRLInfo::term()}.
+ {ok, map()}.
%%
%% Description: Do necessary initializations for a new connection.
%%--------------------------------------------------------------------
connection_init({der, _} = Trustedcerts, Role, CRLCache) ->
- call({connection_init, Trustedcerts, Role, CRLCache});
-
-connection_init(<<>> = Trustedcerts, Role, CRLCache) ->
- call({connection_init, Trustedcerts, Role, CRLCache});
-
+ {ok, Extracted} = ssl_pkix_db:extract_trusted_certs(Trustedcerts),
+ call({connection_init, Extracted, Role, CRLCache});
connection_init(Trustedcerts, Role, CRLCache) ->
call({connection_init, Trustedcerts, Role, CRLCache}).
@@ -129,26 +123,14 @@ connection_init(Trustedcerts, Role, CRLCache) ->
%% Description: Cache a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- case ssl_pkix_db:lookup_cached_pem(DbHandle, File) of
- [{Content,_}] ->
- {ok, Content};
- [Content] ->
+ case ssl_pkix_db:lookup(File, DbHandle) of
+ [Content] ->
{ok, Content};
undefined ->
- call({cache_pem, File})
+ ssl_pem_cache:insert(File)
end.
%%--------------------------------------------------------------------
--spec clear_pem_cache() -> ok.
-%%
-%% Description: Clear the PEM cache
-%%--------------------------------------------------------------------
-clear_pem_cache() ->
- %% Not supported for distribution at the moement, should it be?
- put(ssl_manager, manager_name(normal)),
- call(unconditionally_clear_pem_cache).
-
-%%--------------------------------------------------------------------
-spec lookup_trusted_cert(term(), reference(), serialnumber(), issuer()) ->
undefined |
{ok, {der_cert(), #'OTPCertificate'{}}}.
@@ -205,26 +187,22 @@ invalidate_session(Port, Session) ->
load_mitigation(),
cast({invalidate_session, Port, Session}).
--spec invalidate_pem(File::binary()) -> ok.
-invalidate_pem(File) ->
- cast({invalidate_pem, File}).
-
insert_crls(Path, CRLs)->
insert_crls(Path, CRLs, normal).
insert_crls(?NO_DIST_POINT_PATH = Path, CRLs, ManagerType)->
- put(ssl_manager, manager_name(ManagerType)),
+ put(ssl_manager, name(ManagerType)),
cast({insert_crls, Path, CRLs});
insert_crls(Path, CRLs, ManagerType)->
- put(ssl_manager, manager_name(ManagerType)),
+ put(ssl_manager, name(ManagerType)),
call({insert_crls, Path, CRLs}).
delete_crls(Path)->
delete_crls(Path, normal).
delete_crls(?NO_DIST_POINT_PATH = Path, ManagerType)->
- put(ssl_manager, manager_name(ManagerType)),
+ put(ssl_manager, name(ManagerType)),
cast({delete_crls, Path});
delete_crls(Path, ManagerType)->
- put(ssl_manager, manager_name(ManagerType)),
+ put(ssl_manager, name(ManagerType)),
call({delete_crls, Path}).
%%====================================================================
@@ -238,13 +216,14 @@ delete_crls(Path, ManagerType)->
%%
%% Description: Initiates the server
%%--------------------------------------------------------------------
-init([Name, Opts]) ->
- put(ssl_manager, Name),
+init([ManagerName, PemCacheName, Opts]) ->
+ put(ssl_manager, ManagerName),
+ put(ssl_pem_cache, PemCacheName),
process_flag(trap_exit, true),
CacheCb = proplists:get_value(session_cb, Opts, ssl_session_cache),
SessionLifeTime =
proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'),
- CertDb = ssl_pkix_db:create(),
+ CertDb = ssl_pkix_db:create(PemCacheName),
ClientSessionCache =
CacheCb:init([{role, client} |
proplists:get_value(session_cb_init_args, Opts, [])]),
@@ -253,16 +232,12 @@ init([Name, Opts]) ->
proplists:get_value(session_cb_init_args, Opts, [])]),
Timer = erlang:send_after(SessionLifeTime * 1000 + 5000,
self(), validate_sessions),
- Interval = pem_check_interval(),
- erlang:send_after(Interval, self(), clear_pem_cache),
{ok, #state{certificate_db = CertDb,
session_cache_client = ClientSessionCache,
session_cache_server = ServerSessionCache,
session_cache_cb = CacheCb,
session_lifetime = SessionLifeTime,
session_validation_timer = Timer,
- last_pem_check = os:timestamp(),
- clear_pem_cache = Interval,
session_cache_client_max =
max_session_cache_size(session_cache_client_max),
session_cache_server_max =
@@ -285,18 +260,25 @@ init([Name, Opts]) ->
handle_call({{connection_init, <<>>, Role, {CRLCb, UserCRLDb}}, _Pid}, _From,
#state{certificate_db = [CertDb, FileRefDb, PemChace | _] = Db} = State) ->
Ref = make_ref(),
- Result = {ok, Ref, CertDb, FileRefDb, PemChace,
- session_cache(Role, State), {CRLCb, crl_db_info(Db, UserCRLDb)}},
- {reply, Result, State#state{certificate_db = Db}};
+ {reply, {ok, #{cert_db_ref => Ref,
+ cert_db_handle => CertDb,
+ fileref_db_handle => FileRefDb,
+ pem_cache => PemChace,
+ session_cache => session_cache(Role, State),
+ crl_db_info => {CRLCb, crl_db_info(Db, UserCRLDb)}}}, State};
handle_call({{connection_init, Trustedcerts, Role, {CRLCb, UserCRLDb}}, Pid}, _From,
#state{certificate_db = [CertDb, FileRefDb, PemChace | _] = Db} = State) ->
case add_trusted_certs(Pid, Trustedcerts, Db) of
{ok, Ref} ->
- {reply, {ok, Ref, CertDb, FileRefDb, PemChace, session_cache(Role, State),
- {CRLCb, crl_db_info(Db, UserCRLDb)}}, State};
- {error, _} = Error ->
- {reply, Error, State}
+ {reply, {ok, #{cert_db_ref => Ref,
+ cert_db_handle => CertDb,
+ fileref_db_handle => FileRefDb,
+ pem_cache => PemChace,
+ session_cache => session_cache(Role, State),
+ crl_db_info => {CRLCb, crl_db_info(Db, UserCRLDb)}}}, State};
+ {error, _} = Error ->
+ {reply, Error, State}
end;
handle_call({{insert_crls, Path, CRLs}, _}, _From,
@@ -313,21 +295,7 @@ handle_call({{new_session_id, Port}, _},
_, #state{session_cache_cb = CacheCb,
session_cache_server = Cache} = State) ->
Id = new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb),
- {reply, Id, State};
-
-handle_call({{cache_pem,File}, _Pid}, _,
- #state{certificate_db = Db} = State) ->
- try ssl_pkix_db:cache_pem_file(File, Db) of
- Result ->
- {reply, Result, State}
- catch
- _:Reason ->
- {reply, {error, Reason}, State}
- end;
-handle_call({unconditionally_clear_pem_cache, _},_,
- #state{certificate_db = [_,_,PemChace | _]} = State) ->
- ssl_pkix_db:clear(PemChace),
- {reply, ok, State}.
+ {reply, Id, State}.
%%--------------------------------------------------------------------
-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
@@ -365,11 +333,6 @@ handle_cast({insert_crls, Path, CRLs},
handle_cast({delete_crls, CRLsOrPath},
#state{certificate_db = Db} = State) ->
ssl_pkix_db:remove_crls(Db, CRLsOrPath),
- {noreply, State};
-
-handle_cast({invalidate_pem, File},
- #state{certificate_db = [_, _, PemCache | _]} = State) ->
- ssl_pkix_db:remove(File, PemCache),
{noreply, State}.
%%--------------------------------------------------------------------
@@ -401,22 +364,14 @@ handle_info({delayed_clean_session, Key, Cache}, #state{session_cache_cb = Cache
CacheCb:delete(Cache, Key),
{noreply, State};
-handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace | _],
- clear_pem_cache = Interval,
- last_pem_check = CheckPoint} = State) ->
- NewCheckPoint = os:timestamp(),
- start_pem_cache_validator(PemChace, CheckPoint),
- erlang:send_after(Interval, self(), clear_pem_cache),
- {noreply, State#state{last_pem_check = NewCheckPoint}};
-
handle_info({clean_cert_db, Ref, File},
- #state{certificate_db = [CertDb,RefDb, PemCache | _]} = State) ->
+ #state{certificate_db = [CertDb, {RefDb, FileMapDb} | _]} = State) ->
case ssl_pkix_db:lookup(Ref, RefDb) of
undefined -> %% Alredy cleaned
ok;
_ ->
- clean_cert_db(Ref, CertDb, RefDb, PemCache, File)
+ clean_cert_db(Ref, CertDb, RefDb, FileMapDb, File)
end,
{noreply, State};
@@ -569,16 +524,11 @@ new_id(Port, Tries, Cache, CacheCb) ->
new_id(Port, Tries - 1, Cache, CacheCb)
end.
-clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
+clean_cert_db(Ref, CertDb, RefDb, FileMapDb, File) ->
case ssl_pkix_db:ref_count(Ref, RefDb, 0) of
0 ->
- case ssl_pkix_db:lookup_cached_pem(PemCache, File) of
- [{Content, Ref}] ->
- ssl_pkix_db:insert(File, Content, PemCache);
- _ ->
- ok
- end,
ssl_pkix_db:remove(Ref, RefDb),
+ ssl_pkix_db:remove(File, FileMapDb),
ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
_ ->
ok
@@ -662,42 +612,6 @@ exists_equivalent(#session{
exists_equivalent(Session, [ _ | Rest]) ->
exists_equivalent(Session, Rest).
-start_pem_cache_validator(PemCache, CheckPoint) ->
- spawn_link(?MODULE, init_pem_cache_validator,
- [[get(ssl_manager), PemCache, CheckPoint]]).
-
-init_pem_cache_validator([SslManagerName, PemCache, CheckPoint]) ->
- put(ssl_manager, SslManagerName),
- ssl_pkix_db:foldl(fun pem_cache_validate/2,
- CheckPoint, PemCache).
-
-pem_cache_validate({File, _}, CheckPoint) ->
- case file:read_file_info(File, []) of
- {ok, #file_info{mtime = Time}} ->
- case is_before_checkpoint(Time, CheckPoint) of
- true ->
- ok;
- false ->
- invalidate_pem(File)
- end;
- _ ->
- invalidate_pem(File)
- end,
- CheckPoint.
-
-pem_check_interval() ->
- case application:get_env(ssl, ssl_pem_cache_clean) of
- {ok, Interval} when is_integer(Interval) ->
- Interval;
- _ ->
- ?CLEAR_PEM_CACHE
- end.
-
-is_before_checkpoint(Time, CheckPoint) ->
- calendar:datetime_to_gregorian_seconds(
- calendar:now_to_datetime(CheckPoint)) -
- calendar:datetime_to_gregorian_seconds(Time) > 0.
-
add_trusted_certs(Pid, Trustedcerts, Db) ->
try
ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db)
diff --git a/lib/ssl/src/ssl_pem_cache.erl b/lib/ssl/src/ssl_pem_cache.erl
new file mode 100644
index 0000000000..6cc0729208
--- /dev/null
+++ b/lib/ssl/src/ssl_pem_cache.erl
@@ -0,0 +1,266 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 20016-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Manages ssl sessions and trusted certifacates
+%%----------------------------------------------------------------------
+
+-module(ssl_pem_cache).
+-behaviour(gen_server).
+
+%% Internal application API
+-export([start_link/1,
+ start_link_dist/1,
+ name/1,
+ insert/1,
+ clear/0]).
+
+% Spawn export
+-export([init_pem_cache_validator/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-include("ssl_handshake.hrl").
+-include("ssl_internal.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-record(state, {
+ pem_cache,
+ last_pem_check :: erlang:timestamp(),
+ clear :: integer()
+ }).
+
+-define(CLEAR_PEM_CACHE, 120000).
+-define(DEFAULT_MAX_SESSION_CACHE, 1000).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec name(normal | dist) -> atom().
+%%
+%% Description: Returns the registered name of the ssl cache process
+%% in the operation modes 'normal' and 'dist'.
+%%--------------------------------------------------------------------
+name(normal) ->
+ ?MODULE;
+name(dist) ->
+ list_to_atom(atom_to_list(?MODULE) ++ "dist").
+
+%%--------------------------------------------------------------------
+-spec start_link(list()) -> {ok, pid()} | ignore | {error, term()}.
+%%
+%% Description: Starts the ssl pem cache handler
+%%--------------------------------------------------------------------
+start_link(_) ->
+ CacheName = name(normal),
+ gen_server:start_link({local, CacheName},
+ ?MODULE, [CacheName], []).
+
+%%--------------------------------------------------------------------
+-spec start_link_dist(list()) -> {ok, pid()} | ignore | {error, term()}.
+%%
+%% Description: Starts a special instance of the ssl manager to
+%% be used by the erlang distribution. Note disables soft upgrade!
+%%--------------------------------------------------------------------
+start_link_dist(_) ->
+ DistCacheName = name(dist),
+ gen_server:start_link({local, DistCacheName},
+ ?MODULE, [DistCacheName], []).
+
+
+%%--------------------------------------------------------------------
+-spec insert(binary()) -> {ok, term()} | {error, reason()}.
+%%
+%% Description: Cache a pem file and return its content.
+%%--------------------------------------------------------------------
+insert(File) ->
+ {ok, PemBin} = file:read_file(File),
+ Content = public_key:pem_decode(PemBin),
+ case bypass_cache() of
+ true ->
+ {ok, Content};
+ false ->
+ cast({cache_pem, File, Content}),
+ {ok, Content}
+ end.
+
+%%--------------------------------------------------------------------
+-spec clear() -> ok.
+%%
+%% Description: Clear the PEM cache
+%%--------------------------------------------------------------------
+clear() ->
+ %% Not supported for distribution at the moement, should it be?
+ put(ssl_pem_cache, name(normal)),
+ call(unconditionally_clear_pem_cache).
+
+-spec invalidate_pem(File::binary()) -> ok.
+invalidate_pem(File) ->
+ cast({invalidate_pem, File}).
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec init(list()) -> {ok, #state{}}.
+%% Possible return values not used now.
+%% | {ok, #state{}, timeout()} | ignore | {stop, term()}.
+%%
+%% Description: Initiates the server
+%%--------------------------------------------------------------------
+init([Name]) ->
+ put(ssl_pem_cache, Name),
+ process_flag(trap_exit, true),
+ PemCache = ssl_pkix_db:create_pem_cache(Name),
+ Interval = pem_check_interval(),
+ erlang:send_after(Interval, self(), clear_pem_cache),
+ {ok, #state{pem_cache = PemCache,
+ last_pem_check = os:timestamp(),
+ clear = Interval
+ }}.
+
+%%--------------------------------------------------------------------
+-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}.
+%% Possible return values not used now.
+%% {reply, reply(), #state{}, timeout()} |
+%% {noreply, #state{}} |
+%% {noreply, #state{}, timeout()} |
+%% {stop, reason(), reply(), #state{}} |
+%% {stop, reason(), #state{}}.
+%%
+%% Description: Handling call messages
+%%--------------------------------------------------------------------
+handle_call({unconditionally_clear_pem_cache, _},_,
+ #state{pem_cache = PemCache} = State) ->
+ ssl_pkix_db:clear(PemCache),
+ {reply, ok, State}.
+
+%%--------------------------------------------------------------------
+-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
+%% Possible return values not used now.
+%% | {noreply, #state{}, timeout()} |
+%% {stop, reason(), #state{}}.
+%%
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast({cache_pem, File, Content}, #state{pem_cache = Db} = State) ->
+ ssl_pkix_db:insert(File, Content, Db),
+ {noreply, State};
+
+handle_cast({invalidate_pem, File}, #state{pem_cache = Db} = State) ->
+ ssl_pkix_db:remove(File, Db),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+-spec handle_info(msg(), #state{}) -> {noreply, #state{}}.
+%% Possible return values not used now.
+%% |{noreply, #state{}, timeout()} |
+%% {stop, reason(), #state{}}.
+%%
+%% Description: Handling all non call/cast messages
+%%-------------------------------------------------------------------
+handle_info(clear_pem_cache, #state{pem_cache = PemCache,
+ clear = Interval,
+ last_pem_check = CheckPoint} = State) ->
+ NewCheckPoint = os:timestamp(),
+ start_pem_cache_validator(PemCache, CheckPoint),
+ erlang:send_after(Interval, self(), clear_pem_cache),
+ {noreply, State#state{last_pem_check = NewCheckPoint}};
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+-spec terminate(reason(), #state{}) -> ok.
+%%
+%% Description: This function is called by a gen_server 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_server terminates with Reason.
+%% The return value is ignored.
+%%--------------------------------------------------------------------
+terminate(_Reason, #state{}) ->
+ ok.
+
+%%--------------------------------------------------------------------
+-spec code_change(term(), #state{}, list()) -> {ok, #state{}}.
+%%
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+call(Msg) ->
+ gen_server:call(get(ssl_pem_cache), {Msg, self()}, infinity).
+
+cast(Msg) ->
+ gen_server:cast(get(ssl_pem_cache), Msg).
+
+start_pem_cache_validator(PemCache, CheckPoint) ->
+ spawn_link(?MODULE, init_pem_cache_validator,
+ [[get(ssl_pem_cache), PemCache, CheckPoint]]).
+
+init_pem_cache_validator([CacheName, PemCache, CheckPoint]) ->
+ put(ssl_pem_cache, CacheName),
+ ssl_pkix_db:foldl(fun pem_cache_validate/2,
+ CheckPoint, PemCache).
+
+pem_cache_validate({File, _}, CheckPoint) ->
+ case file:read_file_info(File, []) of
+ {ok, #file_info{mtime = Time}} ->
+ case is_before_checkpoint(Time, CheckPoint) of
+ true ->
+ ok;
+ false ->
+ invalidate_pem(File)
+ end;
+ _ ->
+ invalidate_pem(File)
+ end,
+ CheckPoint.
+
+is_before_checkpoint(Time, CheckPoint) ->
+ calendar:datetime_to_gregorian_seconds(
+ calendar:now_to_datetime(CheckPoint)) -
+ calendar:datetime_to_gregorian_seconds(Time) > 0.
+
+pem_check_interval() ->
+ case application:get_env(ssl, ssl_pem_cache_clean) of
+ {ok, Interval} when is_integer(Interval) ->
+ Interval;
+ _ ->
+ ?CLEAR_PEM_CACHE
+ end.
+
+bypass_cache() ->
+ case application:get_env(ssl, bypass_pem_cache) of
+ {ok, Bool} when is_boolean(Bool) ->
+ Bool;
+ _ ->
+ false
+ end.
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index b16903d7c7..b28636569d 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,36 +28,43 @@
-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
--export([create/0, add_crls/3, remove_crls/2, remove/1, add_trusted_certs/3,
+-export([create/1, create_pem_cache/1,
+ add_crls/3, remove_crls/2, remove/1, add_trusted_certs/3,
+ extract_trusted_certs/1,
remove_trusted_certs/2, insert/3, remove/2, clear/1, db_size/1,
ref_count/3, lookup_trusted_cert/4, foldl/3, select_cert_by_issuer/2,
- lookup_cached_pem/2, cache_pem_file/2, cache_pem_file/3,
- lookup/2]).
+ decode_pem_file/1, lookup/2]).
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec create() -> [db_handle(),...].
+-spec create(atom()) -> [db_handle(),...].
%%
%% Description: Creates a new certificate db.
%% Note: lookup_trusted_cert/4 may be called from any process but only
%% the process that called create may call the other functions.
%%--------------------------------------------------------------------
-create() ->
+create(PEMCacheName) ->
[%% Let connection process delete trusted certs
%% that can only belong to one connection. (Supplied directly
%% on DER format to ssl:connect/listen.)
ets:new(ssl_otp_cacertificate_db, [set, public]),
%% Let connection processes call ref_count/3 directly
- ets:new(ssl_otp_ca_file_ref, [set, public]),
- ets:new(ssl_otp_pem_cache, [set, protected]),
+ {ets:new(ssl_otp_ca_file_ref, [set, public]),
+ ets:new(ssl_otp_ca_ref_file_mapping, [set, protected])
+ },
+ %% Lookups in named table owned by ssl_pem_cache process
+ PEMCacheName,
%% Default cache
{ets:new(ssl_otp_crl_cache, [set, protected]),
ets:new(ssl_otp_crl_issuer_mapping, [bag, protected])}
].
+create_pem_cache(Name) ->
+ ets:new(Name, [named_table, set, protected]).
+
%%--------------------------------------------------------------------
-spec remove([db_handle()]) -> ok.
%%
@@ -69,6 +76,10 @@ remove(Dbs) ->
true = ets:delete(Db1);
(undefined) ->
ok;
+ (ssl_pem_cache) ->
+ ok;
+ (ssl_pem_cache_dist) ->
+ ok;
(Db) ->
true = ets:delete(Db)
end, Dbs).
@@ -82,19 +93,24 @@ remove(Dbs) ->
%% <SerialNumber, Issuer>. Ref is used as it is specified
%% for each connection which certificates are trusted.
%%--------------------------------------------------------------------
-lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
+lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) when is_reference(Ref) ->
case lookup({Ref, SerialNumber, Issuer}, DbHandle) of
undefined ->
undefined;
[Certs] ->
{ok, Certs}
+ end;
+lookup_trusted_cert(_DbHandle, {extracted,Certs}, SerialNumber, Issuer) ->
+ try
+ [throw(Cert)
+ || {decoded, {{_Ref,CertSerial,CertIssuer}, Cert}} <- Certs,
+ CertSerial =:= SerialNumber, CertIssuer =:= Issuer],
+ undefined
+ catch
+ Cert ->
+ {ok, Cert}
end.
-lookup_cached_pem([_, _, PemChache | _], File) ->
- lookup_cached_pem(PemChache, File);
-lookup_cached_pem(PemChache, File) ->
- lookup(File, PemChache).
-
%%--------------------------------------------------------------------
-spec add_trusted_certs(pid(), {erlang:timestamp(), string()} |
{der, list()}, [db_handle()]) -> {ok, [db_handle()]}.
@@ -103,43 +119,48 @@ lookup_cached_pem(PemChache, File) ->
%% runtime database. Returns Ref that should be handed to lookup_trusted_cert
%% together with the cert serialnumber and issuer.
%%--------------------------------------------------------------------
+add_trusted_certs(_Pid, {extracted, _} = Certs, _) ->
+ {ok, Certs};
+
add_trusted_certs(_Pid, {der, DerList}, [CertDb, _,_ | _]) ->
NewRef = make_ref(),
add_certs_from_der(DerList, NewRef, CertDb),
{ok, NewRef};
-add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache | _] = Db) ->
- case lookup_cached_pem(Db, File) of
- [{_Content, Ref}] ->
+add_trusted_certs(_Pid, File, [ _, {RefDb, FileMapDb} | _] = Db) ->
+ case lookup(File, FileMapDb) of
+ [Ref] ->
ref_count(Ref, RefDb, 1),
{ok, Ref};
- [Content] ->
- Ref = make_ref(),
- update_counter(Ref, 1, RefDb),
- insert(File, {Content, Ref}, PemChache),
- add_certs_from_pem(Content, Ref, CertsDb),
- {ok, Ref};
undefined ->
new_trusted_cert_entry(File, Db)
end.
-%%--------------------------------------------------------------------
-%%
-%% Description: Cache file as binary in DB
-%%--------------------------------------------------------------------
--spec cache_pem_file(binary(), [db_handle()]) -> {ok, term()}.
-cache_pem_file(File, [_CertsDb, _RefDb, PemChache | _]) ->
- {ok, PemBin} = file:read_file(File),
- Content = public_key:pem_decode(PemBin),
- insert(File, Content, PemChache),
- {ok, Content}.
+extract_trusted_certs({der, DerList}) ->
+ {ok, {extracted, certs_from_der(DerList)}};
+extract_trusted_certs(File) ->
+ case file:read_file(File) of
+ {ok, PemBin} ->
+ Content = public_key:pem_decode(PemBin),
+ DerList = [Cert || {'Certificate', Cert, not_encrypted} <- Content],
+ {ok, {extracted, certs_from_der(DerList)}};
+ Error ->
+ %% Have to simulate a failure happening in a server for
+ %% external handlers.
+ {error, {badmatch, Error}}
+ end.
--spec cache_pem_file(reference(), binary(), [db_handle()]) -> {ok, term()}.
-cache_pem_file(Ref, File, [_CertsDb, _RefDb, PemChache| _]) ->
- {ok, PemBin} = file:read_file(File),
- Content = public_key:pem_decode(PemBin),
- insert(File, {Content, Ref}, PemChache),
- {ok, Content}.
+-spec decode_pem_file(binary()) -> {ok, term()}.
+decode_pem_file(File) ->
+ case file:read_file(File) of
+ {ok, PemBin} ->
+ Content = public_key:pem_decode(PemBin),
+ {ok, Content};
+ Error ->
+ %% Have to simulate a failure happening in a server for
+ %% external handlers.
+ {error, {badmatch, Error}}
+ end.
%%--------------------------------------------------------------------
-spec remove_trusted_certs(reference(), db_handle()) -> ok.
@@ -203,6 +224,10 @@ select_cert_by_issuer(Cache, Issuer) ->
%%
%% Description: Updates a reference counter in a <Db>.
%%--------------------------------------------------------------------
+ref_count({extracted, _}, _Db, _N) ->
+ not_cached;
+ref_count(Key, {Db, _}, N) ->
+ ref_count(Key, Db, N);
ref_count(Key, Db, N) ->
ets:update_counter(Db,Key,N).
@@ -235,9 +260,9 @@ insert(Key, Data, Db) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-update_counter(Key, Count, Db) ->
- true = ets:insert(Db, {Key, Count}),
- ok.
+init_ref_db(Ref, File, {RefDb, FileMapDb}) ->
+ true = ets:insert(RefDb, {Ref, 1}),
+ true = ets:insert(FileMapDb, {File, Ref}).
remove_certs(Ref, CertsDb) ->
true = ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}),
@@ -248,29 +273,45 @@ add_certs_from_der(DerList, Ref, CertsDb) ->
[Add(Cert) || Cert <- DerList],
ok.
+certs_from_der(DerList) ->
+ Ref = make_ref(),
+ [Decoded || Cert <- DerList,
+ Decoded <- [decode_certs(Ref, Cert)],
+ Decoded =/= undefined].
+
add_certs_from_pem(PemEntries, Ref, CertsDb) ->
Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end,
[Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries],
ok.
add_certs(Cert, Ref, CertsDb) ->
+ try
+ {decoded, {Key, Val}} = decode_certs(Ref, Cert),
+ insert(Key, Val, CertsDb)
+ catch
+ error:_ ->
+ ok
+ end.
+
+decode_certs(Ref, Cert) ->
try ErlCert = public_key:pkix_decode_cert(Cert, otp),
TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
Issuer = public_key:pkix_normalize_name(
TBSCertificate#'OTPTBSCertificate'.issuer),
- insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb)
+ {decoded, {{Ref, SerialNumber, Issuer}, {Cert, ErlCert}}}
catch
error:_ ->
Report = io_lib:format("SSL WARNING: Ignoring a CA cert as "
"it could not be correctly decoded.~n", []),
- error_logger:info_report(Report)
+ error_logger:info_report(Report),
+ undefined
end.
-new_trusted_cert_entry(File, [CertsDb, RefDb, _ | _] = Db) ->
+new_trusted_cert_entry(File, [CertsDb, RefsDb, _ | _]) ->
Ref = make_ref(),
- update_counter(Ref, 1, RefDb),
- {ok, Content} = cache_pem_file(Ref, File, Db),
+ init_ref_db(Ref, File, RefsDb),
+ {ok, Content} = ssl_pem_cache:insert(File),
add_certs_from_pem(Content, Ref, CertsDb),
{ok, Ref}.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 5bb1c92c2d..b10069c3cb 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -30,8 +30,7 @@
-include("ssl_alert.hrl").
%% Connection state handling
--export([init_connection_states/2,
- current_connection_state/2, pending_connection_state/2,
+-export([initial_security_params/1, current_connection_state/2, pending_connection_state/2,
activate_pending_connection_state/2,
set_security_params/3,
set_mac_secret/4,
@@ -39,11 +38,8 @@
set_pending_cipher_state/4,
set_renegotiation_flag/2,
set_client_verify_data/3,
- set_server_verify_data/3]).
-
-%% Encoding records
--export([encode_handshake/3, encode_alert_record/3,
- encode_change_cipher_spec/2, encode_data/3]).
+ set_server_verify_data/3,
+ empty_connection_state/2, initial_connection_state/2, record_protocol_role/1]).
%% Compression
-export([compress/3, uncompress/3, compressions/0]).
@@ -52,122 +48,95 @@
-export([cipher/4, decipher/4, is_correct_mac/2,
cipher_aead/4, decipher_aead/4]).
--export_type([ssl_version/0, ssl_atom_version/0]).
+%% Encoding
+-export([encode_plain_text/4]).
+
+-export_type([ssl_version/0, ssl_atom_version/0, connection_states/0, connection_state/0]).
-type ssl_version() :: {integer(), integer()}.
-type ssl_atom_version() :: tls_record:tls_atom_version().
-
+-type connection_states() :: term(). %% Map
+-type connection_state() :: term(). %% Map
%%====================================================================
%% Internal application API
%%====================================================================
+
%%--------------------------------------------------------------------
--spec init_connection_states(client | server, one_n_minus_one | zero_n | disabled ) ->
- #connection_states{}.
-%%
-%% Description: Creates a connection_states record with appropriate
-%% values for the initial SSL connection setup.
-%%--------------------------------------------------------------------
-init_connection_states(Role, BeastMitigation) ->
- ConnectionEnd = record_protocol_role(Role),
- Current = initial_connection_state(ConnectionEnd, BeastMitigation),
- Pending = empty_connection_state(ConnectionEnd, BeastMitigation),
- #connection_states{dtls_write_msg_seq = 1, % only used by dtls
- current_read = Current,
- pending_read = Pending,
- current_write = Current,
- pending_write = Pending
- }.
-
-%%--------------------------------------------------------------------
--spec current_connection_state(#connection_states{}, read | write) ->
- #connection_state{}.
+-spec current_connection_state(connection_states(), read | write) ->
+ connection_state().
%%
-%% Description: Returns the instance of the connection_state record
+%% Description: Returns the instance of the connection_state map
%% that is currently defined as the current conection state.
%%--------------------------------------------------------------------
-current_connection_state(#connection_states{current_read = Current},
- read) ->
- Current;
-current_connection_state(#connection_states{current_write = Current},
- write) ->
- Current.
+current_connection_state(ConnectionStates, read) ->
+ maps:get(current_read, ConnectionStates);
+current_connection_state(ConnectionStates, write) ->
+ maps:get(current_write, ConnectionStates).
%%--------------------------------------------------------------------
--spec pending_connection_state(#connection_states{}, read | write) ->
- term().
+-spec pending_connection_state(connection_states(), read | write) ->
+ connection_state().
%%
-%% Description: Returns the instance of the connection_state record
-%% that is currently defined as the pending conection state.
+%% Description: Returns the instance of the connection_state map
+%% that is pendingly defined as the pending conection state.
%%--------------------------------------------------------------------
-pending_connection_state(#connection_states{pending_read = Pending},
- read) ->
- Pending;
-pending_connection_state(#connection_states{pending_write = Pending},
- write) ->
- Pending.
-
+pending_connection_state(ConnectionStates, read) ->
+ maps:get(pending_read, ConnectionStates);
+pending_connection_state(ConnectionStates, write) ->
+ maps:get(pending_write, ConnectionStates).
%%--------------------------------------------------------------------
--spec activate_pending_connection_state(#connection_states{}, read | write) ->
- #connection_states{}.
+-spec activate_pending_connection_state(connection_states(), read | write) ->
+ connection_states().
%%
%% Description: Creates a new instance of the connection_states record
%% where the pending state of <Type> has been activated.
%%--------------------------------------------------------------------
-activate_pending_connection_state(States =
- #connection_states{current_read = Current,
- pending_read = Pending},
+activate_pending_connection_state(#{current_read := Current,
+ pending_read := Pending} = States,
read) ->
- NewCurrent = Pending#connection_state{epoch = dtls_next_epoch(Current),
- sequence_number = 0},
- BeastMitigation = Pending#connection_state.beast_mitigation,
- SecParams = Pending#connection_state.security_parameters,
+ #{secure_renegotiation := SecureRenegotation} = Current,
+ #{beast_mitigation := BeastMitigation,
+ security_parameters := SecParams} = Pending,
+ NewCurrent = Pending#{sequence_number => 0},
ConnectionEnd = SecParams#security_parameters.connection_end,
EmptyPending = empty_connection_state(ConnectionEnd, BeastMitigation),
- SecureRenegotation = NewCurrent#connection_state.secure_renegotiation,
- NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation},
- States#connection_states{current_read = NewCurrent,
- pending_read = NewPending
- };
-
-activate_pending_connection_state(States =
- #connection_states{current_write = Current,
- pending_write = Pending},
+ NewPending = EmptyPending#{secure_renegotiation => SecureRenegotation},
+ States#{current_read => NewCurrent,
+ pending_read => NewPending
+ };
+
+activate_pending_connection_state(#{current_write := Current,
+ pending_write := Pending} = States,
write) ->
- NewCurrent = Pending#connection_state{epoch = dtls_next_epoch(Current),
- sequence_number = 0},
- BeastMitigation = Pending#connection_state.beast_mitigation,
- SecParams = Pending#connection_state.security_parameters,
+ NewCurrent = Pending#{sequence_number => 0},
+ #{secure_renegotiation := SecureRenegotation} = Current,
+ #{beast_mitigation := BeastMitigation,
+ security_parameters := SecParams} = Pending,
ConnectionEnd = SecParams#security_parameters.connection_end,
EmptyPending = empty_connection_state(ConnectionEnd, BeastMitigation),
- SecureRenegotation = NewCurrent#connection_state.secure_renegotiation,
- NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation},
- States#connection_states{current_write = NewCurrent,
- pending_write = NewPending
- }.
-
+ NewPending = EmptyPending#{secure_renegotiation => SecureRenegotation},
+ States#{current_write => NewCurrent,
+ pending_write => NewPending
+ }.
%%--------------------------------------------------------------------
-spec set_security_params(#security_parameters{}, #security_parameters{},
- #connection_states{}) -> #connection_states{}.
+ connection_states()) -> connection_states().
%%
%% Description: Creates a new instance of the connection_states record
%% where the pending states gets its security parameters updated.
%%--------------------------------------------------------------------
-set_security_params(ReadParams, WriteParams, States =
- #connection_states{pending_read = Read,
- pending_write = Write}) ->
- States#connection_states{pending_read =
- Read#connection_state{security_parameters =
- ReadParams},
- pending_write =
- Write#connection_state{security_parameters =
- WriteParams}
- }.
+set_security_params(ReadParams, WriteParams,
+ #{pending_read := Read,
+ pending_write := Write} = States) ->
+ States#{pending_read => Read#{security_parameters => ReadParams},
+ pending_write => Write#{security_parameters => WriteParams}
+ }.
%%--------------------------------------------------------------------
-spec set_mac_secret(binary(), binary(), client | server,
- #connection_states{}) -> #connection_states{}.
+ connection_states()) -> connection_states().
%%
%% Description: update the mac_secret field in pending connection states
%%--------------------------------------------------------------------
@@ -177,203 +146,151 @@ set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret, server, States) ->
set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret, States).
set_mac_secret(ReadMacSecret, WriteMacSecret,
- States = #connection_states{pending_read = Read,
- pending_write = Write}) ->
- States#connection_states{
- pending_read = Read#connection_state{mac_secret = ReadMacSecret},
- pending_write = Write#connection_state{mac_secret = WriteMacSecret}
+ States = #{pending_read := Read,
+ pending_write := Write}) ->
+ States#{pending_read => Read#{mac_secret => ReadMacSecret},
+ pending_write => Write#{mac_secret => WriteMacSecret}
}.
%%--------------------------------------------------------------------
--spec set_master_secret(binary(), #connection_states{}) -> #connection_states{}.
+-spec set_master_secret(binary(), connection_states()) -> connection_states().
%%
%% Description: Set master_secret in pending connection states
%%--------------------------------------------------------------------
set_master_secret(MasterSecret,
- States = #connection_states{pending_read = Read,
- pending_write = Write}) ->
- ReadSecPar = Read#connection_state.security_parameters,
- Read1 = Read#connection_state{
- security_parameters = ReadSecPar#security_parameters{
- master_secret = MasterSecret}},
- WriteSecPar = Write#connection_state.security_parameters,
- Write1 = Write#connection_state{
- security_parameters = WriteSecPar#security_parameters{
- master_secret = MasterSecret}},
- States#connection_states{pending_read = Read1, pending_write = Write1}.
-
-%%--------------------------------------------------------------------
--spec set_renegotiation_flag(boolean(), #connection_states{}) -> #connection_states{}.
+ States = #{pending_read := Read = #{security_parameters := ReadSecPar},
+ pending_write := Write = #{security_parameters := WriteSecPar}}) ->
+ Read1 = Read#{security_parameters => ReadSecPar#security_parameters{
+ master_secret = MasterSecret}},
+ Write1 = Write#{security_parameters => WriteSecPar#security_parameters{
+ master_secret = MasterSecret}},
+ States#{pending_read => Read1, pending_write => Write1}.
+
+%%--------------------------------------------------------------------
+-spec set_renegotiation_flag(boolean(), connection_states()) -> connection_states().
%%
%% Description: Set secure_renegotiation in pending connection states
%%--------------------------------------------------------------------
-set_renegotiation_flag(Flag, #connection_states{
- current_read = CurrentRead0,
- current_write = CurrentWrite0,
- pending_read = PendingRead0,
- pending_write = PendingWrite0}
+set_renegotiation_flag(Flag, #{current_read := CurrentRead0,
+ current_write := CurrentWrite0,
+ pending_read := PendingRead0,
+ pending_write := PendingWrite0}
= ConnectionStates) ->
- CurrentRead = CurrentRead0#connection_state{secure_renegotiation = Flag},
- CurrentWrite = CurrentWrite0#connection_state{secure_renegotiation = Flag},
- PendingRead = PendingRead0#connection_state{secure_renegotiation = Flag},
- PendingWrite = PendingWrite0#connection_state{secure_renegotiation = Flag},
- ConnectionStates#connection_states{current_read = CurrentRead,
- current_write = CurrentWrite,
- pending_read = PendingRead,
- pending_write = PendingWrite}.
+ CurrentRead = CurrentRead0#{secure_renegotiation => Flag},
+ CurrentWrite = CurrentWrite0#{secure_renegotiation => Flag},
+ PendingRead = PendingRead0#{secure_renegotiation => Flag},
+ PendingWrite = PendingWrite0#{secure_renegotiation => Flag},
+ ConnectionStates#{current_read => CurrentRead,
+ current_write => CurrentWrite,
+ pending_read => PendingRead,
+ pending_write => PendingWrite}.
%%--------------------------------------------------------------------
-spec set_client_verify_data(current_read | current_write | current_both,
- binary(), #connection_states{})->
- #connection_states{}.
+ binary(), connection_states())->
+ connection_states().
%%
%% Description: Set verify data in connection states.
%%--------------------------------------------------------------------
set_client_verify_data(current_read, Data,
- #connection_states{current_read = CurrentRead0,
- pending_write = PendingWrite0}
+ #{current_read := CurrentRead0,
+ pending_write := PendingWrite0}
= ConnectionStates) ->
- CurrentRead = CurrentRead0#connection_state{client_verify_data = Data},
- PendingWrite = PendingWrite0#connection_state{client_verify_data = Data},
- ConnectionStates#connection_states{current_read = CurrentRead,
- pending_write = PendingWrite};
+ CurrentRead = CurrentRead0#{client_verify_data => Data},
+ PendingWrite = PendingWrite0#{client_verify_data => Data},
+ ConnectionStates#{current_read => CurrentRead,
+ pending_write => PendingWrite};
set_client_verify_data(current_write, Data,
- #connection_states{pending_read = PendingRead0,
- current_write = CurrentWrite0}
+ #{pending_read := PendingRead0,
+ current_write := CurrentWrite0}
= ConnectionStates) ->
- PendingRead = PendingRead0#connection_state{client_verify_data = Data},
- CurrentWrite = CurrentWrite0#connection_state{client_verify_data = Data},
- ConnectionStates#connection_states{pending_read = PendingRead,
- current_write = CurrentWrite};
+ PendingRead = PendingRead0#{client_verify_data => Data},
+ CurrentWrite = CurrentWrite0#{client_verify_data => Data},
+ ConnectionStates#{pending_read => PendingRead,
+ current_write => CurrentWrite};
set_client_verify_data(current_both, Data,
- #connection_states{current_read = CurrentRead0,
- current_write = CurrentWrite0}
+ #{current_read := CurrentRead0,
+ current_write := CurrentWrite0}
= ConnectionStates) ->
- CurrentRead = CurrentRead0#connection_state{client_verify_data = Data},
- CurrentWrite = CurrentWrite0#connection_state{client_verify_data = Data},
- ConnectionStates#connection_states{current_read = CurrentRead,
- current_write = CurrentWrite}.
+ CurrentRead = CurrentRead0#{client_verify_data => Data},
+ CurrentWrite = CurrentWrite0#{client_verify_data => Data},
+ ConnectionStates#{current_read => CurrentRead,
+ current_write => CurrentWrite}.
%%--------------------------------------------------------------------
-spec set_server_verify_data(current_read | current_write | current_both,
- binary(), #connection_states{})->
- #connection_states{}.
+ binary(), connection_states())->
+ connection_states().
%%
%% Description: Set verify data in pending connection states.
%%--------------------------------------------------------------------
set_server_verify_data(current_write, Data,
- #connection_states{pending_read = PendingRead0,
- current_write = CurrentWrite0}
+ #{pending_read := PendingRead0,
+ current_write := CurrentWrite0}
= ConnectionStates) ->
- PendingRead = PendingRead0#connection_state{server_verify_data = Data},
- CurrentWrite = CurrentWrite0#connection_state{server_verify_data = Data},
- ConnectionStates#connection_states{pending_read = PendingRead,
- current_write = CurrentWrite};
+ PendingRead = PendingRead0#{server_verify_data => Data},
+ CurrentWrite = CurrentWrite0#{server_verify_data => Data},
+ ConnectionStates#{pending_read => PendingRead,
+ current_write => CurrentWrite};
set_server_verify_data(current_read, Data,
- #connection_states{current_read = CurrentRead0,
- pending_write = PendingWrite0}
+ #{current_read := CurrentRead0,
+ pending_write := PendingWrite0}
= ConnectionStates) ->
- CurrentRead = CurrentRead0#connection_state{server_verify_data = Data},
- PendingWrite = PendingWrite0#connection_state{server_verify_data = Data},
- ConnectionStates#connection_states{current_read = CurrentRead,
- pending_write = PendingWrite};
+ CurrentRead = CurrentRead0#{server_verify_data => Data},
+ PendingWrite = PendingWrite0#{server_verify_data => Data},
+ ConnectionStates#{current_read => CurrentRead,
+ pending_write => PendingWrite};
set_server_verify_data(current_both, Data,
- #connection_states{current_read = CurrentRead0,
- current_write = CurrentWrite0}
+ #{current_read := CurrentRead0,
+ current_write := CurrentWrite0}
= ConnectionStates) ->
- CurrentRead = CurrentRead0#connection_state{server_verify_data = Data},
- CurrentWrite = CurrentWrite0#connection_state{server_verify_data = Data},
- ConnectionStates#connection_states{current_read = CurrentRead,
- current_write = CurrentWrite}.
+ CurrentRead = CurrentRead0#{server_verify_data => Data},
+ CurrentWrite = CurrentWrite0#{server_verify_data => Data},
+ ConnectionStates#{current_read => CurrentRead,
+ current_write => CurrentWrite}.
%%--------------------------------------------------------------------
--spec set_pending_cipher_state(#connection_states{}, #cipher_state{},
+-spec set_pending_cipher_state(connection_states(), #cipher_state{},
#cipher_state{}, client | server) ->
- #connection_states{}.
+ connection_states().
%%
%% Description: Set the cipher state in the specified pending connection state.
%%--------------------------------------------------------------------
-set_pending_cipher_state(#connection_states{pending_read = Read,
- pending_write = Write} = States,
+set_pending_cipher_state(#{pending_read := Read,
+ pending_write := Write} = States,
ClientState, ServerState, server) ->
- States#connection_states{
- pending_read = Read#connection_state{cipher_state = ClientState},
- pending_write = Write#connection_state{cipher_state = ServerState}};
+ States#{
+ pending_read => Read#{cipher_state => ClientState},
+ pending_write => Write#{cipher_state => ServerState}};
-set_pending_cipher_state(#connection_states{pending_read = Read,
- pending_write = Write} = States,
+set_pending_cipher_state(#{pending_read := Read,
+ pending_write := Write} = States,
ClientState, ServerState, client) ->
- States#connection_states{
- pending_read = Read#connection_state{cipher_state = ServerState},
- pending_write = Write#connection_state{cipher_state = ClientState}}.
-
-
-%%--------------------------------------------------------------------
--spec encode_handshake(iolist(), ssl_version(), #connection_states{}) ->
- {iolist(), #connection_states{}}.
-%%
-%% Description: Encodes a handshake message to send on the ssl-socket.
-%%--------------------------------------------------------------------
-encode_handshake(Frag, Version,
- #connection_states{current_write =
- #connection_state{
- beast_mitigation = BeastMitigation,
- security_parameters =
- #security_parameters{bulk_cipher_algorithm = BCA}}} =
- ConnectionStates)
-when is_list(Frag) ->
- case iolist_size(Frag) of
- N when N > ?MAX_PLAIN_TEXT_LENGTH ->
- Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
- encode_iolist(?HANDSHAKE, Data, Version, ConnectionStates);
- _ ->
- encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
- end;
-%% TODO: this is a workarround for DTLS
-%%
-%% DTLS need to select the connection write state based on Epoch it wants to
-%% send this fragment in. That Epoch does not nessarily has to be the same
-%% as the current_write epoch.
-%% The right solution might be to pass the WriteState instead of the ConnectionStates,
-%% however, this will require substantion API changes.
-encode_handshake(Frag, Version, ConnectionStates) ->
- encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
-
-%%--------------------------------------------------------------------
--spec encode_alert_record(#alert{}, ssl_version(), #connection_states{}) ->
- {iolist(), #connection_states{}}.
-%%
-%% Description: Encodes an alert message to send on the ssl-socket.
-%%--------------------------------------------------------------------
-encode_alert_record(#alert{level = Level, description = Description},
- Version, ConnectionStates) ->
- encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
- ConnectionStates).
-
-%%--------------------------------------------------------------------
--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.
-%%--------------------------------------------------------------------
-encode_change_cipher_spec(Version, ConnectionStates) ->
- encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
-
-%%--------------------------------------------------------------------
--spec encode_data(binary(), ssl_version(), #connection_states{}) ->
- {iolist(), #connection_states{}}.
-%%
-%% Description: Encodes data to send on the ssl-socket.
-%%--------------------------------------------------------------------
-encode_data(Frag, Version,
- #connection_states{current_write = #connection_state{
- beast_mitigation = BeastMitigation,
- security_parameters =
- #security_parameters{bulk_cipher_algorithm = BCA}}} =
- ConnectionStates) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
- encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
+ States#{
+ pending_read => Read#{cipher_state => ServerState},
+ pending_write => Write#{cipher_state => ClientState}}.
+
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}
+ } = WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ AAD = ssl_cipher:calc_aad(Type, Version, WriteState1),
+ ssl_record:cipher_aead(Version, Comp, WriteState1, AAD);
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}
+ }= WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ MacHash = ssl_cipher:calc_mac_hash(Type, Version, Comp, WriteState1),
+ ssl_record:cipher(Version, Comp, WriteState1, MacHash);
+encode_plain_text(_,_,_,CS) ->
+ exit({cs, CS}).
uncompress(?NULL, Data, CS) ->
{Data, CS}.
@@ -390,73 +307,74 @@ compressions() ->
[?byte(?NULL)].
%%--------------------------------------------------------------------
--spec cipher(ssl_version(), iodata(), #connection_state{}, MacHash::binary()) ->
- {CipherFragment::binary(), #connection_state{}}.
+-spec cipher(ssl_version(), iodata(), connection_state(), MacHash::binary()) ->
+ {CipherFragment::binary(), connection_state()}.
%%
%% Description: Payload encryption
%%--------------------------------------------------------------------
cipher(Version, Fragment,
- #connection_state{cipher_state = CipherS0,
- security_parameters=
- #security_parameters{bulk_cipher_algorithm =
- BulkCipherAlgo}
- } = WriteState0, MacHash) ->
-
+ #{cipher_state := CipherS0,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm =
+ BulkCipherAlgo}
+ } = WriteState0, MacHash) ->
+
{CipherFragment, CipherS1} =
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
- {CipherFragment, WriteState0#connection_state{cipher_state = CipherS1}}.
+ {CipherFragment, WriteState0#{cipher_state => CipherS1}}.
%%--------------------------------------------------------------------
--spec cipher_aead(ssl_version(), iodata(), #connection_state{}, MacHash::binary()) ->
- {CipherFragment::binary(), #connection_state{}}.
+-spec cipher_aead(ssl_version(), iodata(), connection_state(), MacHash::binary()) ->
+ {CipherFragment::binary(), connection_state()}.
%%
%% Description: Payload encryption
%%--------------------------------------------------------------------
cipher_aead(Version, Fragment,
- #connection_state{cipher_state = CipherS0,
- sequence_number = SeqNo,
- security_parameters=
- #security_parameters{bulk_cipher_algorithm =
- BulkCipherAlgo}
- } = WriteState0, AAD) ->
-
+ #{cipher_state := CipherS0,
+ sequence_number := SeqNo,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm =
+ BulkCipherAlgo}
+ } = WriteState0, AAD) ->
+
{CipherFragment, CipherS1} =
ssl_cipher:cipher_aead(BulkCipherAlgo, CipherS0, SeqNo, AAD, Fragment, Version),
- {CipherFragment, WriteState0#connection_state{cipher_state = CipherS1}}.
+ {CipherFragment, WriteState0#{cipher_state => CipherS1}}.
%%--------------------------------------------------------------------
--spec decipher(ssl_version(), binary(), #connection_state{}, boolean()) -> {binary(), binary(), #connection_state{}} | #alert{}.
+-spec decipher(ssl_version(), binary(), connection_state(), boolean()) -> {binary(), binary(), connection_state} | #alert{}.
%%
%% Description: Payload decryption
%%--------------------------------------------------------------------
decipher(Version, CipherFragment,
- #connection_state{security_parameters =
- #security_parameters{bulk_cipher_algorithm =
- BulkCipherAlgo,
- hash_size = HashSz},
- cipher_state = CipherS0
- } = ReadState, PaddingCheck) ->
+ #{security_parameters :=
+ #security_parameters{bulk_cipher_algorithm =
+ BulkCipherAlgo,
+ hash_size = HashSz},
+ cipher_state := CipherS0
+ } = ReadState, PaddingCheck) ->
case ssl_cipher:decipher(BulkCipherAlgo, HashSz, CipherS0, CipherFragment, Version, PaddingCheck) of
{PlainFragment, Mac, CipherS1} ->
- CS1 = ReadState#connection_state{cipher_state = CipherS1},
+ CS1 = ReadState#{cipher_state => CipherS1},
{PlainFragment, Mac, CS1};
#alert{} = Alert ->
Alert
end.
%%--------------------------------------------------------------------
--spec decipher_aead(ssl_version(), binary(), #connection_state{}, binary()) -> {binary(), binary(), #connection_state{}} | #alert{}.
+-spec decipher_aead(ssl_version(), binary(), connection_state(), binary()) ->
+ {binary(), binary(), connection_state()} | #alert{}.
%%
%% Description: Payload decryption
%%--------------------------------------------------------------------
decipher_aead(Version, CipherFragment,
- #connection_state{sequence_number = SeqNo,
- security_parameters =
- #security_parameters{bulk_cipher_algorithm =
- BulkCipherAlgo},
- cipher_state = CipherS0
- } = ReadState, AAD) ->
+ #{sequence_number := SeqNo,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm =
+ BulkCipherAlgo},
+ cipher_state := CipherS0
+ } = ReadState, AAD) ->
case ssl_cipher:decipher_aead(BulkCipherAlgo, CipherS0, SeqNo, AAD, CipherFragment, Version) of
{PlainFragment, CipherS1} ->
- CS1 = ReadState#connection_state{cipher_state = CipherS1},
+ CS1 = ReadState#{cipher_state => CipherS1},
{PlainFragment, CS1};
#alert{} = Alert ->
Alert
@@ -466,8 +384,15 @@ decipher_aead(Version, CipherFragment,
%%--------------------------------------------------------------------
empty_connection_state(ConnectionEnd, BeastMitigation) ->
SecParams = empty_security_params(ConnectionEnd),
- #connection_state{security_parameters = SecParams,
- beast_mitigation = BeastMitigation}.
+ #{security_parameters => SecParams,
+ beast_mitigation => BeastMitigation,
+ compression_state => undefined,
+ cipher_state => undefined,
+ mac_secret => undefined,
+ secure_renegotiation => undefined,
+ client_verify_data => undefined,
+ server_verify_data => undefined
+ }.
empty_security_params(ConnectionEnd = ?CLIENT) ->
#security_parameters{connection_end = ConnectionEnd,
@@ -481,11 +406,6 @@ random() ->
Random_28_bytes = ssl_cipher:random_bytes(28),
<<?UINT32(Secs_since_1970), Random_28_bytes/binary>>.
-dtls_next_epoch(#connection_state{epoch = undefined}) -> %% SSL/TLS
- undefined;
-dtls_next_epoch(#connection_state{epoch = Epoch}) -> %% DTLS
- Epoch + 1.
-
is_correct_mac(Mac, Mac) ->
true;
is_correct_mac(_M,_H) ->
@@ -497,58 +417,20 @@ record_protocol_role(server) ->
?SERVER.
initial_connection_state(ConnectionEnd, BeastMitigation) ->
- #connection_state{security_parameters =
- initial_security_params(ConnectionEnd),
- sequence_number = 0,
- beast_mitigation = BeastMitigation
- }.
+ #{security_parameters =>
+ initial_security_params(ConnectionEnd),
+ sequence_number => 0,
+ beast_mitigation => BeastMitigation,
+ compression_state => undefined,
+ cipher_state => undefined,
+ mac_secret => undefined,
+ secure_renegotiation => undefined,
+ client_verify_data => undefined,
+ server_verify_data => undefined
+ }.
initial_security_params(ConnectionEnd) ->
SecParams = #security_parameters{connection_end = ConnectionEnd,
compression_algorithm = ?NULL},
ssl_cipher:security_parameters(?TLS_NULL_WITH_NULL_NULL, SecParams).
-
-encode_plain_text(Type, Version, Data, ConnectionStates) ->
- RecordCB = protocol_module(Version),
- RecordCB:encode_plain_text(Type, Version, Data, ConnectionStates).
-
-encode_iolist(Type, Data, Version, ConnectionStates0) ->
- RecordCB = protocol_module(Version),
- {ConnectionStates, EncodedMsg} =
- lists:foldl(fun(Text, {CS0, Encoded}) ->
- {Enc, CS1} =
- RecordCB:encode_plain_text(Type, Version, Text, CS0),
- {CS1, [Enc | Encoded]}
- end, {ConnectionStates0, []}, Data),
- {lists:reverse(EncodedMsg), ConnectionStates}.
-
-%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
-%% not vulnerable to this attack.
-split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version, BCA, one_n_minus_one) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- do_split_bin(Rest, ChunkSize, [[FirstByte]]);
-%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
-%% splitting.
-split_bin(Bin, ChunkSize, Version, BCA, zero_n) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- do_split_bin(Bin, ChunkSize, [[<<>>]]);
-split_bin(Bin, ChunkSize, _, _, _) ->
- do_split_bin(Bin, ChunkSize, []).
-
-do_split_bin(<<>>, _, Acc) ->
- lists:reverse(Acc);
-do_split_bin(Bin, ChunkSize, Acc) ->
- case Bin of
- <<Chunk:ChunkSize/binary, Rest/binary>> ->
- do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
- _ ->
- lists:reverse(Acc, [Bin])
- end.
-
-protocol_module({3, _}) ->
- tls_record;
-protocol_module({254, _}) ->
- dtls_record.
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index a41264ff9b..ed007f58d7 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -30,29 +30,27 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Connection states - RFC 4346 section 6.1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--record(connection_state, {
- security_parameters,
- compression_state,
- cipher_state,
- mac_secret,
- epoch, %% Only used by DTLS
- sequence_number,
- %% RFC 5746
- secure_renegotiation,
- client_verify_data,
- server_verify_data,
- %% How to do BEAST mitigation?
- beast_mitigation
- }).
-
--record(connection_states, {
- dtls_write_msg_seq, %% Only used by DTLS
+%% For documentation purposes are now maps in implementation
+%% -record(connection_state, {
+%% security_parameters,
+%% compression_state,
+%% cipher_state,
+%% mac_secret,
+%% sequence_number,
+%% %% RFC 5746
+%% secure_renegotiation,
+%% client_verify_data,
+%% server_verify_data,
+%% %% How to do BEAST mitigation?
+%% beast_mitigation
+%% }).
- current_read,
- pending_read,
- current_write,
- pending_write
- }).
+%% -record(connection_states, {
+%% current_read,
+%% pending_read,
+%% current_write,
+%% pending_write,
+%% }).
-record(security_parameters, {
cipher_suite,
diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl
index 7fa1f7dc9e..05a7aaaa82 100644
--- a/lib/ssl/src/ssl_sup.erl
+++ b/lib/ssl/src/ssl_sup.erl
@@ -25,7 +25,7 @@
-behaviour(supervisor).
%% API
--export([start_link/0, manager_opts/0]).
+-export([start_link/0]).
%% Supervisor callback
-export([init/1]).
@@ -44,78 +44,28 @@ start_link() ->
%%%=========================================================================
init([]) ->
- SessionCertManager = session_and_cert_manager_child_spec(),
- TLSConnetionManager = tls_connection_manager_child_spec(),
- %% Not supported yet
- %%DTLSConnetionManager = tls_connection_manager_child_spec(),
- %% Handles emulated options so that they inherited by the accept socket, even when setopts is performed on
- %% the listen socket
- ListenOptionsTracker = listen_options_tracker_child_spec(),
- {ok, {{one_for_all, 10, 3600}, [SessionCertManager, TLSConnetionManager, ListenOptionsTracker]}}.
+ {ok, {{rest_for_one, 10, 3600}, [ssl_admin_child_spec(),
+ ssl_connection_sup()
+ ]}}.
-
-manager_opts() ->
- CbOpts = case application:get_env(ssl, session_cb) of
- {ok, Cb} when is_atom(Cb) ->
- InitArgs = session_cb_init_args(),
- [{session_cb, Cb}, {session_cb_init_args, InitArgs}];
- _ ->
- []
- end,
- case application:get_env(ssl, session_lifetime) of
- {ok, Time} when is_integer(Time) ->
- [{session_lifetime, Time}| CbOpts];
- _ ->
- CbOpts
- end.
-
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-
-session_and_cert_manager_child_spec() ->
- Opts = manager_opts(),
- Name = ssl_manager,
- StartFunc = {ssl_manager, start_link, [Opts]},
- Restart = permanent,
- Shutdown = 4000,
- Modules = [ssl_manager],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-tls_connection_manager_child_spec() ->
- Name = tls_connection,
- StartFunc = {tls_connection_sup, start_link, []},
+ssl_admin_child_spec() ->
+ Name = ssl_admin_sup,
+ StartFunc = {ssl_admin_sup, start_link, []},
Restart = permanent,
Shutdown = 4000,
- Modules = [tls_connection_sup],
+ Modules = [ssl_admin_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-%% dtls_connection_manager_child_spec() ->
-%% Name = dtls_connection,
-%% StartFunc = {dtls_connection_sup, start_link, []},
-%% Restart = permanent,
-%% Shutdown = 4000,
-%% Modules = [dtls_connection, ssl_connection],
-%% Type = supervisor,
-%% {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-
-listen_options_tracker_child_spec() ->
- Name = ssl_socket,
- StartFunc = {ssl_listen_tracker_sup, start_link, []},
- Restart = permanent,
+ssl_connection_sup() ->
+ Name = ssl_connection_sup,
+ StartFunc = {ssl_connection_sup, start_link, []},
+ Restart = permanent,
Shutdown = 4000,
- Modules = [ssl_socket],
+ Modules = [ssl_connection_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-session_cb_init_args() ->
- case application:get_env(ssl, session_cb_init_args) of
- {ok, Args} when is_list(Args) ->
- Args;
- _ ->
- []
- end.
diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl
index a920f54ed2..08947f24dd 100644
--- a/lib/ssl/src/ssl_tls_dist_proxy.erl
+++ b/lib/ssl/src/ssl_tls_dist_proxy.erl
@@ -117,7 +117,7 @@ handle_call({listen, Driver, Name}, _From, State) ->
{ok, WorldTcpAddress} = get_tcp_address(World),
{_,Port} = WorldTcpAddress#net_address.address,
ErlEpmd = net_kernel:epmd_module(),
- case ErlEpmd:register_node(Name, Port) of
+ case ErlEpmd:register_node(Name, Port, Driver) of
{ok, Creation} ->
{reply, {ok, {Socket, TcpAddress, Creation}},
State#state{listen={Socket, World}}};
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 9880befa94..b18c69c740 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,33 +45,30 @@
%% Setup
-export([start_fsm/8, start_link/7, init/1]).
+-export([encode_data/3, encode_alert/3]).
+
%% State transition handling
--export([next_record/1, next_event/3]).
+-export([next_record/1, next_event/3, next_event/4]).
%% Handshake handling
-export([renegotiate/2, send_handshake/2,
queue_handshake/2, queue_change_cipher/2,
- reinit_handshake_data/1, handle_sni_extension/2]).
+ reinit_handshake_data/1, select_sni_extension/1]).
%% Alert and close handling
--export([send_alert/2, handle_own_alert/4, handle_close_alert/3,
- handle_normal_shutdown/3,
- close/5, alert_user/6, alert_user/9
- ]).
+-export([send_alert/2, close/5]).
%% Data handling
--export([write_application_data/3, read_application_data/2,
- passive_receive/2, next_record_if_active/1, handle_common_event/4]).
+-export([passive_receive/2, next_record_if_active/1, handle_common_event/4, send/3,
+ socket/5]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
connection/3]).
%% gen_statem callbacks
--export([terminate/3, code_change/4, format_status/2]).
+-export([callback_mode/0, terminate/3, code_change/4, format_status/2]).
--define(GEN_STATEM_CB_MODE, state_functions).
-
%%====================================================================
%% Internal application API
%%====================================================================
@@ -109,9 +106,10 @@ send_handshake(Handshake, State) ->
queue_handshake(Handshake, #state{negotiated_version = Version,
tls_handshake_history = Hist0,
flight_buffer = Flight0,
+ ssl_options = #ssl_options{v2_hello_compatible = V2HComp},
connection_states = ConnectionStates0} = State0) ->
{BinHandshake, ConnectionStates, Hist} =
- encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
+ encode_handshake(Handshake, Version, ConnectionStates0, Hist0, V2HComp),
State0#state{connection_states = ConnectionStates,
tls_handshake_history = Hist,
flight_buffer = Flight0 ++ [BinHandshake]}.
@@ -119,8 +117,8 @@ queue_handshake(Handshake, #state{negotiated_version = Version,
send_handshake_flight(#state{socket = Socket,
transport_cb = Transport,
flight_buffer = Flight} = State0) ->
- Transport:send(Socket, Flight),
- State0#state{flight_buffer = []}.
+ send(Transport, Socket, Flight),
+ {State0#state{flight_buffer = []}, []}.
queue_change_cipher(Msg, #state{negotiated_version = Version,
flight_buffer = Flight0,
@@ -135,8 +133,8 @@ send_alert(Alert, #state{negotiated_version = Version,
transport_cb = Transport,
connection_states = ConnectionStates0} = State0) ->
{BinMsg, ConnectionStates} =
- ssl_alert:encode(Alert, Version, ConnectionStates0),
- Transport:send(Socket, BinMsg),
+ encode_alert(Alert, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
State0#state{connection_states = ConnectionStates}.
reinit_handshake_data(State) ->
@@ -149,6 +147,23 @@ reinit_handshake_data(State) ->
tls_handshake_history = ssl_handshake:init_handshake_history()
}.
+select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
+ HelloExtensions#hello_extensions.sni;
+select_sni_extension(_) ->
+ undefined.
+
+encode_data(Data, Version, ConnectionStates0)->
+ tls_record:encode_data(Data, Version, ConnectionStates0).
+
+%%--------------------------------------------------------------------
+-spec encode_alert(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert
+%%--------------------------------------------------------------------
+encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
+ tls_record:encode_alert_record(Alert, Version, ConnectionStates).
+
%%====================================================================
%% tls_connection_sup API
%%====================================================================
@@ -169,11 +184,18 @@ init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
- gen_statem:enter_loop(?MODULE, [], ?GEN_STATEM_CB_MODE, init, State)
+ gen_statem:enter_loop(?MODULE, [], init, State)
catch throw:Error ->
- gen_statem:enter_loop(?MODULE, [], ?GEN_STATEM_CB_MODE, error, {Error, State0})
+ gen_statem:enter_loop(?MODULE, [], error, {Error, State0})
end.
+callback_mode() ->
+ state_functions.
+
+socket(Pid, Transport, Socket, Connection, Tracker) ->
+ tls_socket:socket(Pid, Transport, Socket, Connection, Tracker).
+
+
%%--------------------------------------------------------------------
%% State functions
%%--------------------------------------------------------------------
@@ -185,7 +207,7 @@ init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
init({call, From}, {start, Timeout},
#state{host = Host, port = Port, role = client,
- ssl_options = SslOpts,
+ ssl_options = #ssl_options{v2_hello_compatible = V2HComp} = SslOpts,
session = #session{own_certificate = Cert} = Session0,
transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates0,
@@ -201,8 +223,8 @@ init({call, From}, {start, Timeout},
HelloVersion = tls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
Handshake0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
- encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0),
- Transport:send(Socket, BinMsg),
+ encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0, V2HComp),
+ send(Transport, Socket, BinMsg),
State1 = State0#state{connection_states = ConnectionStates,
negotiated_version = Version, %% Requested version
session =
@@ -213,7 +235,7 @@ init({call, From}, {start, Timeout},
{Record, State} = next_record(State1),
next_event(hello, Record, State);
init(Type, Event, State) ->
- ssl_connection:init(Type, Event, State, ?MODULE).
+ gen_handshake(ssl_connection, init, Type, Event, State).
%%--------------------------------------------------------------------
-spec error(gen_statem:event_type(),
@@ -234,9 +256,7 @@ error(_, _, _) ->
#state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-hello(internal, #client_hello{client_version = ClientVersion,
- extensions = #hello_extensions{ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves}} = Hello,
+hello(internal, #client_hello{client_version = ClientVersion} = Hello,
#state{connection_states = ConnectionStates0,
port = Port, session = #session{own_certificate = Cert} = Session0,
renegotiation = {Renegotiation, _},
@@ -249,7 +269,7 @@ hello(internal, #client_hello{client_version = ClientVersion,
case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
#alert{} = Alert ->
- handle_own_alert(Alert, ClientVersion, hello, State);
+ ssl_connection:handle_own_alert(Alert, ClientVersion, hello, State);
{Version, {Type, Session},
ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
Protocol = case Protocol0 of
@@ -257,13 +277,13 @@ hello(internal, #client_hello{client_version = ClientVersion,
_ -> Protocol0
end,
- ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt},
+ gen_handshake(ssl_connection, hello, internal, {common_client_hello, Type, ServerHelloExt},
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
+ client_hello_version = ClientVersion,
hashsign_algorithm = HashSign,
session = Session,
- client_ecc = {EllipticCurves, EcPointFormats},
- negotiated_protocol = Protocol}, ?MODULE)
+ negotiated_protocol = Protocol})
end;
hello(internal, #server_hello{} = Hello,
#state{connection_states = ConnectionStates0,
@@ -273,42 +293,42 @@ hello(internal, #server_hello{} = Hello,
ssl_options = SslOptions} = State) ->
case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
- handle_own_alert(Alert, ReqVersion, hello, State);
+ ssl_connection:handle_own_alert(Alert, ReqVersion, hello, State);
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
end;
hello(info, Event, State) ->
- handle_info(Event, hello, State);
+ gen_info(Event, hello, State);
hello(Type, Event, State) ->
- ssl_connection:hello(Type, Event, State, ?MODULE).
+ gen_handshake(ssl_connection, hello, Type, Event, State).
%%--------------------------------------------------------------------
-spec abbreviated(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
abbreviated(info, Event, State) ->
- handle_info(Event, abbreviated, State);
+ gen_info(Event, abbreviated, State);
abbreviated(Type, Event, State) ->
- ssl_connection:abbreviated(Type, Event, State, ?MODULE).
+ gen_handshake(ssl_connection, abbreviated, Type, Event, State).
%%--------------------------------------------------------------------
-spec certify(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
certify(info, Event, State) ->
- handle_info(Event, certify, State);
+ gen_info(Event, certify, State);
certify(Type, Event, State) ->
- ssl_connection:certify(Type, Event, State, ?MODULE).
+ gen_handshake(ssl_connection, certify, Type, Event, State).
%%--------------------------------------------------------------------
-spec cipher(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
cipher(info, Event, State) ->
- handle_info(Event, cipher, State);
+ gen_info(Event, cipher, State);
cipher(Type, Event, State) ->
- ssl_connection:cipher(Type, Event, State, ?MODULE).
+ gen_handshake(ssl_connection, cipher, Type, Event, State).
%%--------------------------------------------------------------------
-spec connection(gen_statem:event_type(),
@@ -316,7 +336,7 @@ cipher(Type, Event, State) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
connection(info, Event, State) ->
- handle_info(Event, connection, State);
+ gen_info(Event, connection, State);
connection(internal, #hello_request{},
#state{role = client, host = Host, port = Port,
session = #session{own_certificate = Cert} = Session0,
@@ -326,12 +346,12 @@ connection(internal, #hello_request{},
renegotiation = {Renegotiation, _}} = State0) ->
Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
- State1 = send_handshake(Hello, State0),
+ {State1, Actions} = send_handshake(Hello, State0),
{Record, State} =
next_record(
State1#state{session = Session0#session{session_id
= Hello#client_hello.session_id}}),
- next_event(hello, Record, State);
+ next_event(hello, Record, State, Actions);
connection(internal, #client_hello{} = Hello,
#state{role = server, allow_renegotiate = true} = State0) ->
%% Mitigate Computational DoS attack
@@ -373,34 +393,47 @@ handle_info({Protocol, _, Data}, StateName,
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
- handle_normal_shutdown(Alert, StateName, State0),
+ ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
{stop, {shutdown, own_alert}}
end;
handle_info({CloseTag, Socket}, StateName,
#state{socket = Socket, close_tag = CloseTag,
+ socket_options = #socket_options{active = Active},
+ protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs},
negotiated_version = Version} = State) ->
+
%% Note that as of TLS 1.1,
%% failure to properly close a connection no longer requires that a
%% session not be resumed. This is a change from TLS 1.0 to conform
%% with widespread implementation practice.
- case Version of
- {1, N} when N >= 1 ->
- ok;
- _ ->
- %% As invalidate_sessions here causes performance issues,
- %% we will conform to the widespread implementation
- %% practice and go aginst the spec
- %%invalidate_session(Role, Host, Port, Session)
- ok
- end,
- handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
- {stop, {shutdown, transport_closed}};
+
+ case (Active == false) andalso (CTs =/= []) of
+ false ->
+ case Version of
+ {1, N} when N >= 1 ->
+ ok;
+ _ ->
+ %% As invalidate_sessions here causes performance issues,
+ %% we will conform to the widespread implementation
+ %% practice and go aginst the spec
+ %%invalidate_session(Role, Host, Port, Session)
+ ok
+ end,
+
+ ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ {stop, {shutdown, transport_closed}};
+ true ->
+ %% Fixes non-delivery of final TLS record in {active, once}.
+ %% Basically allows the application the opportunity to set {active, once} again
+ %% and then receive the final message.
+ next_event(StateName, no_record, State)
+ end;
handle_info(Msg, StateName, State) ->
ssl_connection:handle_info(Msg, StateName, State).
handle_common_event(internal, #alert{} = Alert, StateName,
#state{negotiated_version = Version} = State) ->
- handle_own_alert(Alert, Version, StateName, State);
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State);
%%% TLS record protocol level handshake messages
handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
@@ -410,18 +443,26 @@ handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
ssl_options = Options} = State0) ->
try
{Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0, Options),
- State =
+ State1 =
State0#state{protocol_buffers =
Buffers#protocol_buffers{tls_handshake_buffer = Buf}},
- Events = tls_handshake_events(Packets),
- case StateName of
- connection ->
- ssl_connection:hibernate_after(StateName, State, Events);
- _ ->
- {next_state, StateName, State, Events}
- end
+ case Packets of
+ [] ->
+ assert_buffer_sanity(Buf, Options),
+ {Record, State} = next_record(State1),
+ next_event(StateName, Record, State);
+ _ ->
+ Events = tls_handshake_events(Packets),
+ case StateName of
+ connection ->
+ ssl_connection:hibernate_after(StateName, State1, Events);
+ _ ->
+ {next_state, StateName,
+ State1#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
+ end
+ end
catch throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State0)
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
end;
%%% TLS record protocol level application data messages
handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) ->
@@ -432,16 +473,27 @@ handle_common_event(internal, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Da
%%% TLS record protocol level Alert messages
handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
#state{negotiated_version = Version} = State) ->
- case decode_alerts(EncAlerts) of
+ try decode_alerts(EncAlerts) of
Alerts = [_|_] ->
handle_alerts(Alerts, {next_state, StateName, State});
+ [] ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, empty_alert),
+ Version, StateName, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State)
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State)
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, alert_decode_error),
+ Version, StateName, State)
+
end;
%% Ignore unknown TLS record level protocol messages
handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
{next_state, StateName, State}.
+send(Transport, Socket, Data) ->
+ tls_socket:send(Transport, Socket, Data).
+
%%--------------------------------------------------------------------
%% gen_statem callbacks
%%--------------------------------------------------------------------
@@ -457,22 +509,22 @@ format_status(Type, Data) ->
%%--------------------------------------------------------------------
code_change(_OldVsn, StateName, State0, {Direction, From, To}) ->
State = convert_state(State0, Direction, From, To),
- {?GEN_STATEM_CB_MODE, StateName, State};
+ {ok, StateName, State};
code_change(_OldVsn, StateName, State, _) ->
- {?GEN_STATEM_CB_MODE, StateName, State}.
+ {ok, StateName, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-encode_handshake(Handshake, Version, ConnectionStates0, Hist0) ->
+encode_handshake(Handshake, Version, ConnectionStates0, Hist0, V2HComp) ->
Frag = tls_handshake:encode_handshake(Handshake, Version),
- Hist = ssl_handshake:update_handshake_history(Hist0, Frag),
+ Hist = ssl_handshake:update_handshake_history(Hist0, Frag, V2HComp),
{Encoded, ConnectionStates} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
{Encoded, ConnectionStates, Hist}.
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
+ tls_record:encode_change_cipher_spec(Version, ConnectionStates).
decode_alerts(Bin) ->
ssl_alert:decode(Bin).
@@ -480,7 +532,7 @@ decode_alerts(Bin) ->
initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, User,
{CbModule, DataTag, CloseTag, ErrorTag}) ->
#ssl_options{beast_mitigation = BeastMitigation} = SSLOptions,
- ConnectionStates = ssl_record:init_connection_states(Role, BeastMitigation),
+ ConnectionStates = tls_record:init_connection_states(Role, BeastMitigation),
SessionCacheCb = case application:get_env(ssl, session_cb) of
{ok, Cb} when is_atom(Cb) ->
@@ -515,23 +567,6 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us
flight_buffer = []
}.
-
-update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) ->
- SSLOption =
- case OrigSSLOptions#ssl_options.sni_fun of
- undefined ->
- proplists:get_value(SNIHostname,
- OrigSSLOptions#ssl_options.sni_hosts);
- SNIFun ->
- SNIFun(SNIHostname)
- end,
- case SSLOption of
- undefined ->
- undefined;
- _ ->
- ssl:handle_options(SSLOption, OrigSSLOptions)
- end.
-
next_tls_record(Data, #state{protocol_buffers = #protocol_buffers{tls_record_buffer = Buf0,
tls_cipher_texts = CT0} = Buffers} = State0) ->
case tls_record:get_tls_records(Data, Buf0) of
@@ -543,7 +578,9 @@ next_tls_record(Data, #state{protocol_buffers = #protocol_buffers{tls_record_buf
#alert{} = Alert ->
Alert
end.
-
+next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 ->
+ {no_record, State#state{unprocessed_handshake_events = N-1}};
+
next_record(#state{protocol_buffers =
#protocol_buffers{tls_packets = [], tls_cipher_texts = [CT | Rest]}
= Buffers,
@@ -560,7 +597,7 @@ next_record(#state{protocol_buffers =
next_record(#state{protocol_buffers = #protocol_buffers{tls_packets = [], tls_cipher_texts = []},
socket = Socket,
transport_cb = Transport} = State) ->
- ssl_socket:setopts(Transport, Socket, [{active,once}]),
+ tls_socket:setopts(Transport, Socket, [{active,once}]),
{no_record, State};
next_record(State) ->
{no_record, State}.
@@ -579,7 +616,7 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
{Record, State} = next_record(State0),
next_event(StateName, Record, State);
_ ->
- {Record, State} = read_application_data(<<>>, State0),
+ {Record, State} = ssl_connection:read_application_data(<<>>, State0),
next_event(StateName, Record, State)
end.
@@ -591,7 +628,7 @@ next_event(connection = StateName, no_record, State0, Actions) ->
{no_record, State} ->
ssl_connection:hibernate_after(StateName, State, Actions);
{#ssl_tls{} = Record, State} ->
- {next_state, StateName, State, [{next_event, internal, {tls_record, Record}} | Actions]};
+ {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
{#alert{} = Alert, State} ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end;
@@ -600,225 +637,17 @@ next_event(StateName, Record, State, Actions) ->
no_record ->
{next_state, StateName, State, Actions};
#ssl_tls{} = Record ->
- {next_state, StateName, State, [{next_event, internal, {tls_record, Record}} | Actions]};
+ {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
#alert{} = Alert ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end.
-read_application_data(Data, #state{user_application = {_Mon, Pid},
- socket = Socket,
- transport_cb = Transport,
- socket_options = SOpts,
- bytes_to_read = BytesToRead,
- start_or_recv_from = RecvFrom,
- timer = Timer,
- user_data_buffer = Buffer0,
- tracker = Tracker} = State0) ->
- Buffer1 = if
- Buffer0 =:= <<>> -> Data;
- Data =:= <<>> -> Buffer0;
- true -> <<Buffer0/binary, Data/binary>>
- end,
- case get_data(SOpts, BytesToRead, Buffer1) of
- {ok, ClientData, Buffer} -> % Send data
- SocketOpt = deliver_app_data(Transport, Socket, SOpts, ClientData, Pid, RecvFrom, Tracker),
- cancel_timer(Timer),
- State = State0#state{user_data_buffer = Buffer,
- start_or_recv_from = undefined,
- timer = undefined,
- bytes_to_read = undefined,
- socket_options = SocketOpt
- },
- if
- SocketOpt#socket_options.active =:= false; Buffer =:= <<>> ->
- %% Passive mode, wait for active once or recv
- %% Active and empty, get more data
- next_record_if_active(State);
- true -> %% We have more data
- read_application_data(<<>>, State)
- end;
- {more, Buffer} -> % no reply, we need more data
- next_record(State0#state{user_data_buffer = Buffer});
- {passive, Buffer} ->
- next_record_if_active(State0#state{user_data_buffer = Buffer});
- {error,_Reason} -> %% Invalid packet in packet mode
- deliver_packet_error(Transport, Socket, SOpts, Buffer1, Pid, RecvFrom, Tracker),
- {stop, normal, State0}
- end.
-
-%% Picks ClientData
-get_data(_, _, <<>>) ->
- {more, <<>>};
-%% Recv timed out save buffer data until next recv
-get_data(#socket_options{active=false}, undefined, Buffer) ->
- {passive, Buffer};
-get_data(#socket_options{active=Active, packet=Raw}, BytesToRead, Buffer)
- when Raw =:= raw; Raw =:= 0 -> %% Raw Mode
- if
- Active =/= false orelse BytesToRead =:= 0 ->
- %% Active true or once, or passive mode recv(0)
- {ok, Buffer, <<>>};
- byte_size(Buffer) >= BytesToRead ->
- %% Passive Mode, recv(Bytes)
- <<Data:BytesToRead/binary, Rest/binary>> = Buffer,
- {ok, Data, Rest};
- true ->
- %% Passive Mode not enough data
- {more, Buffer}
- end;
-get_data(#socket_options{packet=Type, packet_size=Size}, _, Buffer) ->
- PacketOpts = [{packet_size, Size}],
- case decode_packet(Type, Buffer, PacketOpts) of
- {more, _} ->
- {more, Buffer};
- Decoded ->
- Decoded
- end.
-
-decode_packet({http, headers}, Buffer, PacketOpts) ->
- decode_packet(httph, Buffer, PacketOpts);
-decode_packet({http_bin, headers}, Buffer, PacketOpts) ->
- decode_packet(httph_bin, Buffer, PacketOpts);
-decode_packet(Type, Buffer, PacketOpts) ->
- erlang:decode_packet(Type, Buffer, PacketOpts).
-
-%% Just like with gen_tcp sockets, an ssl socket that has been configured with
-%% {packet, http} (or {packet, http_bin}) will automatically switch to expect
-%% HTTP headers after it sees a HTTP Request or HTTP Response line. We
-%% represent the current state as follows:
-%% #socket_options.packet =:= http: Expect a HTTP Request/Response line
-%% #socket_options.packet =:= {http, headers}: Expect HTTP Headers
-%% Note that if the user has explicitly configured the socket to expect
-%% HTTP headers using the {packet, httph} option, we don't do any automatic
-%% switching of states.
-deliver_app_data(Transport, Socket, SOpts = #socket_options{active=Active, packet=Type},
- Data, Pid, From, Tracker) ->
- send_or_reply(Active, Pid, From, format_reply(Transport, Socket, SOpts, Data, Tracker)),
- SO = case Data of
- {P, _, _, _} when ((P =:= http_request) or (P =:= http_response)),
- ((Type =:= http) or (Type =:= http_bin)) ->
- SOpts#socket_options{packet={Type, headers}};
- http_eoh when tuple_size(Type) =:= 2 ->
- % End of headers - expect another Request/Response line
- {Type1, headers} = Type,
- SOpts#socket_options{packet=Type1};
- _ ->
- SOpts
- end,
- case Active of
- once ->
- SO#socket_options{active=false};
- _ ->
- SO
- end.
-
-format_reply(_, _,#socket_options{active = false, mode = Mode, packet = Packet,
- header = Header}, Data, _) ->
- {ok, do_format_reply(Mode, Packet, Header, Data)};
-format_reply(Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
- header = Header}, Data, Tracker) ->
- {ssl, ssl_socket:socket(self(), Transport, Socket, ?MODULE, Tracker),
- do_format_reply(Mode, Packet, Header, Data)}.
-
-deliver_packet_error(Transport, Socket, SO= #socket_options{active = Active}, Data, Pid, From, Tracker) ->
- send_or_reply(Active, Pid, From, format_packet_error(Transport, Socket, SO, Data, Tracker)).
-
-format_packet_error(_, _,#socket_options{active = false, mode = Mode}, Data, _) ->
- {error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}};
-format_packet_error(Transport, Socket, #socket_options{active = _, mode = Mode}, Data, Tracker) ->
- {ssl_error, ssl_socket:socket(self(), Transport, Socket, ?MODULE, Tracker),
- {invalid_packet, do_format_reply(Mode, raw, 0, Data)}}.
-
-do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode
- header(N, Data);
-do_format_reply(binary, _, _, Data) ->
- Data;
-do_format_reply(list, Packet, _, Data)
- when Packet == http; Packet == {http, headers};
- Packet == http_bin; Packet == {http_bin, headers};
- Packet == httph; Packet == httph_bin ->
- Data;
-do_format_reply(list, _,_, Data) ->
- binary_to_list(Data).
-
-header(0, <<>>) ->
- <<>>;
-header(_, <<>>) ->
- [];
-header(0, Binary) ->
- Binary;
-header(N, Binary) ->
- <<?BYTE(ByteN), NewBinary/binary>> = Binary,
- [ByteN | header(N-1, NewBinary)].
-
-send_or_reply(false, _Pid, From, Data) when From =/= undefined ->
- gen_statem:reply(From, Data);
-%% Can happen when handling own alert or tcp error/close and there is
-%% no outstanding gen_fsm sync events
-send_or_reply(false, no_pid, _, _) ->
- ok;
-send_or_reply(_, Pid, _From, Data) ->
- send_user(Pid, Data).
-
-send_user(Pid, Msg) ->
- Pid ! Msg.
-
-tls_handshake_events([]) ->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake));
tls_handshake_events(Packets) ->
lists:map(fun(Packet) ->
{next_event, internal, {handshake, Packet}}
end, Packets).
-write_application_data(Data0, From,
- #state{socket = Socket,
- negotiated_version = Version,
- transport_cb = Transport,
- connection_states = ConnectionStates0,
- socket_options = SockOpts,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State) ->
- Data = encode_packet(Data0, SockOpts),
-
- case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
- true ->
- renegotiate(State#state{renegotiation = {true, internal}},
- [{next_event, {call, From}, {application_data, Data0}}]);
- false ->
- {Msgs, ConnectionStates} = ssl_record:encode_data(Data, Version, ConnectionStates0),
- Result = Transport:send(Socket, Msgs),
- ssl_connection:hibernate_after(connection, State#state{connection_states = ConnectionStates},
- [{reply, From, Result}])
- end.
-
-encode_packet(Data, #socket_options{packet=Packet}) ->
- case Packet of
- 1 -> encode_size_packet(Data, 8, (1 bsl 8) - 1);
- 2 -> encode_size_packet(Data, 16, (1 bsl 16) - 1);
- 4 -> encode_size_packet(Data, 32, (1 bsl 32) - 1);
- _ -> Data
- end.
-encode_size_packet(Bin, Size, Max) ->
- Len = erlang:byte_size(Bin),
- case Len > Max of
- true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
- false -> <<Len:Size, Bin/binary>>
- end.
-
-time_to_renegotiate(_Data,
- #connection_states{current_write =
- #connection_state{sequence_number = Num}},
- RenegotiateAt) ->
-
- %% We could do test:
- %% is_time_to_renegotiate((erlang:byte_size(_Data) div ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt),
- %% but we chose to have a some what lower renegotiateAt and a much cheaper test
- is_time_to_renegotiate(Num, RenegotiateAt).
-
-is_time_to_renegotiate(N, M) when N < M->
- false;
-is_time_to_renegotiate(_,_) ->
- true.
renegotiate(#state{role = client} = State, Actions) ->
%% Handle same way as if server requested
%% the renegotiation
@@ -835,8 +664,8 @@ renegotiate(#state{role = server,
Frag = tls_handshake:encode_handshake(HelloRequest, Version),
Hs0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
- Transport:send(Socket, BinMsg),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
State1 = State0#state{connection_states =
ConnectionStates,
tls_handshake_history = Hs0},
@@ -848,135 +677,14 @@ handle_alerts([], Result) ->
handle_alerts(_, {stop,_} = Stop) ->
Stop;
handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
- handle_alerts(Alerts, handle_alert(Alert, StateName, State));
+ handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State));
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
- handle_alerts(Alerts, handle_alert(Alert, StateName, State)).
-handle_alert(#alert{level = ?FATAL} = Alert, StateName,
- #state{socket = Socket, transport_cb = Transport,
- ssl_options = SslOpts, start_or_recv_from = From, host = Host,
- port = Port, session = Session, user_application = {_Mon, Pid},
- role = Role, socket_options = Opts, tracker = Tracker}) ->
- invalidate_session(Role, Host, Port, Session),
- log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
- alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role),
- {stop, normal};
-
-handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
- StateName, State) ->
- handle_normal_shutdown(Alert, StateName, State),
- {stop, {shutdown, peer_close}};
-
-handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{ssl_options = SslOpts, renegotiation = {true, internal}} = State) ->
- log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
- handle_normal_shutdown(Alert, StateName, State),
- {stop, {shutdown, peer_close}};
-
-handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{ssl_options = SslOpts, renegotiation = {true, From}} = State0) ->
- log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
- gen_statem:reply(From, {error, renegotiation_rejected}),
- {Record, State} = next_record(State0),
- %% Go back to connection!
- next_event(connection, Record, State);
+ handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
-%% Gracefully log and ignore all other warning alerts
-handle_alert(#alert{level = ?WARNING} = Alert, StateName,
- #state{ssl_options = SslOpts} = State0) ->
- log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
- {Record, State} = next_record(State0),
- next_event(StateName, Record, State).
-
-alert_user(Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role) ->
- alert_user(Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role);
-alert_user(Transport, Tracker, Socket,_, _, _, From, Alert, Role) ->
- alert_user(Transport, Tracker, Socket, From, Alert, Role).
-
-alert_user(Transport, Tracker, Socket, From, Alert, Role) ->
- alert_user(Transport, Tracker, Socket, false, no_pid, From, Alert, Role).
-
-alert_user(_, _, _, false = Active, Pid, From, Alert, Role) when From =/= undefined ->
- %% If there is an outstanding ssl_accept | recv
- %% From will be defined and send_or_reply will
- %% send the appropriate error message.
- ReasonCode = ssl_alert:reason_code(Alert, Role),
- send_or_reply(Active, Pid, From, {error, ReasonCode});
-alert_user(Transport, Tracker, Socket, Active, Pid, From, Alert, Role) ->
- case ssl_alert:reason_code(Alert, Role) of
- closed ->
- send_or_reply(Active, Pid, From,
- {ssl_closed, ssl_socket:socket(self(),
- Transport, Socket, ?MODULE, Tracker)});
- ReasonCode ->
- send_or_reply(Active, Pid, From,
- {ssl_error, ssl_socket:socket(self(),
- Transport, Socket, ?MODULE, Tracker), ReasonCode})
- end.
-
-log_alert(true, Info, Alert) ->
- Txt = ssl_alert:alert_txt(Alert),
- error_logger:format("SSL: ~p: ~s\n", [Info, Txt]);
-log_alert(false, _, _) ->
- ok.
-
-handle_own_alert(Alert, Version, StateName,
- #state{transport_cb = Transport,
- socket = Socket,
- connection_states = ConnectionStates,
- ssl_options = SslOpts} = State) ->
- try %% Try to tell the other side
- {BinMsg, _} =
- ssl_alert:encode(Alert, Version, ConnectionStates),
- Transport:send(Socket, BinMsg)
- catch _:_ -> %% Can crash if we are in a uninitialized state
- ignore
- end,
- try %% Try to tell the local user
- log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
- handle_normal_shutdown(Alert,StateName, State)
- catch _:_ ->
- ok
- end,
- {stop, {shutdown, own_alert}}.
-
-handle_normal_shutdown(Alert, _, #state{socket = Socket,
- transport_cb = Transport,
- start_or_recv_from = StartFrom,
- tracker = Tracker,
- role = Role, renegotiation = {false, first}}) ->
- alert_user(Transport, Tracker,Socket, StartFrom, Alert, Role);
-
-handle_normal_shutdown(Alert, StateName, #state{socket = Socket,
- socket_options = Opts,
- transport_cb = Transport,
- user_application = {_Mon, Pid},
- tracker = Tracker,
- start_or_recv_from = RecvFrom, role = Role}) ->
- alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role).
-
-handle_close_alert(Data, StateName, State0) ->
- case next_tls_record(Data, State0) of
- {#ssl_tls{type = ?ALERT, fragment = EncAlerts}, State} ->
- [Alert|_] = decode_alerts(EncAlerts),
- handle_normal_shutdown(Alert, StateName, State);
- _ ->
- ok
- end.
-
-cancel_timer(undefined) ->
- ok;
-cancel_timer(Timer) ->
- erlang:cancel_timer(Timer),
- ok.
-
-invalidate_session(client, Host, Port, Session) ->
- ssl_manager:invalidate_session(Host, Port, Session);
-invalidate_session(server, _, Port, Session) ->
- ssl_manager:invalidate_session(Port, Session).
%% User closes or recursive call!
close({close, Timeout}, Socket, Transport = gen_tcp, _,_) ->
- ssl_socket:setopts(Transport, Socket, [{active, false}]),
+ tls_socket:setopts(Transport, Socket, [{active, false}]),
Transport:shutdown(Socket, write),
_ = Transport:recv(Socket, 0, Timeout),
ok;
@@ -1011,31 +719,66 @@ convert_options_partial_chain(Options, up) ->
convert_options_partial_chain(Options, down) ->
list_to_tuple(proplists:delete(partial_chain, tuple_to_list(Options))).
-handle_sni_extension(#client_hello{extensions = HelloExtensions}, State0) ->
- case HelloExtensions#hello_extensions.sni of
- undefined ->
- State0;
- #sni{hostname = Hostname} ->
- NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
- case NewOptions of
- undefined ->
- State0;
- _ ->
- {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbHandle, OwnCert, Key, DHParams} =
- ssl_config:init(NewOptions, State0#state.role),
- State0#state{
- session = State0#state.session#session{own_certificate = OwnCert},
- file_ref_db = FileRefHandle,
- cert_db_ref = Ref,
- cert_db = CertDbHandle,
- crl_db = CRLDbHandle,
- session_cache = CacheHandle,
- private_key = Key,
- diffie_hellman_params = DHParams,
- ssl_options = NewOptions,
- sni_hostname = Hostname
- }
- end
+gen_handshake(GenConnection, StateName, Type, Event,
+ #state{negotiated_version = Version} = State) ->
+ try GenConnection:StateName(Type, Event, State, ?MODULE) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data),
+ Version, StateName, State)
+ end.
+
+gen_info(Event, connection = StateName, #state{negotiated_version = Version} = State) ->
+ try handle_info(Event, StateName, State) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR,
+ malformed_data),
+ Version, StateName, State)
end;
-handle_sni_extension(_, State) ->
- State.
+
+gen_info(Event, StateName, #state{negotiated_version = Version} = State) ->
+ try handle_info(Event, StateName, State) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data),
+ Version, StateName, State)
+ end.
+
+unprocessed_events(Events) ->
+ %% The first handshake event will be processed immediately
+ %% as it is entered first in the event queue and
+ %% when it is processed there will be length(Events)-1
+ %% handshake events left to process before we should
+ %% process more TLS-records received on the socket.
+ erlang:length(Events)-1.
+
+
+assert_buffer_sanity(<<?BYTE(_Type), ?UINT24(Length), Rest/binary>>, #ssl_options{max_handshake_size = Max}) when
+ Length =< Max ->
+ case size(Rest) of
+ N when N < Length ->
+ true;
+ N when N > Length ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ too_big_handshake_data));
+ _ ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data))
+ end;
+assert_buffer_sanity(Bin, _) ->
+ case size(Bin) of
+ N when N < 3 ->
+ true;
+ _ ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data))
+ end.
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 566b7db332..80d0239498 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_number(), #connection_states{},
+-spec client_hello(host(), inet:port_number(), ssl_record:connection_states(),
#ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
#client_hello{}.
%%
@@ -54,8 +54,7 @@ client_hello(Host, Port, ConnectionStates,
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
Version = tls_record:highest_protocol_version(Versions),
- Pending = ssl_record:pending_connection_state(ConnectionStates, read),
- SecParams = Pending#connection_state.security_parameters,
+ #{security_parameters := SecParams} = ssl_record:pending_connection_state(ConnectionStates, read),
AvailableCipherSuites = ssl_handshake:available_suites(UserSuites, Version),
Extensions = ssl_handshake:client_hello_extensions(Host, Version,
AvailableCipherSuites,
@@ -78,14 +77,14 @@ client_hello(Host, Port, ConnectionStates,
%%--------------------------------------------------------------------
-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
- #connection_states{} | {inet:port_number(), #session{}, db_handle(),
- atom(), #connection_states{},
+ ssl_record:connection_states() | {inet:port_number(), #session{}, db_handle(),
+ atom(), ssl_record:connection_states(),
binary() | undefined, ssl_cipher:key_algo()},
boolean()) ->
{tls_record:tls_version(), session_id(),
- #connection_states{}, alpn | npn, binary() | undefined}|
+ ssl_record:connection_states(), alpn | npn, binary() | undefined}|
{tls_record:tls_version(), {resumed | new, #session{}},
- #connection_states{}, binary() | undefined,
+ ssl_record:connection_states(), binary() | undefined,
#hello_extensions{}, {ssl_cipher:hash(), ssl_cipher:sign_algo()} | undefined} |
#alert{}.
%%
@@ -109,19 +108,25 @@ hello(#client_hello{client_version = ClientVersion,
cipher_suites = CipherSuites} = Hello,
#ssl_options{versions = Versions} = SslOpts,
Info, Renegotiation) ->
- Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
- case ssl_cipher:is_fallback(CipherSuites) of
+ try
+ Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
+ case ssl_cipher:is_fallback(CipherSuites) of
true ->
- Highest = tls_record:highest_protocol_version(Versions),
- case tls_record:is_higher(Highest, Version) of
- true ->
- ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end;
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end.
+ Highest = tls_record:highest_protocol_version(Versions),
+ case tls_record:is_higher(Highest, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end;
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
+ end.
+
%%--------------------------------------------------------------------
-spec encode_handshake(tls_handshake(), tls_record:tls_version()) -> iolist().
%%
@@ -155,13 +160,15 @@ handle_client_hello(Version, #client_hello{session_id = SugesstedId,
extensions = #hello_extensions{elliptic_curves = Curves,
signature_algs = ClientHashSigns} = HelloExt},
#ssl_options{versions = Versions,
- signature_algs = SupportedHashSigns} = SslOpts,
+ signature_algs = SupportedHashSigns,
+ eccs = SupportedECCs,
+ honor_ecc_order = ECCOrder} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, _}, Renegotiation) ->
case tls_record:is_acceptable_version(Version, Versions) of
true ->
AvailableHashSigns = ssl_handshake:available_signature_algs(
ClientHashSigns, SupportedHashSigns, Cert, Version),
- ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(Version)),
+ ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, ECCOrder),
{Type, #session{cipher_suite = CipherSuite} = Session1}
= ssl_handshake:select_session(SugesstedId, CipherSuites, AvailableHashSigns, Compressions,
Port, Session0#session{ecc = ECCCurve}, Version,
@@ -185,37 +192,33 @@ handle_client_hello(Version, #client_hello{session_id = SugesstedId,
end.
get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
- Body:Length/binary,Rest/binary>>, #ssl_options{v2_hello_compatible = V2Hello} = Opts, Acc) ->
+ Body:Length/binary,Rest/binary>>,
+ #ssl_options{v2_hello_compatible = V2Hello} = Opts, Acc) ->
Raw = <<?BYTE(Type), ?UINT24(Length), Body/binary>>,
- Handshake = decode_handshake(Version, Type, Body, V2Hello),
- get_tls_handshake_aux(Version, Rest, Opts, [{Handshake,Raw} | Acc]);
+ try decode_handshake(Version, Type, Body, V2Hello) of
+ Handshake ->
+ get_tls_handshake_aux(Version, Rest, Opts, [{Handshake,Raw} | Acc])
+ catch
+ _:_ ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, handshake_decode_error))
+ end;
get_tls_handshake_aux(_Version, Data, _, Acc) ->
{lists:reverse(Acc), Data}.
decode_handshake(_, ?HELLO_REQUEST, <<>>, _) ->
#hello_request{};
-%% Client hello v2.
-%% The server must be able to receive such messages, from clients that
-%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
-decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>, true) ->
- #client_hello{client_version = {Major, Minor},
- random = ssl_v2:client_random(ChallengeData, CDLength),
- session_id = 0,
- cipher_suites = ssl_handshake:decode_suites('3_bytes', CipherSuites),
- compression_methods = [?NULL],
- extensions = #hello_extensions{}
- };
-decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(_), ?BYTE(_),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- _CipherSuites:CSLength/binary,
- _ChallengeData:CDLength/binary>>, false) ->
- throw(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION, ssl_v2_client_hello_no_supported));
+decode_handshake(_Version, ?CLIENT_HELLO, Bin, true) ->
+ try decode_hello(Bin) of
+ Hello ->
+ Hello
+ catch
+ _:_ ->
+ decode_v2_hello(Bin)
+ end;
+decode_handshake(_Version, ?CLIENT_HELLO, Bin, false) ->
+ decode_hello(Bin);
+
decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
@@ -232,10 +235,40 @@ decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:3
compression_methods = Comp_methods,
extensions = DecodedExtensions
};
-
decode_handshake(Version, Tag, Msg, _) ->
ssl_handshake:decode_handshake(Version, Tag, Msg).
+
+decode_hello(<<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+ ?BYTE(SID_length), Session_ID:SID_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({client, Extensions}),
+
+ #client_hello{
+ client_version = {Major,Minor},
+ random = Random,
+ session_id = Session_ID,
+ cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
+ compression_methods = Comp_methods,
+ extensions = DecodedExtensions
+ }.
+%% The server must be able to receive such messages, from clients that
+%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
+decode_v2_hello(<<?BYTE(Major), ?BYTE(Minor),
+ ?UINT16(CSLength), ?UINT16(0),
+ ?UINT16(CDLength),
+ CipherSuites:CSLength/binary,
+ ChallengeData:CDLength/binary>>) ->
+ #client_hello{client_version = {Major, Minor},
+ random = ssl_v2:client_random(ChallengeData, CDLength),
+ session_id = 0,
+ cipher_suites = ssl_handshake:decode_suites('3_bytes', CipherSuites),
+ compression_methods = [?NULL],
+ extensions = #hello_extensions{}
+ }.
+
enc_handshake(#hello_request{}, _Version) ->
{?HELLO_REQUEST, <<>>};
enc_handshake(#client_hello{client_version = {Major, Minor},
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 9348c8bbdd..993a1622fe 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,12 +32,11 @@
-include("ssl_cipher.hrl").
%% Handling of incoming data
--export([get_tls_records/2]).
+-export([get_tls_records/2, init_connection_states/2]).
-%% Decoding
--export([decode_cipher_text/3]).
-
-%% Encoding
+%% Encoding TLS records
+-export([encode_handshake/3, encode_alert_record/3,
+ encode_change_cipher_spec/2, encode_data/3]).
-export([encode_plain_text/4]).
%% Protocol version handling
@@ -46,6 +45,9 @@
is_higher/2, supported_protocol_versions/0,
is_acceptable_version/1, is_acceptable_version/2]).
+%% Decoding
+-export([decode_cipher_text/3]).
+
-export_type([tls_version/0, tls_atom_version/0]).
-type tls_version() :: ssl_record:ssl_version().
@@ -56,12 +58,28 @@
%%====================================================================
%% Internal application API
%%====================================================================
+%%--------------------------------------------------------------------
+-spec init_connection_states(client | server, one_n_minus_one | zero_n | disabled) ->
+ ssl_record:connection_states().
+%% %
+ %
+%% Description: Creates a connection_states record with appropriate
+%% values for the initial SSL connection setup.
+%%--------------------------------------------------------------------
+init_connection_states(Role, BeastMitigation) ->
+ ConnectionEnd = ssl_record:record_protocol_role(Role),
+ Current = initial_connection_state(ConnectionEnd, BeastMitigation),
+ Pending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
+ #{current_read => Current,
+ pending_read => Pending,
+ current_write => Current,
+ pending_write => Pending}.
%%--------------------------------------------------------------------
-spec get_tls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}.
%%
-%% Description: Given old buffer and new data from TCP, packs up a records
%% and returns it as a list of tls_compressed binaries also returns leftover
+%% Description: Given old buffer and new data from TCP, packs up a records
%% data
%%--------------------------------------------------------------------
get_tls_records(Data, <<>>) ->
@@ -69,155 +87,61 @@ get_tls_records(Data, <<>>) ->
get_tls_records(Data, Buffer) ->
get_tls_records_aux(list_to_binary([Buffer, Data]), []).
-get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length),
- Data:Length/binary, Rest/binary>>, Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary,
- Rest/binary>>, Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-%% Matches an ssl v2 client hello message.
-%% The server must be able to receive such messages, from clients that
-%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
-get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>,
- Acc) ->
- case Data0 of
- <<?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>> ->
- Length = Length0-1,
- <<?BYTE(_), Data1:Length/binary>> = Data0,
- Data = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length), Data1/binary>>,
- get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
- _ ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
-
- end;
-
-get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
- ?UINT16(Length), _/binary>>,
- _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
- ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version,
+ #{current_write :=
+ #{beast_mitigation := BeastMitigation,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm = BCA}}} =
+ ConnectionStates) ->
+ case iolist_size(Frag) of
+ N when N > ?MAX_PLAIN_TEXT_LENGTH ->
+ Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
+ encode_iolist(?HANDSHAKE, Data, Version, ConnectionStates);
+ _ ->
+ encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
+ end.
-get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc)
- when Length0 > ?MAX_CIPHER_TEXT_LENGTH ->
- ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ Version, ConnectionStates) ->
+ encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
-get_tls_records_aux(Data, Acc) ->
- case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
- true ->
- {lists:reverse(Acc), Data};
- false ->
- ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
- end.
+%%--------------------------------------------------------------------
+-spec encode_change_cipher_spec(tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record: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, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
-encode_plain_text(Type, Version, Data,
- #connection_states{current_write =
- #connection_state{
- sequence_number = Seq,
- compression_state=CompS0,
- security_parameters=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm=CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#connection_state{compression_state = CompS1},
- AAD = calc_aad(Type, Version, WriteState1),
- {CipherFragment, WriteState} = ssl_record:cipher_aead(Version, Comp, WriteState1, AAD),
- CipherText = encode_tls_cipher_text(Type, Version, CipherFragment),
- {CipherText, ConnectionStates#connection_states{current_write = WriteState#connection_state{sequence_number = Seq +1}}};
-
-encode_plain_text(Type, Version, Data,
- #connection_states{current_write =
- #connection_state{
- sequence_number = Seq,
- compression_state=CompS0,
- security_parameters=
- #security_parameters{compression_algorithm=CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#connection_state{compression_state = CompS1},
- MacHash = calc_mac_hash(Type, Version, Comp, WriteState1),
- {CipherFragment, WriteState} = ssl_record:cipher(Version, Comp, WriteState1, MacHash),
- CipherText = encode_tls_cipher_text(Type, Version, CipherFragment),
- {CipherText, ConnectionStates#connection_states{current_write = WriteState#connection_state{sequence_number = Seq +1}}}.
-
-%%--------------------------------------------------------------------
--spec decode_cipher_text(#ssl_tls{}, #connection_states{}, boolean()) ->
- {#ssl_tls{}, #connection_states{}}| #alert{}.
+%%--------------------------------------------------------------------
+-spec encode_data(binary(), tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
%%
-%% Description: Decode cipher text
+%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- fragment = CipherFragment} = CipherText,
- #connection_states{current_read =
- #connection_state{
- compression_state = CompressionS0,
- sequence_number = Seq,
- security_parameters=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm=CompAlg}
- } = ReadState0} = ConnnectionStates0, _) ->
- AAD = calc_aad(Type, Version, ReadState0),
- case ssl_record:decipher_aead(Version, CipherFragment, ReadState0, AAD) of
- {PlainFragment, ReadState1} ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#connection_states{
- current_read = ReadState1#connection_state{
- sequence_number = Seq + 1,
- compression_state = CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- #alert{} = Alert ->
- Alert
- end;
+encode_data(Frag, Version,
+ #{current_write := #{beast_mitigation := BeastMitigation,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm = BCA}}} =
+ ConnectionStates) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
+ encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
+
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- fragment = CipherFragment} = CipherText,
- #connection_states{current_read =
- #connection_state{
- compression_state = CompressionS0,
- sequence_number = Seq,
- security_parameters=
- #security_parameters{compression_algorithm=CompAlg}
- } = ReadState0} = ConnnectionStates0, PaddingCheck) ->
- case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
- {PlainFragment, Mac, ReadState1} ->
- MacHash = calc_mac_hash(Type, Version, PlainFragment, ReadState1),
- case ssl_record:is_correct_mac(Mac, MacHash) of
- true ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#connection_states{
- current_read = ReadState1#connection_state{
- sequence_number = Seq + 1,
- compression_state = CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end;
- #alert{} = Alert ->
- Alert
- end.
%%--------------------------------------------------------------------
-spec protocol_version(tls_atom_version() | tls_version()) ->
tls_version() | tls_atom_version().
@@ -375,6 +299,82 @@ is_acceptable_version(_,_) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+initial_connection_state(ConnectionEnd, BeastMitigation) ->
+ #{security_parameters =>
+ ssl_record:initial_security_params(ConnectionEnd),
+ sequence_number => 0,
+ beast_mitigation => BeastMitigation,
+ compression_state => undefined,
+ cipher_state => undefined,
+ mac_secret => undefined,
+ secure_renegotiation => undefined,
+ client_verify_data => undefined,
+ server_verify_data => undefined
+ }.
+
+get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary, Rest/binary>>,
+ Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length),
+ Data:Length/binary, Rest/binary>>, Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary,
+ Rest/binary>>, Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary, Rest/binary>>,
+ Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+%% Matches an ssl v2 client hello message.
+%% The server must be able to receive such messages, from clients that
+%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
+get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>,
+ Acc) ->
+ case Data0 of
+ <<?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>> ->
+ Length = Length0-1,
+ <<?BYTE(_), Data1:Length/binary>> = Data0,
+ Data = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length), Data1/binary>>,
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+ _ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+
+ end;
+
+get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
+ ?UINT16(Length), _/binary>>,
+ _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
+ ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+
+get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc)
+ when Length0 > ?MAX_CIPHER_TEXT_LENGTH ->
+ ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+
+get_tls_records_aux(Data, Acc) ->
+ case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
+ true ->
+ {lists:reverse(Acc), Data};
+ false ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
+ end.
+
+encode_plain_text(Type, Version, Data, #{current_write := Write0} = ConnectionStates) ->
+ {CipherFragment, Write1} = ssl_record:encode_plain_text(Type, Version, Data, Write0),
+ {CipherText, Write} = encode_tls_cipher_text(Type, Version, CipherFragment, Write1),
+ {CipherText, ConnectionStates#{current_write => Write}}.
lowest_list_protocol_version(Ver, []) ->
Ver;
@@ -386,20 +386,10 @@ highest_list_protocol_version(Ver, []) ->
highest_list_protocol_version(Ver1, [Ver2 | Rest]) ->
highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
-encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment) ->
+encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment, #{sequence_number := Seq} = Write) ->
Length = erlang:iolist_size(Fragment),
- [<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment].
-
-
-mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
- _Length, _Fragment) ->
- <<>>;
-mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
-mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
- when N =:= 1; N =:= 2; N =:= 3 ->
- tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
- Length, Fragment).
+ {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment],
+ Write#{sequence_number => Seq +1}}.
highest_protocol_version() ->
highest_protocol_version(supported_protocol_versions()).
@@ -407,21 +397,96 @@ highest_protocol_version() ->
lowest_protocol_version() ->
lowest_protocol_version(supported_protocol_versions()).
-
sufficient_tlsv1_2_crypto_support() ->
CryptoSupport = crypto:supports(),
proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
-calc_mac_hash(Type, Version,
- PlainFragment, #connection_state{sequence_number = SeqNo,
- mac_secret = MacSecret,
- security_parameters =
- SecPars}) ->
- Length = erlang:iolist_size(PlainFragment),
- mac_hash(Version, SecPars#security_parameters.mac_algorithm,
- MacSecret, SeqNo, Type,
- Length, PlainFragment).
-
-calc_aad(Type, {MajVer, MinVer},
- #connection_state{sequence_number = SeqNo}) ->
- <<SeqNo:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
+encode_iolist(Type, Data, Version, ConnectionStates0) ->
+ {ConnectionStates, EncodedMsg} =
+ lists:foldl(fun(Text, {CS0, Encoded}) ->
+ {Enc, CS1} =
+ encode_plain_text(Type, Version, Text, CS0),
+ {CS1, [Enc | Encoded]}
+ end, {ConnectionStates0, []}, Data),
+ {lists:reverse(EncodedMsg), ConnectionStates}.
+
+%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
+%% not vulnerable to this attack.
+split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version, BCA, one_n_minus_one) when
+ BCA =/= ?RC4 andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ do_split_bin(Rest, ChunkSize, [[FirstByte]]);
+%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
+%% splitting.
+split_bin(Bin, ChunkSize, Version, BCA, zero_n) when
+ BCA =/= ?RC4 andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ do_split_bin(Bin, ChunkSize, [[<<>>]]);
+split_bin(Bin, ChunkSize, _, _, _) ->
+ do_split_bin(Bin, ChunkSize, []).
+
+do_split_bin(<<>>, _, Acc) ->
+ lists:reverse(Acc);
+do_split_bin(Bin, ChunkSize, Acc) ->
+ case Bin of
+ <<Chunk:ChunkSize/binary, Rest/binary>> ->
+ do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
+ _ ->
+ lists:reverse(Acc, [Bin])
+ end.
+
+%%--------------------------------------------------------------------
+-spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states(), boolean()) ->
+ {#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
+%%
+%% Description: Decode cipher text
+%%--------------------------------------------------------------------
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ fragment = CipherFragment} = CipherText,
+ #{current_read :=
+ #{compression_state := CompressionS0,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}
+ } = ReadState0} = ConnnectionStates0, _) ->
+ AAD = ssl_cipher:calc_aad(Type, Version, ReadState0),
+ case ssl_record:decipher_aead(Version, CipherFragment, ReadState0, AAD) of
+ {PlainFragment, ReadState1} ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+ ConnnectionStates = ConnnectionStates0#{
+ current_read => ReadState1#{sequence_number => Seq + 1,
+ compression_state => CompressionS1}},
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ #alert{} = Alert ->
+ Alert
+ end;
+
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ fragment = CipherFragment} = CipherText,
+ #{current_read :=
+ #{compression_state := CompressionS0,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}
+ } = ReadState0} = ConnnectionStates0, PaddingCheck) ->
+ case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
+ {PlainFragment, Mac, ReadState1} ->
+ MacHash = ssl_cipher:calc_mac_hash(Type, Version, PlainFragment, ReadState1),
+ case ssl_record:is_correct_mac(Mac, MacHash) of
+ true ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+ ConnnectionStates = ConnnectionStates0#{
+ current_read => ReadState1#{
+ sequence_number => Seq + 1,
+ compression_state => CompressionS1}},
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+ #alert{} = Alert ->
+ Alert
+ end.
diff --git a/lib/ssl/src/ssl_socket.erl b/lib/ssl/src/tls_socket.erl
index b2aea2ba9c..e76d9c100a 100644
--- a/lib/ssl/src/ssl_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -17,16 +17,19 @@
%%
%% %CopyrightEnd%
%%
--module(ssl_socket).
+-module(tls_socket).
-behaviour(gen_server).
-include("ssl_internal.hrl").
-include("ssl_api.hrl").
--export([socket/5, setopts/3, getopts/3, getstat/3, peername/2, sockname/2, port/2]).
+-export([send/3, listen/3, accept/3, socket/5, connect/4, upgrade/3,
+ setopts/3, getopts/3, getstat/3, peername/2, sockname/2, port/2]).
+-export([split_options/1, get_socket_opts/3]).
-export([emulated_options/0, internal_inet_values/0, default_inet_values/0,
- init/1, start_link/3, terminate/2, inherit_tracker/3, get_emulated_opts/1,
+ init/1, start_link/3, terminate/2, inherit_tracker/3,
+ emulated_socket_options/2, get_emulated_opts/1,
set_emulated_opts/2, get_all_opts/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3]).
@@ -39,6 +42,76 @@
%%--------------------------------------------------------------------
%%% Internal API
%%--------------------------------------------------------------------
+send(Transport, Socket, Data) ->
+ Transport:send(Socket, Data).
+
+listen(Transport, Port, #config{transport_info = {Transport, _, _, _},
+ inet_user = Options,
+ ssl = SslOpts, emulated = EmOpts} = Config) ->
+ case Transport:listen(Port, Options ++ internal_inet_values()) of
+ {ok, ListenSocket} ->
+ {ok, Tracker} = inherit_tracker(ListenSocket, EmOpts, SslOpts),
+ {ok, #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}}};
+ Err = {error, _} ->
+ Err
+ end.
+
+accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
+ connection_cb = ConnectionCb,
+ ssl = SslOpts,
+ emulated = Tracker}, Timeout) ->
+ case Transport:accept(ListenSocket, Timeout) of
+ {ok, Socket} ->
+ {ok, EmOpts} = get_emulated_opts(Tracker),
+ {ok, Port} = tls_socket:port(Transport, Socket),
+ ConnArgs = [server, "localhost", Port, Socket,
+ {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Tracker}, self(), CbInfo],
+ case tls_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ ssl_connection:socket_control(ConnectionCb, Socket, Pid, Transport, Tracker);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+upgrade(Socket, #config{transport_info = {Transport,_,_,_}= CbInfo,
+ ssl = SslOptions,
+ emulated = EmOpts, connection_cb = ConnectionCb}, Timeout) ->
+ ok = setopts(Transport, Socket, tls_socket:internal_inet_values()),
+ case peername(Transport, Socket) of
+ {ok, {Address, Port}} ->
+ ssl_connection:connect(ConnectionCb, Address, Port, Socket,
+ {SslOptions,
+ emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout);
+ {error, Error} ->
+ {error, Error}
+ end.
+
+connect(Address, Port,
+ #config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
+ emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
+ Timeout) ->
+ {Transport, _, _, _} = CbInfo,
+ try Transport:connect(Address, Port, SocketOpts, Timeout) of
+ {ok, Socket} ->
+ ssl_connection:connect(ConnetionCb, Address, Port, Socket,
+ {SslOpts,
+ emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ exit:{function_clause, _} ->
+ {error, {options, {cb_info, CbInfo}}};
+ exit:badarg ->
+ {error, {options, {socket_options, UserOpts}}};
+ exit:{badarg, _} ->
+ {error, {options, {socket_options, UserOpts}}}
+ end.
+
socket(Pid, Transport, Socket, ConnectionCb, Tracker) ->
#sslsocket{pid = Pid,
%% "The name "fd" is keept for backwards compatibility
@@ -241,3 +314,17 @@ get_emulated_opts(TrackerPid, EmOptNames) ->
lists:map(fun(Name) -> {value, Value} = lists:keysearch(Name, 1, EmOpts),
Value end,
EmOptNames).
+
+emulated_socket_options(InetValues, #socket_options{
+ mode = Mode,
+ header = Header,
+ active = Active,
+ packet = Packet,
+ packet_size = Size}) ->
+ #socket_options{
+ mode = proplists:get_value(mode, InetValues, Mode),
+ header = proplists:get_value(header, InetValues, Header),
+ active = proplists:get_value(active, InetValues, Active),
+ packet = proplists:get_value(packet, InetValues, Packet),
+ packet_size = proplists:get_value(packet_size, InetValues, Size)
+ }.
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 711db77708..6797b290d4 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,9 +31,18 @@
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
setup_keys/8, suites/1, prf/5,
- ecc_curves/1, oid_to_enum/1, enum_to_oid/1,
+ ecc_curves/1, ecc_curves/2, oid_to_enum/1, enum_to_oid/1,
default_signature_algs/1, signature_algs/2]).
+-type named_curve() :: sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1 |
+ sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1 |
+ sect283k1 | sect283r1 | brainpoolP256r1 | secp256k1 | secp256r1 |
+ sect239k1 | sect233k1 | sect233r1 | secp224k1 | secp224r1 |
+ sect193r1 | sect193r2 | secp192k1 | secp192r1 | sect163k1 |
+ sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2.
+-type curves() :: [named_curve()].
+-export_type([curves/0, named_curve/0]).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -195,21 +204,21 @@ suites(Minor) when Minor == 1; Minor == 2 ->
?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
?TLS_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-
?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_RSA_WITH_AES_128_CBC_SHA
+ ?TLS_RSA_WITH_AES_128_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA
];
suites(3) ->
[
@@ -399,13 +408,20 @@ is_pair(Hash, rsa, Hashs) ->
lists:member(Hash, AtLeastMd5).
%% list ECC curves in prefered order
-ecc_curves(_Minor) ->
- TLSCurves = [sect571r1,sect571k1,secp521r1,brainpoolP512r1,
- sect409k1,sect409r1,brainpoolP384r1,secp384r1,
- sect283k1,sect283r1,brainpoolP256r1,secp256k1,secp256r1,
- sect239k1,sect233k1,sect233r1,secp224k1,secp224r1,
- sect193r1,sect193r2,secp192k1,secp192r1,sect163k1,
- sect163r1,sect163r2,secp160k1,secp160r1,secp160r2],
+-spec ecc_curves(1..3 | all) -> [named_curve()].
+ecc_curves(all) ->
+ [sect571r1,sect571k1,secp521r1,brainpoolP512r1,
+ sect409k1,sect409r1,brainpoolP384r1,secp384r1,
+ sect283k1,sect283r1,brainpoolP256r1,secp256k1,secp256r1,
+ sect239k1,sect233k1,sect233r1,secp224k1,secp224r1,
+ sect193r1,sect193r2,secp192k1,secp192r1,sect163k1,
+ sect163r1,sect163r2,secp160k1,secp160r1,secp160r2];
+ecc_curves(Minor) ->
+ TLSCurves = ecc_curves(all),
+ ecc_curves(Minor, TLSCurves).
+
+-spec ecc_curves(1..3, [named_curve()]) -> [named_curve()].
+ecc_curves(_Minor, TLSCurves) ->
CryptoCurves = crypto:ec_curves(),
lists:foldr(fun(Curve, Curves) ->
case proplists:get_bool(Curve, CryptoCurves) of
@@ -414,6 +430,7 @@ ecc_curves(_Minor) ->
end
end, [], TLSCurves).
+
%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
oid_to_enum(?sect163k1) -> 1;
oid_to_enum(?sect163r1) -> 2;
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 009bcd81ad..e14f7f60c4 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -172,8 +172,8 @@ revoke(Root, CA, User, C) ->
gencrl(Root, CA, C).
gencrl(Root, CA, C) ->
- %% By default, the CRL is valid for 24 hours from now.
- gencrl(Root, CA, C, 24).
+ %% By default, the CRL is valid for a week from now.
+ gencrl(Root, CA, C, 24*7).
gencrl(Root, CA, C, CrlHours) ->
CACnfFile = filename:join([Root, CA, "ca.cnf"]),
diff --git a/lib/ssl/test/ssl.spec b/lib/ssl/test/ssl.spec
index 86e14c033e..0ad94e22bc 100644
--- a/lib/ssl/test/ssl.spec
+++ b/lib/ssl/test/ssl.spec
@@ -1,4 +1,5 @@
{suites,"../ssl_test",all}.
{skip_cases, "../ssl_test",
- ssl_bench_SUITE, [setup_sequential, setup_concurrent, payload_simple],
+ ssl_bench_SUITE, [setup_sequential, setup_concurrent, payload_simple,
+ use_pem_cache, bypass_pem_cache],
"Benchmarks run separately"}.
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index b8a03f578d..f779765b18 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -46,7 +46,7 @@ groups() ->
{'tlsv1', [], all_versions_groups()},
{'erlang_server', [], key_cert_combinations()},
{'erlang_client', [], key_cert_combinations()},
- {'erlang', [], key_cert_combinations() ++ misc()}
+ {'erlang', [], key_cert_combinations() ++ misc() ++ ecc_negotiation()}
].
all_versions_groups ()->
@@ -68,6 +68,23 @@ key_cert_combinations() ->
misc()->
[client_ecdsa_server_ecdsa_with_raw_key].
+ecc_negotiation() ->
+ [ecc_default_order,
+ ecc_default_order_custom_curves,
+ ecc_client_order,
+ ecc_client_order_custom_curves,
+ ecc_unknown_curve,
+ client_ecdh_server_ecdh_ecc_server_custom,
+ client_rsa_server_ecdh_ecc_server_custom,
+ client_ecdh_server_rsa_ecc_server_custom,
+ client_rsa_server_rsa_ecc_server_custom,
+ client_ecdsa_server_ecdsa_ecc_server_custom,
+ client_ecdsa_server_rsa_ecc_server_custom,
+ client_rsa_server_ecdsa_ecc_server_custom,
+ client_ecdsa_server_ecdsa_ecc_client_custom,
+ client_rsa_server_ecdsa_ecc_client_custom
+ ].
+
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
end_per_suite(Config0),
@@ -145,7 +162,7 @@ init_per_testcase(TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
end_per_testcase(TestCase, Config),
- ssl:start(),
+ ssl_test_lib:clean_start(),
ct:timetrap({seconds, 15}),
Config.
@@ -159,42 +176,42 @@ end_per_testcase(_TestCase, Config) ->
client_ecdh_server_ecdh(Config) when is_list(Config) ->
COpts = proplists:get_value(client_ecdh_rsa_opts, Config),
- SOpts = proplists:get_value(server_ecdh_rsa_verify_opts, Config),
+ SOpts = proplists:get_value(server_ecdh_rsa_opts, Config),
basic_test(COpts, SOpts, Config).
client_ecdh_server_rsa(Config) when is_list(Config) ->
COpts = proplists:get_value(client_ecdh_rsa_opts, Config),
- SOpts = proplists:get_value(server_ecdh_rsa_verify_opts, Config),
+ SOpts = proplists:get_value(server_opts, Config),
basic_test(COpts, SOpts, Config).
client_rsa_server_ecdh(Config) when is_list(Config) ->
- COpts = proplists:get_value(client_ecdh_rsa_opts, Config),
- SOpts = proplists:get_value(server_ecdh_rsa_verify_opts, Config),
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_ecdh_rsa_opts, Config),
basic_test(COpts, SOpts, Config).
client_rsa_server_rsa(Config) when is_list(Config) ->
- COpts = proplists:get_value(client_verification_opts, Config),
- SOpts = proplists:get_value(server_verification_opts, Config),
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_opts, Config),
basic_test(COpts, SOpts, Config).
client_ecdsa_server_ecdsa(Config) when is_list(Config) ->
COpts = proplists:get_value(client_ecdsa_opts, Config),
- SOpts = proplists:get_value(server_ecdsa_verify_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
basic_test(COpts, SOpts, Config).
client_ecdsa_server_rsa(Config) when is_list(Config) ->
COpts = proplists:get_value(client_ecdsa_opts, Config),
- SOpts = proplists:get_value(server_ecdsa_verify_opts, Config),
+ SOpts = proplists:get_value(server_opts, Config),
basic_test(COpts, SOpts, Config).
client_rsa_server_ecdsa(Config) when is_list(Config) ->
- COpts = proplists:get_value(client_ecdsa_opts, Config),
- SOpts = proplists:get_value(server_ecdsa_verify_opts, Config),
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
basic_test(COpts, SOpts, Config).
client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) ->
COpts = proplists:get_value(client_ecdsa_opts, Config),
- SOpts = proplists:get_value(server_ecdsa_verify_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
ServerCert = proplists:get_value(certfile, SOpts),
ServerKeyFile = proplists:get_value(keyfile, SOpts),
{ok, PemBin} = file:read_file(ServerKeyFile),
@@ -218,6 +235,132 @@ client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) ->
check_result(Server, SType, Client, CType),
close(Server, Client).
+ecc_default_order(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [],
+ case supported_eccs([{eccs, [sect571r1]}]) of
+ true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+ecc_default_order_custom_curves(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+ecc_client_order(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{honor_ecc_order, false}],
+ case supported_eccs([{eccs, [sect571r1]}]) of
+ true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+ecc_client_order_custom_curves(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{honor_ecc_order, false}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+ecc_unknown_curve(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{eccs, ['123_fake_curve']}],
+ ecc_test_error(COpts, SOpts, [], ECCOpts, Config).
+
+%% We can only expect to see a named curve on a conn with
+%% a server supporting ecdsa. Otherwise the curve is selected
+%% but not used and communicated to the client?
+client_ecdh_server_ecdh_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_ecdh_rsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdh_rsa_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_ecdh_server_rsa_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_ecdh_rsa_opts, Config),
+ SOpts = proplists:get_value(server_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_rsa_server_ecdh_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_ecdh_rsa_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_rsa_server_rsa_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_ecdsa_server_ecdsa_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_ecdsa_server_rsa_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_rsa_server_ecdsa_ecc_server_custom(Config) ->
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_ecdsa_server_ecdsa_ecc_client_custom(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
+client_rsa_server_ecdsa_ecc_client_custom(Config) ->
+ COpts = proplists:get_value(client_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ECCOpts = [{eccs, [secp256r1, sect571r1]}],
+ case supported_eccs(ECCOpts) of
+ true -> ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
+ false -> {skip, "unsupported named curves"}
+ end.
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -244,20 +387,48 @@ basic_test(ClientCert, ClientKey, ClientCA, ServerCert, ServerKey, ServerCA, Con
check_result(Server, SType, Client, CType),
close(Server, Client).
-start_client(openssl, Port, CA, OwnCa, Cert, Key, Config) ->
+
+ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
+ CCA = proplists:get_value(cacertfile, COpts),
+ CCert = proplists:get_value(certfile, COpts),
+ CKey = proplists:get_value(keyfile, COpts),
+ SCA = proplists:get_value(cacertfile, SOpts),
+ SCert = proplists:get_value(certfile, SOpts),
+ SKey = proplists:get_value(keyfile, SOpts),
+ {Server, Port} = start_server_ecc(erlang, CCA, SCA, SCert, SKey, Expect, SECCOpts, Config),
+ Client = start_client_ecc(erlang, Port, SCA, CCA, CCert, CKey, Expect, CECCOpts, Config),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ close(Server, Client).
+
+ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
+ CCA = proplists:get_value(cacertfile, COpts),
+ CCert = proplists:get_value(certfile, COpts),
+ CKey = proplists:get_value(keyfile, COpts),
+ SCA = proplists:get_value(cacertfile, SOpts),
+ SCert = proplists:get_value(certfile, SOpts),
+ SKey = proplists:get_value(keyfile, SOpts),
+ {Server, Port} = start_server_ecc_error(erlang, CCA, SCA, SCert, SKey, SECCOpts, Config),
+ Client = start_client_ecc_error(erlang, Port, SCA, CCA, CCert, CKey, CECCOpts, Config),
+ Error = {error, {tls_alert, "insufficient security"}},
+ ssl_test_lib:check_result(Server, Error, Client, Error).
+
+
+start_client(openssl, Port, PeerCA, OwnCa, Cert, Key, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
- NewCA = new_ca(filename:join(PrivDir, "new_ca.pem"), CA, OwnCa),
+ CA = new_openssl_ca(filename:join(PrivDir, "openssl_client_ca.pem"), PeerCA, OwnCa),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Exe = "openssl",
Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
ssl_test_lib:version_flag(Version),
- "-cert", Cert, "-CAfile", NewCA,
+ "-cert", Cert, "-CAfile", CA,
"-key", Key, "-host","localhost", "-msg", "-debug"],
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, "Hello world"),
OpenSslPort;
-start_client(erlang, Port, CA, _, Cert, Key, Config) ->
+start_client(erlang, Port, PeerCA, OwnCa, Cert, Key, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_ca(filename:join(PrivDir,"erlang_client_ca.pem"), PeerCA, OwnCa),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -267,20 +438,48 @@ start_client(erlang, Port, CA, _, Cert, Key, Config) ->
{cacertfile, CA},
{certfile, Cert}, {keyfile, Key}]}]).
-start_server(openssl, CA, OwnCa, Cert, Key, Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- NewCA = new_ca(filename:join(PrivDir, "new_ca.pem"), CA, OwnCa),
+start_client_ecc(erlang, Port, PeerCA, OwnCa, Cert, Key, Expect, ECCOpts, Config) ->
+ CA = new_ca("erlang_client_ca", PeerCA, OwnCa),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, check_ecc, [client, Expect]}},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer},
+ {cacertfile, CA},
+ {certfile, Cert}, {keyfile, Key}]}]).
+
+start_client_ecc_error(erlang, Port, PeerCA, OwnCa, Cert, Key, ECCOpts, Config) ->
+ CA = new_ca("erlang_client_ca", PeerCA, OwnCa),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer},
+ {cacertfile, CA},
+ {certfile, Cert}, {keyfile, Key}]}]).
+
+
+start_server(openssl, PeerCA, OwnCa, Cert, Key, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_openssl_ca(filename:join(PrivDir,"openssl_server_ca.pem"), PeerCA, OwnCa),
Port = ssl_test_lib:inet_port(node()),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-verify", "2", "-cert", Cert, "-CAfile", NewCA,
+ "-verify", "2", "-cert", Cert, "-CAfile", CA,
"-key", Key, "-msg", "-debug"],
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, "Hello world"),
{OpenSslPort, Port};
-start_server(erlang, CA, _, Cert, Key, Config) ->
+start_server(erlang, PeerCA, OwnCa, Cert, Key, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_ca(filename:join(PrivDir,"erlang_server_ca.pem"), PeerCA, OwnCa),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
@@ -291,16 +490,42 @@ start_server(erlang, CA, _, Cert, Key, Config) ->
[{verify, verify_peer}, {cacertfile, CA},
{certfile, Cert}, {keyfile, Key}]}]),
{Server, ssl_test_lib:inet_port(Server)}.
-start_server_with_raw_key(erlang, CA, _, Cert, Key, Config) ->
+
+start_server_with_raw_key(erlang, PeerCA, OwnCa, Cert, Key, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_ca(filename:join(PrivDir, "erlang_server_ca.pem"), PeerCA, OwnCa),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active,
- []}},
- {options,
- [{verify, verify_peer}, {cacertfile, CA},
- {certfile, Cert}, {key, Key}]}]),
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active,
+ []}},
+ {options,
+ [{verify, verify_peer}, {cacertfile, CA},
+ {certfile, Cert}, {key, Key}]}]),
+ {Server, ssl_test_lib:inet_port(Server)}.
+
+start_server_ecc(erlang, PeerCA, OwnCa, Cert, Key, Expect, ECCOpts, Config) ->
+ CA = new_ca("erlang_server_ca", PeerCA, OwnCa),
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, check_ecc, [server, Expect]}},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer}, {cacertfile, CA},
+ {certfile, Cert}, {keyfile, Key}]}]),
+ {Server, ssl_test_lib:inet_port(Server)}.
+
+start_server_ecc_error(erlang, PeerCA, OwnCa, Cert, Key, ECCOpts, Config) ->
+ CA = new_ca("erlang_server_ca", PeerCA, OwnCa),
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer}, {cacertfile, CA},
+ {certfile, Cert}, {keyfile, Key}]}]),
{Server, ssl_test_lib:inet_port(Server)}.
check_result(Server, erlang, Client, erlang) ->
@@ -336,19 +561,34 @@ close(Client, Server) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-%% Work around OpenSSL bug, apparently the same bug as we had fixed in
-%% 11629690ba61f8e0c93ef9b2b6102fd279825977
new_ca(FileName, CA, OwnCa) ->
{ok, P1} = file:read_file(CA),
E1 = public_key:pem_decode(P1),
{ok, P2} = file:read_file(OwnCa),
E2 = public_key:pem_decode(P2),
- case os:cmd("openssl version") of
- "OpenSSL 1.0.1p-freebsd" ++ _ ->
- Pem = public_key:pem_encode(E1 ++E2),
- file:write_file(FileName, Pem);
- _ ->
- Pem = public_key:pem_encode(E2 ++E1),
- file:write_file(FileName, Pem)
- end,
+ Pem = public_key:pem_encode(E1 ++E2),
+ file:write_file(FileName, Pem),
FileName.
+
+new_openssl_ca(FileName, CA, OwnCa) ->
+ {ok, P1} = file:read_file(CA),
+ E1 = public_key:pem_decode(P1),
+ {ok, P2} = file:read_file(OwnCa),
+ E2 = public_key:pem_decode(P2),
+ Pem = public_key:pem_encode(E2 ++E1),
+ file:write_file(FileName, Pem),
+ FileName.
+
+supported_eccs(Opts) ->
+ ToCheck = proplists:get_value(eccs, Opts, []),
+ Supported = ssl:eccs(),
+ lists:all(fun(Curve) -> lists:member(Curve, Supported) end, ToCheck).
+
+check_ecc(SSL, Role, Expect) ->
+ {ok, Data} = ssl:connection_information(SSL),
+ case lists:keyfind(ecc, 1, Data) of
+ {ecc, {named_curve, Expect}} -> ok;
+ false when Expect =:= undefined -> ok;
+ Other -> {error, Role, Expect, Other}
+ end.
+
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index da181faf64..158b3524ac 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
proplists:get_value(priv_dir, Config)),
ssl_test_lib:cert_options(Config)
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index efa5faa218..c846913598 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
-define(SLEEP, 500).
-define(RENEGOTIATION_DISABLE_TIME, 12000).
-define(CLEAN_SESSION_DB, 60000).
+-define(SEC_RENEGOTIATION_TIMEOUT, 30).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -51,8 +52,9 @@ all() ->
{group, options},
{group, options_tls},
{group, session},
- %%{group, 'dtlsv1.2'},
- %%{group, 'dtlsv1'},
+ {group, 'dtlsv1.2'},
+ %% {group, 'dtlsv1'}, Breaks dtls in cert_verify_SUITE enable later when
+ %% problem is identified and fixed
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -64,14 +66,15 @@ groups() ->
{basic_tls, [], basic_tests_tls()},
{options, [], options_tests()},
{options_tls, [], options_tests_tls()},
- %%{'dtlsv1.2', [], all_versions_groups()},
- %%{'dtlsv1', [], all_versions_groups()},
+ {'dtlsv1.2', [], all_versions_groups()},
+ {'dtlsv1', [], all_versions_groups()},
{'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]},
{'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()},
{'tlsv1', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests()},
{'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]},
{api,[], api_tests()},
{api_tls,[], api_tests_tls()},
+ {tls_ciphers,[], tls_cipher_tests()},
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
@@ -81,12 +84,13 @@ groups() ->
].
tls_versions_groups ()->
- [{group, api_tls},
+ [{group, renegotiate}, %% Should be in all_versions_groups not fixed for DTLS yet
+ {group, api_tls},
+ {group, tls_ciphers},
{group, error_handling_tests_tls}].
all_versions_groups ()->
[{group, api},
- {group, renegotiate},
{group, ciphers},
{group, ciphers_ec},
{group, error_handling_tests}].
@@ -134,7 +138,8 @@ options_tests() ->
honor_server_cipher_order,
honor_client_cipher_order,
unordered_protocol_versions_server,
- unordered_protocol_versions_client
+ unordered_protocol_versions_client,
+ max_handshake_size
].
options_tests_tls() ->
@@ -144,11 +149,10 @@ options_tests_tls() ->
api_tests() ->
[connection_info,
connection_information,
- peername,
peercert,
peercert_with_client_cert,
- sockname,
versions,
+ eccs,
controlling_process,
getstat,
close_with_timeout,
@@ -158,7 +162,6 @@ api_tests() ->
ssl_recv_timeout,
server_name_indication_option,
accept_pool,
- new_options_in_accept,
prf
].
@@ -171,7 +174,10 @@ api_tests_tls() ->
tls_shutdown,
tls_shutdown_write,
tls_shutdown_both,
- tls_shutdown_error
+ tls_shutdown_error,
+ peername,
+ sockname,
+ new_options_in_accept
].
session_tests() ->
@@ -193,6 +199,11 @@ renegotiate_tests() ->
renegotiate_dos_mitigate_passive,
renegotiate_dos_mitigate_absolute].
+tls_cipher_tests() ->
+ [rc4_rsa_cipher_suites,
+ rc4_ecdh_rsa_cipher_suites,
+ rc4_ecdsa_cipher_suites].
+
cipher_tests() ->
[cipher_suites,
cipher_suites_mix,
@@ -208,9 +219,6 @@ cipher_tests() ->
srp_cipher_suites,
srp_anon_cipher_suites,
srp_dsa_cipher_suites,
- rc4_rsa_cipher_suites,
- rc4_ecdh_rsa_cipher_suites,
- rc4_ecdsa_cipher_suites,
des_rsa_cipher_suites,
des_ecdh_rsa_cipher_suites,
default_reject_anonymous].
@@ -222,15 +230,15 @@ cipher_tests_ec() ->
ciphers_ecdh_rsa_signed_certs_openssl_names].
error_handling_tests()->
- [controller_dies,
- close_transport_accept,
+ [close_transport_accept,
recv_active,
recv_active_once,
recv_error_handling
].
error_handling_tests_tls()->
- [tls_client_closes_socket,
+ [controller_dies,
+ tls_client_closes_socket,
tls_tcp_error_propagation_in_active_mode,
tls_tcp_connect,
tls_tcp_connect_big,
@@ -249,7 +257,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
%% make rsa certs using oppenssl
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
@@ -306,6 +314,7 @@ init_per_testcase(protocol_versions, Config) ->
init_per_testcase(reuse_session_expired, Config) ->
ssl:stop(),
application:load(ssl),
+ ssl_test_lib:clean_env(),
application:set_env(ssl, session_lifetime, ?EXPIRE),
application:set_env(ssl, session_delay_cleanup_time, 500),
ssl:start(),
@@ -315,6 +324,7 @@ init_per_testcase(reuse_session_expired, Config) ->
init_per_testcase(empty_protocol_versions, Config) ->
ssl:stop(),
application:load(ssl),
+ ssl_test_lib:clean_env(),
application:set_env(ssl, protocol_version, []),
ssl:start(),
ct:timetrap({seconds, 5}),
@@ -340,7 +350,7 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
TestCase == renegotiate_dos_mitigate_passive;
TestCase == renegotiate_dos_mitigate_absolute ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 30}),
+ ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}),
Config;
init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
@@ -350,12 +360,27 @@ init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
TestCase == ciphers_dsa_signed_certs;
TestCase == ciphers_dsa_signed_certs_openssl_names;
TestCase == anonymous_cipher_suites;
+ TestCase == ciphers_ecdsa_signed_certs;
+ TestCase == ciphers_ecdsa_signed_certs_openssl_names;
+ TestCase == anonymous_cipher_suites;
+ TestCase == psk_anon_cipher_suites;
+ TestCase == psk_anon_with_hint_cipher_suites;
TestCase == versions_option,
TestCase == tls_tcp_connect_big ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 60}),
Config;
+init_per_testcase(version_option, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config;
+
+init_per_testcase(reuse_session, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config;
+
init_per_testcase(rizzo, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 40}),
@@ -408,8 +433,13 @@ init_per_testcase(TestCase, Config) when TestCase == tls_ssl_accept_timeout;
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 15}),
Config;
-init_per_testcase(clear_pem_cache, Config) ->
+init_per_testcase(TestCase, Config) when TestCase == clear_pem_cache;
+ TestCase == der_input;
+ TestCase == defaults ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ %% White box test need clean start
+ ssl:stop(),
+ ssl:start(),
ct:timetrap({seconds, 20}),
Config;
init_per_testcase(raw_ssl_option, Config) ->
@@ -430,7 +460,18 @@ init_per_testcase(accept_pool, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
Config
end;
-
+init_per_testcase(controller_dies, Config) ->
+ ct:timetrap({seconds, 10}),
+ Config;
+init_per_testcase(eccs, Config) ->
+ case ssl:eccs() of
+ [] ->
+ {skip, "named curves not supported"};
+ [_|_] ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 5}),
+ Config
+ end;
init_per_testcase(_TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 5}),
@@ -441,6 +482,11 @@ end_per_testcase(reuse_session_expired, Config) ->
application:unset_env(ssl, session_delay_cleanup_time),
end_per_testcase(default_action, Config);
+end_per_testcase(Case, Config) when Case == protocol_versions;
+ Case == empty_protocol_versions->
+ application:unset_env(ssl, protocol_versions),
+ end_per_testcase(default_action, Config);
+
end_per_testcase(_TestCase, Config) ->
Config.
@@ -567,8 +613,8 @@ prf(Config) when is_list(Config) ->
connection_info() ->
[{doc,"Test the API function ssl:connection_information/1"}].
connection_info(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -801,8 +847,7 @@ controller_dies(Config) when is_list(Config) ->
Server ! listen,
Tester = self(),
Connect = fun(Pid) ->
- {ok, Socket} = ssl:connect(Hostname, Port,
- [{reuseaddr,true},{ssl_imp,new}]),
+ {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
%% Make sure server finishes and verification
%% and is in coonection state before
%% killing client
@@ -919,9 +964,9 @@ clear_pem_cache(Config) when is_list(Config) ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
- [_,FilRefDb |_] = element(6, State),
+ [_,{FilRefDb, _} |_] = element(6, State),
{Server, Client} = basic_verify_test_no_close(Config),
- CountReferencedFiles = fun({_,-1}, Acc) ->
+ CountReferencedFiles = fun({_, -1}, Acc) ->
Acc;
({_, N}, Acc) ->
N + Acc
@@ -1144,8 +1189,8 @@ cipher_suites_mix() ->
cipher_suites_mix(Config) when is_list(Config) ->
CipherSuites = [{ecdh_rsa,aes_128_cbc,sha256,sha256}, {rsa,aes_128_cbc,sha}],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1474,6 +1519,25 @@ versions(Config) when is_list(Config) ->
[_|_] = Versions = ssl:versions(),
ct:log("~p~n", [Versions]).
+
+%%--------------------------------------------------------------------
+eccs() ->
+ [{doc, "Test API functions eccs/0 and eccs/1"}].
+
+eccs(Config) when is_list(Config) ->
+ [_|_] = All = ssl:eccs(),
+ [] = SSL3 = ssl:eccs({3,0}),
+ [_|_] = Tls = ssl:eccs({3,1}),
+ [_|_] = Tls1 = ssl:eccs({3,2}),
+ [_|_] = Tls2 = ssl:eccs({3,3}),
+ [] = SSL3 = ssl:eccs(sslv3),
+ [_|_] = Tls = ssl:eccs(tlsv1),
+ [_|_] = Tls1 = ssl:eccs('tlsv1.1'),
+ [_|_] = Tls2 = ssl:eccs('tlsv1.2'),
+ %% ordering is currently unverified by the test
+ true = lists:sort(All) =:= lists:usort(SSL3 ++ Tls ++ Tls1 ++ Tls2),
+ ok.
+
%%--------------------------------------------------------------------
send_recv() ->
[{doc,""}].
@@ -2133,8 +2197,9 @@ ciphers_dsa_signed_certs() ->
[{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
ciphers_dsa_signed_certs(Config) when is_list(Config) ->
+ NVersion = ssl_test_lib:protocol_version(Config, tuple),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:dsa_suites(),
+ Ciphers = ssl_test_lib:dsa_suites(NVersion),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
@@ -2151,35 +2216,39 @@ anonymous_cipher_suites()->
[{doc,"Test the anonymous ciphersuites"}].
anonymous_cipher_suites(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:anonymous_suites(),
+ Ciphers = ssl_test_lib:anonymous_suites(Version),
run_suites(Ciphers, Version, Config, anonymous).
%%-------------------------------------------------------------------
psk_cipher_suites() ->
[{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
psk_cipher_suites(Config) when is_list(Config) ->
+ NVersion = tls_record:highest_protocol_version([]),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:psk_suites(),
+ Ciphers = ssl_test_lib:psk_suites(NVersion),
run_suites(Ciphers, Version, Config, psk).
%%-------------------------------------------------------------------
psk_with_hint_cipher_suites()->
[{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
psk_with_hint_cipher_suites(Config) when is_list(Config) ->
+ NVersion = tls_record:highest_protocol_version([]),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:psk_suites(),
+ Ciphers = ssl_test_lib:psk_suites(NVersion),
run_suites(Ciphers, Version, Config, psk_with_hint).
%%-------------------------------------------------------------------
psk_anon_cipher_suites() ->
[{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
psk_anon_cipher_suites(Config) when is_list(Config) ->
+ NVersion = tls_record:highest_protocol_version([]),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:psk_anon_suites(),
+ Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
run_suites(Ciphers, Version, Config, psk_anon).
%%-------------------------------------------------------------------
psk_anon_with_hint_cipher_suites()->
[{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
+ NVersion = tls_record:highest_protocol_version([]),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:psk_anon_suites(),
+ Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
run_suites(Ciphers, Version, Config, psk_anon_with_hint).
%%-------------------------------------------------------------------
srp_cipher_suites()->
@@ -2230,18 +2299,17 @@ rc4_ecdsa_cipher_suites(Config) when is_list(Config) ->
%%-------------------------------------------------------------------
des_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
+ [{doc, "Test the des_rsa ciphersuites"}].
des_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Version = tls_record:protocol_version(NVersion),
- Ciphers = ssl_test_lib:des_suites(NVersion),
+ Version = ssl_test_lib:protocol_version(Config),
+ Ciphers = ssl_test_lib:des_suites(Config),
run_suites(Ciphers, Version, Config, des_rsa).
%-------------------------------------------------------------------
des_ecdh_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
+ [{doc, "Test ECDH rsa signed ciphersuites"}].
des_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Version = tls_record:protocol_version(NVersion),
+ NVersion = ssl_test_lib:protocol_version(Config, tuple),
+ Version = ssl_test_lib:protocol_version(Config),
Ciphers = ssl_test_lib:des_suites(NVersion),
run_suites(Ciphers, Version, Config, des_dhe_rsa).
@@ -2252,9 +2320,11 @@ default_reject_anonymous(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- [Cipher | _] = ssl_test_lib:anonymous_suites(),
-
+ Version = ssl_test_lib:protocol_version(Config),
+ TLSVersion = ssl_test_lib:tls_version(Version),
+
+ [CipherSuite | _] = ssl_test_lib:anonymous_suites(TLSVersion),
+
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{options, ServerOpts}]),
@@ -2263,7 +2333,7 @@ default_reject_anonymous(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{options,
- [{ciphers,[Cipher]} |
+ [{ciphers,[CipherSuite]} |
ClientOpts]}]),
ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}},
@@ -2274,8 +2344,9 @@ ciphers_ecdsa_signed_certs() ->
[{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
+ NVersion = ssl_test_lib:protocol_version(Config, tuple),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:ecdsa_suites(),
+ Ciphers = ssl_test_lib:ecdsa_suites(NVersion),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, ecdsa).
%%--------------------------------------------------------------------
@@ -2292,8 +2363,9 @@ ciphers_ecdh_rsa_signed_certs() ->
[{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
+ NVersion = ssl_test_lib:protocol_version(Config, tuple),
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:ecdh_rsa_suites(),
+ Ciphers = ssl_test_lib:ecdh_rsa_suites(NVersion),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, ecdh_rsa).
%%--------------------------------------------------------------------
@@ -3265,11 +3337,11 @@ hibernate(Config) ->
process_info(Pid, current_function),
ssl_test_lib:check_result(Server, ok, Client, ok),
- timer:sleep(1100),
-
+
+ timer:sleep(1500),
{current_function, {erlang, hibernate, 3}} =
process_info(Pid, current_function),
-
+
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -3302,13 +3374,12 @@ hibernate_right_away(Config) ->
[{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
ssl_test_lib:check_result(Server1, ok, Client1, ok),
-
- {current_function, {erlang, hibernate, 3}} =
+
+ {current_function, {erlang, hibernate, 3}} =
process_info(Pid1, current_function),
-
ssl_test_lib:close(Server1),
ssl_test_lib:close(Client1),
-
+
Server2 = ssl_test_lib:start_server(StartServerOpts),
Port2 = ssl_test_lib:inet_port(Server2),
{Client2, #sslsocket{pid = Pid2}} = ssl_test_lib:start_client(StartClientOpts ++
@@ -3316,8 +3387,8 @@ hibernate_right_away(Config) ->
ssl_test_lib:check_result(Server2, ok, Client2, ok),
- ct:sleep(100), %% Schedule out
-
+ ct:sleep(1000), %% Schedule out
+
{current_function, {erlang, hibernate, 3}} =
process_info(Pid2, current_function),
@@ -3604,9 +3675,10 @@ no_rizzo_rc4() ->
[{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}].
no_rizzo_rc4(Config) when is_list(Config) ->
- Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(),Y == rc4_128],
Prop = proplists:get_value(tc_group_properties, Config),
Version = proplists:get_value(name, Prop),
+ Ciphers = [ssl_cipher:erl_suite_definition(Suite) ||
+ Suite <- ssl_test_lib:rc4_suites(tls_record:protocol_version(Version))],
run_send_recv_rizzo(Ciphers, Config, Version,
{?MODULE, send_recv_result_active_no_rizzo, []}).
@@ -3614,9 +3686,10 @@ rizzo_one_n_minus_one() ->
[{doc,"Test that the 1/n-1-split mitigation of Rizzo/Dungon attack can be explicitly selected"}].
rizzo_one_n_minus_one(Config) when is_list(Config) ->
- Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(), Y =/= rc4_128],
Prop = proplists:get_value(tc_group_properties, Config),
Version = proplists:get_value(name, Prop),
+ AllSuites = ssl_test_lib:available_suites(tls_record:protocol_version(Version)),
+ Ciphers = [X || X ={_,Y,_} <- AllSuites, Y =/= rc4_128],
run_send_recv_rizzo(Ciphers, Config, Version,
{?MODULE, send_recv_result_active_rizzo, []}).
@@ -3624,9 +3697,10 @@ rizzo_zero_n() ->
[{doc,"Test that the 0/n-split mitigation of Rizzo/Dungon attack can be explicitly selected"}].
rizzo_zero_n(Config) when is_list(Config) ->
- Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(), Y =/= rc4_128],
Prop = proplists:get_value(tc_group_properties, Config),
Version = proplists:get_value(name, Prop),
+ AllSuites = ssl_test_lib:available_suites(tls_record:protocol_version(Version)),
+ Ciphers = [X || X ={_,Y,_} <- AllSuites, Y =/= rc4_128],
run_send_recv_rizzo(Ciphers, Config, Version,
{?MODULE, send_recv_result_active_no_rizzo, []}).
@@ -3797,6 +3871,29 @@ unordered_protocol_versions_client(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
+max_handshake_size() ->
+ [{doc,"Test that we can set max_handshake_size to max value."}].
+
+max_handshake_size(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} |ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+%%--------------------------------------------------------------------
server_name_indication_option() ->
[{doc,"Test API server_name_indication option to connect."}].
@@ -4288,7 +4385,7 @@ erlang_ssl_receive(Socket, Data) ->
erlang_ssl_receive(Socket, tl(Data));
Other ->
ct:fail({unexpected_message, Other})
- after ?SLEEP * 3 * test_server:timetrap_scale_factor() ->
+ after timer:seconds(?SEC_RENEGOTIATION_TIMEOUT) * test_server:timetrap_scale_factor() ->
ct:fail({did_not_get, Data})
end.
@@ -4377,7 +4474,7 @@ rizzo_test(Cipher, Config, Version, Mfa) ->
{host, Hostname},
{from, self()},
{mfa, Mfa},
- {options, [{active, true} | ClientOpts]}]),
+ {options, [{active, true}, {ciphers, [Cipher]}| ClientOpts]}]),
Result = ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
@@ -4409,27 +4506,32 @@ run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
case Type of
rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_opts, Config)};
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ssl_test_lib:ssl_options(server_verification_opts, Config)};
dsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
ssl_test_lib:ssl_options(server_dsa_opts, Config)};
anonymous ->
%% No certs in opts!
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_anon, Config)};
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
+ [{reuseaddr, true}, {ciphers, ssl_test_lib:anonymous_suites(Version)}]};
psk ->
{ssl_test_lib:ssl_options(client_psk, Config),
- ssl_test_lib:ssl_options(server_psk, Config)};
+ [{ciphers, ssl_test_lib:psk_suites(Version)} |
+ ssl_test_lib:ssl_options(server_psk, Config)]};
psk_with_hint ->
{ssl_test_lib:ssl_options(client_psk, Config),
- ssl_test_lib:ssl_options(server_psk_hint, Config)};
+ [{ciphers, ssl_test_lib:psk_suites(Version)} |
+ ssl_test_lib:ssl_options(server_psk_hint, Config)
+ ]};
psk_anon ->
{ssl_test_lib:ssl_options(client_psk, Config),
- ssl_test_lib:ssl_options(server_psk_anon, Config)};
+ [{ciphers, ssl_test_lib:psk_anon_suites(Version)} |
+ ssl_test_lib:ssl_options(server_psk_anon, Config)]};
psk_anon_with_hint ->
{ssl_test_lib:ssl_options(client_psk, Config),
- ssl_test_lib:ssl_options(server_psk_anon_hint, Config)};
+ [{ciphers, ssl_test_lib:psk_anon_suites(Version)} |
+ ssl_test_lib:ssl_options(server_psk_anon_hint, Config)]};
srp ->
{ssl_test_lib:ssl_options(client_srp, Config),
ssl_test_lib:ssl_options(server_srp, Config)};
@@ -4440,36 +4542,36 @@ run_suites(Ciphers, Version, Config, Type) ->
{ssl_test_lib:ssl_options(client_srp_dsa, Config),
ssl_test_lib:ssl_options(server_srp_dsa, Config)};
ecdsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
ssl_test_lib:ssl_options(server_ecdsa_opts, Config)};
ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)};
rc4_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
[{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_opts, Config)]};
+ ssl_test_lib:ssl_options(server_verification_opts, Config)]};
rc4_ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
[{ciphers, Ciphers} |
ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
rc4_ecdsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
[{ciphers, Ciphers} |
ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
des_dhe_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
[{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_opts, Config)]};
+ ssl_test_lib:ssl_options(server_verification_opts, Config)]};
des_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
+ {ssl_test_lib:ssl_options(client_verification_opts, Config),
[{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_opts, Config)]}
+ ssl_test_lib:ssl_options(server_verification_opts, Config)]}
end,
Result = lists:map(fun(Cipher) ->
cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- ssl_test_lib:filter_suites(Ciphers)),
+ ssl_test_lib:filter_suites(Ciphers, Version)),
case lists:flatten(Result) of
[] ->
ok;
@@ -4668,3 +4770,4 @@ first_rsa_suite([_ | Rest]) ->
wait_for_send(Socket) ->
%% Make sure TLS process processed send message event
_ = ssl:connection_information(Socket).
+
diff --git a/lib/ssl/test/ssl_bench_SUITE.erl b/lib/ssl/test/ssl_bench_SUITE.erl
index ed439a425f..21989f8d99 100644
--- a/lib/ssl/test/ssl_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_bench_SUITE.erl
@@ -25,11 +25,12 @@
suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
-all() -> [{group, setup}, {group, payload}].
+all() -> [{group, setup}, {group, payload}, {group, pem_cache}].
groups() ->
[{setup, [{repeat, 3}], [setup_sequential, setup_concurrent]},
- {payload, [{repeat, 3}], [payload_simple]}
+ {payload, [{repeat, 3}], [payload_simple]},
+ {pem_cache, [{repeat, 3}], [use_pem_cache, bypass_pem_cache]}
].
init_per_group(_GroupName, Config) ->
@@ -49,9 +50,33 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
+init_per_testcase(use_pem_cache, Conf) ->
+ case bypass_pem_cache_supported() of
+ false -> {skipped, "PEM cache bypass support required"};
+ true ->
+ application:set_env(ssl, bypass_pem_cache, false),
+ Conf
+ end;
+init_per_testcase(bypass_pem_cache, Conf) ->
+ case bypass_pem_cache_supported() of
+ false -> {skipped, "PEM cache bypass support required"};
+ true ->
+ application:set_env(ssl, bypass_pem_cache, true),
+ Conf
+ end;
init_per_testcase(_Func, Conf) ->
Conf.
+end_per_testcase(use_pem_cache, _Config) ->
+ case bypass_pem_cache_supported() of
+ false -> ok;
+ true -> application:set_env(ssl, bypass_pem_cache, false)
+ end;
+end_per_testcase(bypass_pem_cache, _Config) ->
+ case bypass_pem_cache_supported() of
+ false -> ok;
+ true -> application:set_env(ssl, bypass_pem_cache, false)
+ end;
end_per_testcase(_Func, _Conf) ->
ok.
@@ -94,6 +119,18 @@ payload_simple(Config) ->
{suite, "ssl"}, {name, "Payload simple"}]}),
ok.
+use_pem_cache(_Config) ->
+ {ok, Result} = do_test(ssl, pem_cache, 100, 500, node()),
+ ct_event:notify(#event{name = benchmark_data,
+ data=[{value, Result},
+ {suite, "ssl"}, {name, "Use PEM cache"}]}).
+
+bypass_pem_cache(_Config) ->
+ {ok, Result} = do_test(ssl, pem_cache, 100, 500, node()),
+ ct_event:notify(#event{name = benchmark_data,
+ data=[{value, Result},
+ {suite, "ssl"}, {name, "Bypass PEM cache"}]}).
+
ssl() ->
test(ssl, ?COUNT, node()).
@@ -172,6 +209,18 @@ server_init(ssl, payload, Loop, _, Server) ->
ssl:close(TSocket)
end,
setup_server_connection(Socket, Test);
+server_init(ssl, pem_cache, Loop, _, Server) ->
+ {ok, Socket} = ssl:listen(0, ssl_opts(listen_der)),
+ {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, Host} = inet:gethostname(),
+ Server ! {self(), {init, Host, Port}},
+ Test = fun(TSocket) ->
+ ok = ssl:ssl_accept(TSocket),
+ Size = byte_size(msg()),
+ server_echo(TSocket, Size, Loop),
+ ssl:close(TSocket)
+ end,
+ setup_server_connection(Socket, Test);
server_init(Type, Tc, _, _, Server) ->
io:format("No server init code for ~p ~p~n",[Type, Tc]),
@@ -185,6 +234,11 @@ client_init(Master, ssl, payload, Host, Port) ->
Master ! {self(), init},
Size = byte_size(msg()),
{Sock, Size};
+client_init(Master, ssl, pem_cache, Host, Port) ->
+ {ok, Sock} = ssl:connect(Host, Port, ssl_opts(connect_der)),
+ Master ! {self(), init},
+ Size = byte_size(msg()),
+ {Sock, Size};
client_init(_Me, Type, Tc, Host, Port) ->
io:format("No client init code for ~p ~p~n",[Type, Tc]),
{Host, Port}.
@@ -228,6 +282,13 @@ payload(Loop, ssl, D = {Socket, Size}) when Loop > 0 ->
payload(_, _, {Socket, _}) ->
ssl:close(Socket).
+pem_cache(N, ssl, Data = {Socket, Size}) when N > 0 ->
+ ok = ssl:send(Socket, msg()),
+ {ok, _} = ssl:recv(Socket, Size),
+ pem_cache(N-1, ssl, Data);
+pem_cache(_, _, {Socket, _}) ->
+ ssl:close(Socket).
+
msg() ->
<<"Hello",
0:(512*8),
@@ -352,16 +413,43 @@ stop_profile(fprof, File) ->
ssl_opts(listen) ->
[{backlog, 500} | ssl_opts("server")];
ssl_opts(connect) ->
- [{verify, verify_peer}
- | ssl_opts("client")];
+ [{verify, verify_peer} | ssl_opts("client")];
+ssl_opts(listen_der) ->
+ [{backlog, 500} | ssl_opts("server_der")];
+ssl_opts(connect_der) ->
+ [{verify, verify_peer} | ssl_opts("client_der")];
ssl_opts(Role) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
+ CertData = cert_data(Role),
[{active, false},
{depth, 2},
{reuseaddr, true},
{mode,binary},
{nodelay, true},
- {ciphers, [{dhe_rsa,aes_256_cbc,sha}]},
- {cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
+ {ciphers, [{dhe_rsa,aes_256_cbc,sha}]}
+ |CertData].
+
+cert_data(Der) when Der =:= "server_der"; Der =:= "client_der" ->
+ [Role,_] = string:tokens(Der, "_"),
+ Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
+ {ok, CaCert0} = file:read_file(filename:join([Dir, Role, "cacerts.pem"])),
+ {ok, Cert0} = file:read_file(filename:join([Dir, Role, "cert.pem"])),
+ {ok, Key0} = file:read_file(filename:join([Dir, Role, "key.pem"])),
+ [{_, Cert, _}] = public_key:pem_decode(Cert0),
+ CaCert1 = public_key:pem_decode(CaCert0),
+ CaCert = [CCert || {_, CCert, _} <- CaCert1],
+ [{KeyType, Key, _}] = public_key:pem_decode(Key0),
+ [{cert, Cert},
+ {cacerts, CaCert},
+ {key, {KeyType, Key}}];
+cert_data(Role) ->
+ Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
+ [{cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
{certfile, filename:join([Dir, Role, "cert.pem"])},
{keyfile, filename:join([Dir, Role, "key.pem"])}].
+
+bypass_pem_cache_supported() ->
+ %% This function is currently critical to support cache bypass
+ %% and did not exist in prior versions.
+ catch ssl_pkix_db:module_info(), % ensure module is loaded
+ erlang:function_exported(ssl_pkix_db, extract_trusted_certs, 1).
+
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 20165c70f0..bed6f87c74 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,17 +39,26 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [{group, active},
- {group, passive},
- {group, active_once},
- {group, error_handling}].
-
+ [
+ {group, tls},
+ {group, dtls}
+ ].
groups() ->
- [{active, [], tests()},
+ [
+ {tls, [], all_protocol_groups()},
+ {dtls, [], all_protocol_groups()},
+ {active, [], tests()},
{active_once, [], tests()},
{passive, [], tests()},
- {error_handling, [],error_handling_tests()}].
+ {error_handling, [],error_handling_tests()}
+ ].
+
+all_protocol_groups() ->
+ [{group, active},
+ {group, passive},
+ {group, active_once},
+ {group, error_handling}].
tests() ->
[verify_peer,
@@ -65,9 +74,10 @@ tests() ->
cert_expired,
invalid_signature_client,
invalid_signature_server,
- extended_key_usage_verify_peer,
- extended_key_usage_verify_none,
- critical_extension_verify_peer,
+ extended_key_usage_verify_client,
+ extended_key_usage_verify_server,
+ critical_extension_verify_client,
+ critical_extension_verify_server,
critical_extension_verify_none].
error_handling_tests()->
@@ -84,7 +94,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
%% make rsa certs using oppenssl
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
@@ -98,6 +108,26 @@ end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
+init_per_group(tls, Config) ->
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, protocol_version, Version),
+ application:set_env(ssl, bypass_pem_cache, Version),
+ ssl:start(),
+ NewConfig = proplists:delete(protocol, Config),
+ [{protocol, tls}, {version, tls_record:protocol_version(Version)} | NewConfig];
+
+init_per_group(dtls, Config) ->
+ Version = dtls_record:protocol_version(dtls_record:highest_protocol_version([])),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, protocol_version, Version),
+ application:set_env(ssl, bypass_pem_cache, Version),
+ ssl:start(),
+ NewConfig = proplists:delete(protocol_opts, proplists:delete(protocol, Config)),
+ [{protocol, dtls}, {protocol_opts, [{protocol, dtls}]}, {version, dtls_record:protocol_version(Version)} | NewConfig];
+
init_per_group(active, Config) ->
[{active, true}, {receive_function, send_recv_result_active} | Config];
init_per_group(active_once, Config) ->
@@ -122,6 +152,8 @@ init_per_testcase(TestCase, Config) when TestCase == cert_expired;
ssl:clear_pem_cache(),
init_per_testcase(common, Config);
init_per_testcase(_TestCase, Config) ->
+ ssl:stop(),
+ ssl:start(),
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 5}),
Config.
@@ -136,7 +168,7 @@ end_per_testcase(_TestCase, Config) ->
verify_peer() ->
[{doc,"Test option verify_peer"}].
verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
@@ -190,7 +222,7 @@ server_verify_client_once() ->
[{doc,"Test server option verify_client_once"}].
server_verify_client_once(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, []),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
@@ -230,7 +262,7 @@ server_require_peer_cert_ok() ->
server_require_peer_cert_ok(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
| ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -259,7 +291,7 @@ server_require_peer_cert_fail() ->
server_require_peer_cert_fail(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
| ssl_test_lib:ssl_options(server_verification_opts, Config)],
- BadClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ BadClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
@@ -290,7 +322,7 @@ server_require_peer_cert_partial_chain() ->
server_require_peer_cert_partial_chain(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
| ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
{ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
@@ -325,13 +357,13 @@ server_require_peer_cert_allow_partial_chain() ->
server_require_peer_cert_allow_partial_chain(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
| ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
- {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _}] = public_key:pem_decode(ServerCAs),
+ {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
+ [{_,_,_}, {_, IntermidiateCA, _}] = public_key:pem_decode(ClientCAs),
PartialChain = fun(CertChain) ->
case lists:member(IntermidiateCA, CertChain) of
@@ -367,7 +399,7 @@ server_require_peer_cert_do_not_allow_partial_chain() ->
server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
| ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
{ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
@@ -408,7 +440,7 @@ server_require_peer_cert_partial_chain_fun_fail() ->
server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
| ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = proplists:get_value(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
{ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
@@ -448,7 +480,7 @@ verify_fun_always_run_client() ->
verify_fun_always_run_client(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -492,7 +524,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
verify_fun_always_run_server() ->
[{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
verify_fun_always_run_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -524,9 +556,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
{from, self()},
{mfa, {ssl_test_lib,
no_result, []}},
- {options,
- [{verify, verify_peer}
- | ClientOpts]}]),
+ {options, ClientOpts}]),
%% Client error may be {tls_alert, "handshake failure" } or closed depending on timing
%% this is not a bug it is a circumstance of how tcp works!
@@ -544,7 +574,7 @@ cert_expired() ->
cert_expired(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
@@ -607,11 +637,11 @@ two_digits_str(N) ->
lists:flatten(io_lib:format("~p", [N])).
%%--------------------------------------------------------------------
-extended_key_usage_verify_peer() ->
- [{doc,"Test cert that has a critical extended_key_usage extension in verify_peer mode"}].
+extended_key_usage_verify_server() ->
+ [{doc,"Test cert that has a critical extended_key_usage extension in verify_peer mode for server"}].
-extended_key_usage_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+extended_key_usage_verify_server(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
Active = proplists:get_value(active, Config),
@@ -660,7 +690,7 @@ extended_key_usage_verify_peer(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_peer}, {active, Active} |
+ {options, [{verify, verify_none}, {active, Active} |
NewClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -669,12 +699,12 @@ extended_key_usage_verify_peer(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-extended_key_usage_verify_none() ->
- [{doc,"Test cert that has a critical extended_key_usage extension in verify_none mode"}].
+extended_key_usage_verify_client() ->
+ [{doc,"Test cert that has a critical extended_key_usage extension in client verify_peer mode"}].
-extended_key_usage_verify_none(Config) when is_list(Config) ->
+extended_key_usage_verify_client(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
@@ -730,11 +760,11 @@ extended_key_usage_verify_none(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-critical_extension_verify_peer() ->
+critical_extension_verify_server() ->
[{doc,"Test cert that has a critical unknown extension in verify_peer mode"}].
-critical_extension_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+critical_extension_verify_server(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
Active = proplists:get_value(active, Config),
@@ -766,7 +796,7 @@ critical_extension_verify_peer(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_peer}, {active, Active} | NewClientOpts]}]),
+ {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]),
%% This certificate has a critical extension that we don't
%% understand. Therefore, verification should fail.
@@ -775,14 +805,60 @@ critical_extension_verify_peer(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ok.
+%%--------------------------------------------------------------------
+
+critical_extension_verify_client() ->
+ [{doc,"Test cert that has a critical unknown extension in verify_peer mode"}].
+
+critical_extension_verify_client(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Active = proplists:get_value(active, Config),
+ ReceiveFunction = proplists:get_value(receive_function, Config),
+ KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
+ NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem",
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ NewServerCertFile = filename:join([PrivDir, "server", NewCertName]),
+ add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile),
+ NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ NewClientCertFile = filename:join([PrivDir, "client", NewCertName]),
+ add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile),
+ NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_error(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{verify, verify_peer}, {active, Active} | NewClientOpts]}]),
+
+ %% This certificate has a critical extension that we don't
+ %% understand. Therefore, verification should fail.
+ tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}},
+ Client, {error, {tls_alert, "unsupported certificate"}}),
+
+ ssl_test_lib:close(Server),
+ ok.
%%--------------------------------------------------------------------
critical_extension_verify_none() ->
[{doc,"Test cert that has a critical unknown extension in verify_none mode"}].
critical_extension_verify_none(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
@@ -1044,13 +1120,15 @@ client_with_cert_cipher_suites_handshake() ->
client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_verification_opts_digital_signature_only, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib,
send_recv_result_active, []}},
{options, [{active, true},
- {ciphers, ssl_test_lib:rsa_non_signed_suites()}
+ {ciphers,
+ ssl_test_lib:rsa_non_signed_suites(proplists:get_value(version, Config))}
| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
@@ -1070,7 +1148,7 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
server_verify_no_cacerts() ->
[{doc,"Test server must have cacerts if it wants to verify client"}].
server_verify_no_cacerts(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_opts, Config)),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -1084,7 +1162,7 @@ server_verify_no_cacerts(Config) when is_list(Config) ->
unknown_server_ca_fail() ->
[{doc,"Test that the client fails if the ca is unknown in verify_peer mode"}].
unknown_server_ca_fail(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
@@ -1128,7 +1206,7 @@ unknown_server_ca_fail(Config) when is_list(Config) ->
unknown_server_ca_accept_verify_none() ->
[{doc,"Test that the client succeds if the ca is unknown in verify_none mode"}].
unknown_server_ca_accept_verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -1153,8 +1231,8 @@ unknown_server_ca_accept_verify_peer() ->
[{doc, "Test that the client succeds if the ca is unknown in verify_peer mode"
" with a verify_fun that accepts the unknown ca error"}].
unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
@@ -1192,7 +1270,7 @@ unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
unknown_server_ca_accept_backwardscompatibility() ->
[{doc,"Test that old style verify_funs will work"}].
unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
index 00636e5660..e293d183f7 100644
--- a/lib/ssl/test/ssl_crl_SUITE.erl
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -72,7 +72,7 @@ init_per_suite(Config) ->
false ->
{skip, io_lib:format("Bad openssl version: ~p",[OpenSSL_version])};
_ ->
- catch crypto:stop(),
+ end_per_suite(Config),
try crypto:start() of
ok ->
{ok, Hostname0} = inet:gethostname(),
@@ -99,32 +99,37 @@ init_per_group(check_peer, Config) ->
init_per_group(check_best_effort, Config) ->
[{crl_check, best_effort} | Config];
init_per_group(Group, Config0) ->
- case is_idp(Group) of
- true ->
- [{idp_crl, true} | Config0];
- false ->
- DataDir = proplists:get_value(data_dir, Config0),
- CertDir = filename:join(proplists:get_value(priv_dir, Config0), Group),
- {CertOpts, Config} = init_certs(CertDir, Group, Config0),
- {ok, _} = make_certs:all(DataDir, CertDir, CertOpts),
- case Group of
- crl_hash_dir ->
- CrlDir = filename:join(CertDir, "crls"),
- %% Copy CRLs to their hashed filenames.
- %% Find the hashes with 'openssl crl -noout -hash -in crl.pem'.
- populate_crl_hash_dir(CertDir, CrlDir,
- [{"erlangCA", "d6134ed3"},
- {"otpCA", "d4c8d7e5"}],
- replace),
- CrlCacheOpts = [{crl_cache,
- {ssl_crl_hash_dir,
- {internal, [{dir, CrlDir}]}}}];
- _ ->
- CrlCacheOpts = []
- end,
- [{crl_cache_opts, CrlCacheOpts},
- {cert_dir, CertDir},
- {idp_crl, false} | Config]
+ try
+ case is_idp(Group) of
+ true ->
+ [{idp_crl, true} | Config0];
+ false ->
+ DataDir = proplists:get_value(data_dir, Config0),
+ CertDir = filename:join(proplists:get_value(priv_dir, Config0), Group),
+ {CertOpts, Config} = init_certs(CertDir, Group, Config0),
+ {ok, _} = make_certs:all(DataDir, CertDir, CertOpts),
+ CrlCacheOpts = case Group of
+ crl_hash_dir ->
+ CrlDir = filename:join(CertDir, "crls"),
+ %% Copy CRLs to their hashed filenames.
+ %% Find the hashes with 'openssl crl -noout -hash -in crl.pem'.
+ populate_crl_hash_dir(CertDir, CrlDir,
+ [{"erlangCA", "d6134ed3"},
+ {"otpCA", "d4c8d7e5"}],
+ replace),
+ [{crl_cache,
+ {ssl_crl_hash_dir,
+ {internal, [{dir, CrlDir}]}}}];
+ _ ->
+ []
+ end,
+ [{crl_cache_opts, CrlCacheOpts},
+ {cert_dir, CertDir},
+ {idp_crl, false} | Config]
+ end
+ catch
+ _:_ ->
+ {skip, "Unable to create crls"}
end.
end_per_group(_GroupName, Config) ->
@@ -136,7 +141,7 @@ init_per_testcase(Case, Config0) ->
true ->
end_per_testcase(Case, Config0),
inets:start(),
- ssl:start(),
+ ssl_test_lib:clean_start(),
ServerRoot = make_dir_path([proplists:get_value(priv_dir, Config0), idp_crl, tmp]),
%% start a HTTP server to serve the CRLs
{ok, Httpd} = inets:start(httpd, [{ipfamily, proplists:get_value(ipfamily, Config0)},
@@ -155,7 +160,7 @@ init_per_testcase(Case, Config0) ->
[{cert_dir, CertDir} | Config];
false ->
end_per_testcase(Case, Config0),
- ssl:start(),
+ ssl_test_lib:clean_start(),
Config0
end.
@@ -187,7 +192,7 @@ crl_verify_valid(Config) when is_list(Config) ->
{crl_cache, {ssl_crl_cache, {internal, [{http, 5000}]}}},
{verify, verify_peer}];
false ->
- ?config(crl_cache_opts, Config) ++
+ proplists:get_value(crl_cache_opts, Config) ++
[{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])},
{crl_check, Check},
{verify, verify_peer}]
@@ -220,7 +225,7 @@ crl_verify_revoked(Config) when is_list(Config) ->
{crl_check, Check},
{verify, verify_peer}];
false ->
- ?config(crl_cache_opts, Config) ++
+ proplists:get_value(crl_cache_opts, Config) ++
[{cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])},
{crl_check, Check},
{verify, verify_peer}]
@@ -279,8 +284,8 @@ crl_verify_no_crl(Config) when is_list(Config) ->
crl_hash_dir_collision() ->
[{doc,"Verify ssl_crl_hash_dir behaviour with hash collisions"}].
crl_hash_dir_collision(Config) when is_list(Config) ->
- PrivDir = ?config(cert_dir, Config),
- Check = ?config(crl_check, Config),
+ PrivDir = proplists:get_value(cert_dir, Config),
+ Check = proplists:get_value(crl_check, Config),
%% Create two CAs whose names hash to the same value
CA1 = "hash-collision-0000000000",
@@ -307,13 +312,17 @@ crl_hash_dir_collision(Config) when is_list(Config) ->
{CA2, "b68fc624"}],
replace),
- ClientOpts = ?config(crl_cache_opts, Config) ++
- [{cacertfile, filename:join([PrivDir, "erlangCA", "cacerts.pem"])},
+ NewCA = new_ca(filename:join([PrivDir, "new_ca"]),
+ filename:join([PrivDir, "erlangCA", "cacerts.pem"]),
+ filename:join([PrivDir, "server", "cacerts.pem"])),
+
+ ClientOpts = proplists:get_value(crl_cache_opts, Config) ++
+ [{cacertfile, NewCA},
{crl_check, Check},
{verify, verify_peer}],
-
+
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
%% Neither certificate revoked; both succeed.
crl_verify_valid(Hostname, ServerNode, ServerOpts1, ClientNode, ClientOpts),
crl_verify_valid(Hostname, ServerNode, ServerOpts2, ClientNode, ClientOpts),
@@ -346,8 +355,8 @@ crl_hash_dir_collision(Config) when is_list(Config) ->
crl_hash_dir_expired() ->
[{doc,"Verify ssl_crl_hash_dir behaviour with expired CRLs"}].
crl_hash_dir_expired(Config) when is_list(Config) ->
- PrivDir = ?config(cert_dir, Config),
- Check = ?config(crl_check, Config),
+ PrivDir = proplists:get_value(cert_dir, Config),
+ Check = proplists:get_value(crl_check, Config),
CA = "CRL-maybe-expired-CA",
%% Add "issuing distribution point", to ensure that verification
@@ -362,7 +371,7 @@ crl_hash_dir_expired(Config) when is_list(Config) ->
ServerOpts = [{keyfile, filename:join([PrivDir, EndUser, "key.pem"])},
{certfile, filename:join([PrivDir, EndUser, "cert.pem"])},
{cacertfile, filename:join([PrivDir, EndUser, "cacerts.pem"])}],
- ClientOpts = ?config(crl_cache_opts, Config) ++
+ ClientOpts = proplists:get_value(crl_cache_opts, Config) ++
[{cacertfile, filename:join([PrivDir, CA, "cacerts.pem"])},
{crl_check, Check},
{verify, verify_peer}],
@@ -492,3 +501,12 @@ find_free_name(CrlDir, Hash, N) ->
false ->
Name
end.
+
+new_ca(FileName, CA1, CA2) ->
+ {ok, P1} = file:read_file(CA1),
+ E1 = public_key:pem_decode(P1),
+ {ok, P2} = file:read_file(CA2),
+ E2 = public_key:pem_decode(P2),
+ Pem = public_key:pem_encode(E1 ++E2),
+ file:write_file(FileName, Pem),
+ FileName.
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 5ebf9bb2de..8740e8c8f0 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -109,11 +109,11 @@ common_end(_, _Config) ->
basic() ->
[{doc,"Test that two nodes can connect via ssl distribution"}].
basic(Config) when is_list(Config) ->
- NH1 = start_ssl_node(Config),
+ gen_dist_test(basic_test, Config).
+
+basic_test(NH1, NH2, _) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node(Config),
Node2 = NH2#node_handle.nodename,
-
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
@@ -161,18 +161,16 @@ basic(Config) when is_list(Config) ->
ok
end
end)
- end,
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
+ end.
%%--------------------------------------------------------------------
payload() ->
[{doc,"Test that send a lot of data between the ssl distributed noes"}].
payload(Config) when is_list(Config) ->
- NH1 = start_ssl_node(Config),
+ gen_dist_test(payload_test, Config).
+
+payload_test(NH1, NH2, _) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node(Config),
Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
@@ -204,10 +202,8 @@ payload(Config) when is_list(Config) ->
ok
end
end)
- end,
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
+ end.
+
%%--------------------------------------------------------------------
plain_options() ->
[{doc,"Test specifying additional options"}].
@@ -218,20 +214,17 @@ plain_options(Config) when is_list(Config) ->
"client_verify verify_none server_verify verify_none "
"server_depth 1 client_depth 1 "
"server_hibernate_after 500 client_hibernate_after 500",
+ gen_dist_test(plain_options_test, [{additional_dist_opts, DistOpts} | Config]).
- NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+plain_options_test(NH1, NH2, _) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end).
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
%%--------------------------------------------------------------------
plain_verify_options() ->
[{doc,"Test specifying additional options"}].
@@ -240,20 +233,18 @@ plain_verify_options(Config) when is_list(Config) ->
"client_secure_renegotiate true "
"server_reuse_sessions true client_reuse_sessions true "
"server_hibernate_after 500 client_hibernate_after 500",
+ gen_dist_test(plain_verify_options_test, [{additional_dist_opts, DistOpts} | Config]).
- NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+plain_verify_options_test(NH1, NH2, _) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
Node2 = NH2#node_handle.nodename,
-
+
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
-
+
[Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end).
+
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
%%--------------------------------------------------------------------
nodelay_option() ->
[{doc,"Test specifying dist_nodelay option"}].
@@ -265,6 +256,7 @@ nodelay_option(Config) ->
after
application:unset_env(kernel, dist_nodelay)
end.
+%%--------------------------------------------------------------------
listen_port_options() ->
[{doc, "Test specifying listening ports"}].
@@ -285,32 +277,39 @@ listen_port_options(Config) when is_list(Config) ->
#node_handle{} ->
%% If the node was able to start, it didn't take the port
%% option into account.
+ stop_ssl_node(NH1),
exit(unexpected_success)
catch
exit:{accept_failed, timeout} ->
%% The node failed to start, as expected.
ok
end,
-
+
%% Try again, now specifying a high max port.
PortOpt2 = "-kernel inet_dist_listen_min " ++ integer_to_list(Port1) ++
- " inet_dist_listen_max 65535",
+ " inet_dist_listen_max 65535",
NH2 = start_ssl_node([{additional_dist_opts, PortOpt2} | Config]),
- Node2 = NH2#node_handle.nodename,
- Name2 = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node2)),
- {ok, NodesPorts2} = apply_on_ssl_node(NH2, fun net_adm:names/0),
- {Name2, Port2} = lists:keyfind(Name2, 1, NodesPorts2),
-
- %% The new port should be higher:
- if Port2 > Port1 ->
- ok;
- true ->
- error({port, Port2, not_higher_than, Port1})
+
+ try
+ Node2 = NH2#node_handle.nodename,
+ Name2 = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node2)),
+ {ok, NodesPorts2} = apply_on_ssl_node(NH2, fun net_adm:names/0),
+ {Name2, Port2} = lists:keyfind(Name2, 1, NodesPorts2),
+
+ %% The new port should be higher:
+ if Port2 > Port1 ->
+ ok;
+ true ->
+ error({port, Port2, not_higher_than, Port1})
+ end
+ catch
+ _:Reason ->
+ stop_ssl_node(NH2),
+ ct:fail(Reason)
end,
-
- stop_ssl_node(NH1),
stop_ssl_node(NH2),
success(Config).
+
%%--------------------------------------------------------------------
listen_options() ->
[{doc, "Test inet_dist_listen_options"}].
@@ -329,28 +328,25 @@ do_listen_options(Prio, Config) ->
end,
Options = "-kernel inet_dist_listen_options " ++ PriorityString,
-
- NH1 = start_ssl_node([{additional_dist_opts, Options} | Config]),
- NH2 = start_ssl_node([{additional_dist_opts, Options} | Config]),
- Node2 = NH2#node_handle.nodename,
-
+ gen_dist_test(listen_options_test, [{prio, Prio}, {additional_dist_opts, Options} | Config]).
+
+listen_options_test(NH1, NH2, Config) ->
+ Prio = proplists:get_value(prio, Config),
+ Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
PrioritiesNode1 =
apply_on_ssl_node(NH1, fun get_socket_priorities/0),
PrioritiesNode2 =
apply_on_ssl_node(NH2, fun get_socket_priorities/0),
-
+
Elevated1 = [P || P <- PrioritiesNode1, P =:= Prio],
- ?t:format("Elevated1: ~p~n", [Elevated1]),
+ ct:pal("Elevated1: ~p~n", [Elevated1]),
Elevated2 = [P || P <- PrioritiesNode2, P =:= Prio],
- ?t:format("Elevated2: ~p~n", [Elevated2]),
+ ct:pal("Elevated2: ~p~n", [Elevated2]),
[_|_] = Elevated1,
- [_|_] = Elevated2,
+ [_|_] = Elevated2.
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
%%--------------------------------------------------------------------
connect_options() ->
[{doc, "Test inet_dist_connect_options"}].
@@ -369,9 +365,11 @@ do_connect_options(Prio, Config) ->
end,
Options = "-kernel inet_dist_connect_options " ++ PriorityString,
+ gen_dist_test(connect_options_test,
+ [{prio, Prio}, {additional_dist_opts, Options} | Config]).
- NH1 = start_ssl_node([{additional_dist_opts, Options} | Config]),
- NH2 = start_ssl_node([{additional_dist_opts, Options} | Config]),
+connect_options_test(NH1, NH2, Config) ->
+ Prio = proplists:get_value(prio, Config),
Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
@@ -382,17 +380,14 @@ do_connect_options(Prio, Config) ->
apply_on_ssl_node(NH2, fun get_socket_priorities/0),
Elevated1 = [P || P <- PrioritiesNode1, P =:= Prio],
- ?t:format("Elevated1: ~p~n", [Elevated1]),
+ ct:pal("Elevated1: ~p~n", [Elevated1]),
Elevated2 = [P || P <- PrioritiesNode2, P =:= Prio],
- ?t:format("Elevated2: ~p~n", [Elevated2]),
+ ct:pal("Elevated2: ~p~n", [Elevated2]),
%% Node 1 will have a socket with elevated priority.
[_|_] = Elevated1,
%% Node 2 will not, since it only applies to outbound connections.
- [] = Elevated2,
+ [] = Elevated2.
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
%%--------------------------------------------------------------------
use_interface() ->
[{doc, "Test inet_dist_use_interface"}].
@@ -403,22 +398,28 @@ use_interface(Config) when is_list(Config) ->
%% Start a node, and get the port number it's listening on.
NH1 = start_ssl_node([{additional_dist_opts, Options} | Config]),
- Node1 = NH1#node_handle.nodename,
- Name = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node1)),
- {ok, NodesPorts} = apply_on_ssl_node(NH1, fun net_adm:names/0),
- {Name, Port} = lists:keyfind(Name, 1, NodesPorts),
-
- %% Now find the socket listening on that port, and check its sockname.
- Sockets = apply_on_ssl_node(
- NH1,
- fun() ->
- [inet:sockname(P) ||
- P <- inet_ports(),
- {ok, Port} =:= (catch inet:port(P))]
- end),
- %% And check that it's actually listening on localhost.
- [{ok,{{127,0,0,1},Port}}] = Sockets,
-
+
+ try
+ Node1 = NH1#node_handle.nodename,
+ Name = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node1)),
+ {ok, NodesPorts} = apply_on_ssl_node(NH1, fun net_adm:names/0),
+ {Name, Port} = lists:keyfind(Name, 1, NodesPorts),
+
+ %% Now find the socket listening on that port, and check its sockname.
+ Sockets = apply_on_ssl_node(
+ NH1,
+ fun() ->
+ [inet:sockname(P) ||
+ P <- inet_ports(),
+ {ok, Port} =:= (catch inet:port(P))]
+ end),
+ %% And check that it's actually listening on localhost.
+ [{ok,{{127,0,0,1},Port}}] = Sockets
+ catch
+ _:Reason ->
+ stop_ssl_node(NH1),
+ ct:fail(Reason)
+ end,
stop_ssl_node(NH1),
success(Config).
%%--------------------------------------------------------------------
@@ -430,11 +431,11 @@ verify_fun_fail(Config) when is_list(Config) ->
"\"{ssl_dist_SUITE,verify_fail_always,{}}\" "
"client_verify verify_peer client_verify_fun "
"\"{ssl_dist_SUITE,verify_fail_always,{}}\" ",
+ gen_dist_test(verify_fun_fail_test, [{additional_dist_opts, DistOpts} | Config]).
- NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
- NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+verify_fun_fail_test(NH1, NH2, _) ->
Node2 = NH2#node_handle.nodename,
-
+
pang = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[] = apply_on_ssl_node(NH1, fun () -> nodes() end),
@@ -446,25 +447,9 @@ verify_fun_fail(Config) when is_list(Config) ->
%% On the server node, it wouldn't run, because the server didn't
%% request a certificate from the client.
undefined =
- apply_on_ssl_node(NH2, fun () -> ets:info(verify_fun_ran) end),
+ apply_on_ssl_node(NH2, fun () -> ets:info(verify_fun_ran) end).
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
-verify_fail_always(_Certificate, _Event, _State) ->
- %% Create an ETS table, to record the fact that the verify function ran.
- %% Spawn a new process, to avoid the ETS table disappearing.
- Parent = self(),
- spawn(
- fun() ->
- ets:new(verify_fun_ran, [public, named_table]),
- ets:insert(verify_fun_ran, {verify_fail_always_ran, true}),
- Parent ! go_ahead,
- timer:sleep(infinity)
- end),
- receive go_ahead -> ok end,
- {fail, bad_certificate}.
%%--------------------------------------------------------------------
verify_fun_pass() ->
@@ -476,10 +461,10 @@ verify_fun_pass(Config) when is_list(Config) ->
"server_fail_if_no_peer_cert true "
"client_verify verify_peer client_verify_fun "
"\"{ssl_dist_SUITE,verify_pass_always,{}}\" ",
+ gen_dist_test(verify_fun_pass_test, [{additional_dist_opts, DistOpts} | Config]).
- NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+verify_fun_pass_test(NH1, NH2, _) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
@@ -494,25 +479,8 @@ verify_fun_pass(Config) when is_list(Config) ->
%% requested and verified the client's certificate because we
%% passed fail_if_no_peer_cert.
[{verify_pass_always_ran, true}] =
- apply_on_ssl_node(NH2, fun () -> ets:tab2list(verify_fun_ran) end),
+ apply_on_ssl_node(NH2, fun () -> ets:tab2list(verify_fun_ran) end).
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
-
-verify_pass_always(_Certificate, _Event, State) ->
- %% Create an ETS table, to record the fact that the verify function ran.
- %% Spawn a new process, to avoid the ETS table disappearing.
- Parent = self(),
- spawn(
- fun() ->
- ets:new(verify_fun_ran, [public, named_table]),
- ets:insert(verify_fun_ran, {verify_pass_always_ran, true}),
- Parent ! go_ahead,
- timer:sleep(infinity)
- end),
- receive go_ahead -> ok end,
- {valid, State}.
%%--------------------------------------------------------------------
crl_check_pass() ->
[{doc,"Test crl_check with non-revoked certificate"}].
@@ -520,10 +488,10 @@ crl_check_pass(Config) when is_list(Config) ->
DistOpts = "-ssl_dist_opt client_crl_check true",
NewConfig =
[{many_verify_opts, true}, {additional_dist_opts, DistOpts}] ++ Config,
+ gen_dist_test(crl_check_pass_test, NewConfig).
- NH1 = start_ssl_node(NewConfig),
+crl_check_pass_test(NH1, NH2, Config) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node(NewConfig),
Node2 = NH2#node_handle.nodename,
PrivDir = ?config(priv_dir, Config),
@@ -533,11 +501,7 @@ crl_check_pass(Config) when is_list(Config) ->
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
-
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end).
%%--------------------------------------------------------------------
crl_check_fail() ->
@@ -549,10 +513,9 @@ crl_check_fail(Config) when is_list(Config) ->
%% The server uses a revoked certificate.
{server_cert_dir, "revoked"},
{additional_dist_opts, DistOpts}] ++ Config,
+ gen_dist_test(crl_check_fail_test, NewConfig).
- NH1 = start_ssl_node(NewConfig),
- %%Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node(NewConfig),
+crl_check_fail_test(NH1, NH2, Config) ->
Node2 = NH2#node_handle.nodename,
PrivDir = ?config(priv_dir, Config),
@@ -562,11 +525,7 @@ crl_check_fail(Config) when is_list(Config) ->
pang = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [] = apply_on_ssl_node(NH2, fun () -> nodes() end),
-
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
+ [] = apply_on_ssl_node(NH2, fun () -> nodes() end).
%%--------------------------------------------------------------------
crl_check_best_effort() ->
@@ -576,22 +535,18 @@ crl_check_best_effort(Config) when is_list(Config) ->
"server_verify verify_peer server_crl_check best_effort",
NewConfig =
[{many_verify_opts, true}, {additional_dist_opts, DistOpts}] ++ Config,
+ gen_dist_test(crl_check_best_effort_test, NewConfig).
+crl_check_best_effort_test(NH1, NH2, _Config) ->
%% We don't have the correct CRL at hand, but since crl_check is
%% best_effort, we accept it anyway.
- NH1 = start_ssl_node(NewConfig),
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node(NewConfig),
Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
-
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end).
%%--------------------------------------------------------------------
crl_cache_check_pass() ->
@@ -605,20 +560,16 @@ crl_cache_check_pass(Config) when is_list(Config) ->
"\"{ssl_dist_SUITE,{\\\"" ++ NodeDir ++ "\\\",[]}}\"",
NewConfig =
[{many_verify_opts, true}, {additional_dist_opts, DistOpts}] ++ Config,
+ gen_dist_test(crl_cache_check_pass_test, NewConfig).
- NH1 = start_ssl_node(NewConfig),
+crl_cache_check_pass_test(NH1, NH2, _) ->
Node1 = NH1#node_handle.nodename,
- NH2 = start_ssl_node(NewConfig),
Node2 = NH2#node_handle.nodename,
pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
-
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end).
%%--------------------------------------------------------------------
crl_cache_check_fail() ->
@@ -636,44 +587,31 @@ crl_cache_check_fail(Config) when is_list(Config) ->
{server_cert_dir, "revoked"},
{additional_dist_opts, DistOpts}] ++ Config,
- NH1 = start_ssl_node(NewConfig),
- NH2 = start_ssl_node(NewConfig),
- Node2 = NH2#node_handle.nodename,
+ gen_dist_test(crl_cache_check_fail_test, NewConfig).
+crl_cache_check_fail_test(NH1, NH2, _) ->
+ Node2 = NH2#node_handle.nodename,
pang = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
[] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- [] = apply_on_ssl_node(NH2, fun () -> nodes() end),
-
- stop_ssl_node(NH1),
- stop_ssl_node(NH2),
- success(Config).
-
-%% ssl_crl_cache_api callbacks
-lookup(_DistributionPoint, _DbHandle) ->
- not_available.
-
-select({rdnSequence, NameParts}, {NodeDir, _}) ->
- %% Extract the CN from the issuer name...
- [CN] = [CN ||
- [#'AttributeTypeAndValue'{
- type = ?'id-at-commonName',
- value = <<_, _, CN/binary>>}] <- NameParts],
- %% ...and use that as the directory name to find the CRL.
- error_logger:info_report([{found_cn, CN}]),
- CRLFile = filename:join([NodeDir, CN, "crl.pem"]),
- {ok, PemBin} = file:read_file(CRLFile),
- PemEntries = public_key:pem_decode(PemBin),
- CRLs = [ CRL || {'CertificateList', CRL, not_encrypted}
- <- PemEntries],
- CRLs.
-
-fresh_crl(_DistributionPoint, CRL) ->
- CRL.
-
+ [] = apply_on_ssl_node(NH2, fun () -> nodes() end).
%%--------------------------------------------------------------------
%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
+gen_dist_test(Test, Config) ->
+ NH1 = start_ssl_node(Config),
+ NH2 = start_ssl_node(Config),
+ try
+ ?MODULE:Test(NH1, NH2, Config)
+ catch
+ _:Reason ->
+ stop_ssl_node(NH1),
+ stop_ssl_node(NH2),
+ ct:fail(Reason)
+ end,
+ stop_ssl_node(NH1),
+ stop_ssl_node(NH2),
+ success(Config).
%% ssl_node side api
%%
@@ -742,13 +680,15 @@ stop_ssl_node(#node_handle{connection_handler = Handler,
receive
{'DOWN', Mon, process, Handler, Reason} ->
case Reason of
- normal -> ok;
- _ -> exit(Reason)
+ normal ->
+ ok;
+ _ ->
+ ct:pal("Down ~p ~n", [Reason])
end
end;
Error ->
erlang:demonitor(Mon, [flush]),
- exit(Error)
+ ct:pal("Warning ~p ~n", [Error])
end.
start_ssl_node(Config) ->
@@ -1226,3 +1166,53 @@ vsn(App) ->
after
application:stop(ssl)
end.
+
+verify_fail_always(_Certificate, _Event, _State) ->
+ %% Create an ETS table, to record the fact that the verify function ran.
+ %% Spawn a new process, to avoid the ETS table disappearing.
+ Parent = self(),
+ spawn(
+ fun() ->
+ ets:new(verify_fun_ran, [public, named_table]),
+ ets:insert(verify_fun_ran, {verify_fail_always_ran, true}),
+ Parent ! go_ahead,
+ timer:sleep(infinity)
+ end),
+ receive go_ahead -> ok end,
+ {fail, bad_certificate}.
+
+verify_pass_always(_Certificate, _Event, State) ->
+ %% Create an ETS table, to record the fact that the verify function ran.
+ %% Spawn a new process, to avoid the ETS table disappearing.
+ Parent = self(),
+ spawn(
+ fun() ->
+ ets:new(verify_fun_ran, [public, named_table]),
+ ets:insert(verify_fun_ran, {verify_pass_always_ran, true}),
+ Parent ! go_ahead,
+ timer:sleep(infinity)
+ end),
+ receive go_ahead -> ok end,
+ {valid, State}.
+
+%% ssl_crl_cache_api callbacks
+lookup(_DistributionPoint, _DbHandle) ->
+ not_available.
+
+select({rdnSequence, NameParts}, {NodeDir, _}) ->
+ %% Extract the CN from the issuer name...
+ [CN] = [CN ||
+ [#'AttributeTypeAndValue'{
+ type = ?'id-at-commonName',
+ value = <<_, _, CN/binary>>}] <- NameParts],
+ %% ...and use that as the directory name to find the CRL.
+ error_logger:info_report([{found_cn, CN}]),
+ CRLFile = filename:join([NodeDir, CN, "crl.pem"]),
+ {ok, PemBin} = file:read_file(CRLFile),
+ PemEntries = public_key:pem_decode(PemBin),
+ CRLs = [ CRL || {'CertificateList', CRL, not_encrypted}
+ <- PemEntries],
+ CRLs.
+
+fresh_crl(_DistributionPoint, CRL) ->
+ CRL.
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index a671e3e307..9658cb5f56 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() -> [decode_hello_handshake,
+ decode_hello_handshake_version_confusion,
decode_single_hello_extension_correctly,
decode_supported_elliptic_curves_hello_extension_correctly,
decode_unknown_hello_extension_correctly,
@@ -60,7 +61,7 @@ init_per_testcase(ignore_hassign_extension_pre_tls_1_2, Config0) ->
ok ->
case is_supported(sha512) of
true ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
%% make rsa certs using oppenssl
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
@@ -106,6 +107,14 @@ decode_hello_handshake(_Config) ->
#renegotiation_info{renegotiated_connection = <<0>>}
= (Hello#server_hello.extensions)#hello_extensions.renegotiation_info.
+
+decode_hello_handshake_version_confusion(_) ->
+ HelloPacket = <<3,3,0,0,0,0,0,63,210,235,149,6,244,140,108,13,177,74,16,218,33,108,219,41,73,228,3,82,132,123,73,144,118,100,0,0,32,192,4,0,10,192,45,192,38,0,47,192,18,0,163,0,22,0,165,192,29,192,18,192,30,0,103,0,57,192,48,0,47,1,0>>,
+ Version = {3,3},
+ ClientHello = 1,
+ Hello = tls_handshake:decode_handshake({3,3}, ClientHello, HelloPacket, false),
+ Hello = tls_handshake:decode_handshake({3,3}, ClientHello, HelloPacket, true).
+
decode_single_hello_extension_correctly(_Config) ->
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
Extensions = ssl_handshake:decode_hello_extensions(Renegotiation),
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index c55fa73cfb..a02881f1ae 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -68,7 +68,7 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
proplists:get_value(priv_dir, Config)),
ssl_test_lib:cert_options(Config)
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 00eb9fee4f..35af666e9e 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,6 +41,19 @@ all() ->
create_server_hello_with_advertised_protocols_test,
create_server_hello_with_no_advertised_protocols_test].
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ %% This function is required since init_per_suite/1 exists.
+ ok.
+
init_per_testcase(_TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 5}),
@@ -126,15 +139,12 @@ create_server_handshake(Npn) ->
}, Vsn).
create_connection_states() ->
- #connection_states{
- pending_read = #connection_state{
- security_parameters = #security_parameters{
+ #{pending_read => #{security_parameters => #security_parameters{
server_random = <<1:256>>,
compression_algorithm = 1,
cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA
}
- },
- current_read = #connection_state {
- secure_renegotiation = false
- }
- }.
+ },
+ current_read => #{secure_renegotiation => false
+ }
+ }.
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index e49d432c21..3446a566c4 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -41,9 +41,9 @@
-define(MANY, 1000).
-define(SOME, 50).
--define(BASE_TIMEOUT_SECONDS, 15).
--define(SOME_SCALE, 20).
--define(MANY_SCALE, 20).
+-define(BASE_TIMEOUT_SECONDS, 5).
+-define(SOME_SCALE, 2).
+-define(MANY_SCALE, 3).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -140,7 +140,7 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
proplists:get_value(priv_dir, Config)),
ssl_test_lib:cert_options(Config)
@@ -162,6 +162,7 @@ init_per_group(GroupName, Config) ->
{skip, "Missing crypto support"}
end;
_ ->
+ ssl:stop(),
ssl:start(),
Config
end.
@@ -276,6 +277,7 @@ packet_raw_active_once_many_small() ->
[{doc,"Test packet option {packet, raw} in active once mode."}].
packet_raw_active_once_many_small(Config) when is_list(Config) ->
+ ct:timetrap({seconds, ?BASE_TIMEOUT_SECONDS * ?MANY_SCALE}),
Data = "Packet option is {packet, raw}",
packet(Config, Data, send_raw, active_once_raw, ?MANY, raw, once).
@@ -392,6 +394,7 @@ packet_0_active_some_big() ->
[{doc,"Test packet option {packet, 0} in active mode."}].
packet_0_active_some_big(Config) when is_list(Config) ->
+ ct:timetrap({seconds, ?BASE_TIMEOUT_SECONDS * ?SOME_SCALE}),
Data = lists:append(lists:duplicate(100, "1234567890")),
packet(Config, Data, send, active_raw, ?SOME, 0, true).
@@ -427,6 +430,7 @@ packet_2_active_some_big() ->
[{doc,"Test packet option {packet, 2} in active mode"}].
packet_2_active_some_big(Config) when is_list(Config) ->
+ ct:timetrap({seconds, ?BASE_TIMEOUT_SECONDS * ?SOME_SCALE}),
Data = lists:append(lists:duplicate(100, "1234567890")),
packet(Config, Data, send, active_packet, ?SOME, 2, true).
@@ -1900,6 +1904,31 @@ header_decode_two_bytes_one_sent_passive(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
+
+packet(Config, Data, Send, Recv, Quantity, Packet, Active) when Packet == 0;
+ Packet == raw ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, Send ,[Data, Quantity]}},
+ {options, [{nodelay, true},{packet, Packet} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, Recv, [Data, Quantity]}},
+ {options, [{active, Active}, {nodelay, true},
+ {packet, Packet} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client);
+
packet(Config, Data, Send, Recv, Quantity, Packet, Active) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
@@ -1982,26 +2011,19 @@ active_once_raw(Socket, Data, N) ->
active_once_raw(_, _, 0, _) ->
ok;
-active_once_raw(Socket, Data, N, Acc) ->
- receive
- {ssl, Socket, Byte} when length(Byte) == 1 ->
- ssl:setopts(Socket, [{active, once}]),
+active_once_raw(Socket, Data, N, Acc0) ->
+ case lists:prefix(Data, Acc0) of
+ true ->
+ DLen = length(Data),
+ Start = DLen + 1,
+ Len = length(Acc0) - DLen,
+ Acc = string:substr(Acc0, Start, Len),
+ active_once_raw(Socket, Data, N-1, Acc);
+ false ->
receive
- {ssl, Socket, _} ->
- ssl:setopts(Socket, [{active, once}]),
- active_once_raw(Socket, Data, N-1, [])
- end;
- {ssl, Socket, Data} ->
- ssl:setopts(Socket, [{active, once}]),
- active_once_raw(Socket, Data, N-1, []);
- {ssl, Socket, Other} ->
- case Acc ++ Other of
- Data ->
- ssl:setopts(Socket, [{active, once}]),
- active_once_raw(Socket, Data, N-1, []);
- NewAcc ->
+ {ssl, Socket, Info} ->
ssl:setopts(Socket, [{active, once}]),
- active_once_raw(Socket, Data, N, NewAcc)
+ active_once_raw(Socket, Data, N, Acc0 ++ Info)
end
end.
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index cb0571d0a7..cb1957327a 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -70,7 +70,7 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config), proplists:get_value(priv_dir, Config)),
ssl_test_lib:cert_options(Config)
catch _:_ ->
@@ -104,8 +104,13 @@ init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_huge;
TestCase == client_echos_passive_huge;
TestCase == client_echos_active_once_huge;
TestCase == client_echos_active_huge ->
- ct:timetrap({seconds, 90}),
- Config;
+ case erlang:system_info(system_architecture) of
+ "sparc-sun-solaris2.10" ->
+ {skip,"Will take to long time on an old Sparc"};
+ _ ->
+ ct:timetrap({seconds, 90}),
+ Config
+ end;
init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_big;
TestCase == server_echos_active_once_big;
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 13b0ce8ed9..96b15d9b51 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
%% make rsa certs using oppenssl
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
@@ -63,14 +63,15 @@ end_per_group(_GroupName, Config) ->
Config.
init_per_testcase(pem_cleanup = Case, Config) ->
- end_per_testcase(Case, Config) ,
application:load(ssl),
+ end_per_testcase(Case, Config) ,
application:set_env(ssl, ssl_pem_cache_clean, ?CLEANUP_INTERVAL),
ssl:start(),
ct:timetrap({minutes, 1}),
Config.
end_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:clean_env(),
ssl:stop(),
Config.
@@ -81,8 +82,8 @@ pem_cleanup() ->
[{doc, "Test pem cache invalidate mechanism"}].
pem_cleanup(Config)when is_list(Config) ->
process_flag(trap_exit, true),
- ClientOpts = proplists:get_value(client_opts, Config),
- ServerOpts = proplists:get_value(server_opts, Config),
+ ClientOpts = proplists:get_value(client_verification_opts, Config),
+ ServerOpts = proplists:get_value(server_verification_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index b352844ba0..9862b3ce64 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
%% make rsa certs using
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 34ef2e6af9..4e916a7f03 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -41,7 +41,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
ssl_test_lib:cert_options(Config0)
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 27c670cdc2..56b8a8a22d 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -278,8 +278,11 @@ check_result(Server, ServerMsg, Client, ClientMsg) ->
check_result(Server, ServerMsg);
{Port, {data,Debug}} when is_port(Port) ->
- ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
+ ct:log("~p:~p~n Openssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Server, ServerMsg, Client, ClientMsg);
+ {Port,closed} when is_port(Port) ->
+ ct:log("~p:~p~n Openssl port ~n",[?MODULE,?LINE]),
+ check_result(Server, ServerMsg, Client, ClientMsg);
Unexpected ->
Reason = {{expected, {Client, ClientMsg}},
{expected, {Server, ServerMsg}}, {got, Unexpected}},
@@ -291,11 +294,11 @@ check_result(Pid, Msg) ->
{Pid, Msg} ->
ok;
{Port, {data,Debug}} when is_port(Port) ->
- ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
+ ct:log("~p:~p~n Openssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Pid,Msg);
- %% {Port, {exit_status, Status}} when is_port(Port) ->
- %% ct:log("~p:~p Exit status: ~p~n",[?MODULE,?LINE, Status]),
- %% check_result(Pid, Msg);
+ {Port,closed} when is_port(Port)->
+ ct:log("~p:~p Openssl port closed ~n",[?MODULE,?LINE]),
+ check_result(Pid, Msg);
Unexpected ->
Reason = {{expected, {Pid, Msg}},
{got, Unexpected}},
@@ -385,7 +388,9 @@ cert_options(Config) ->
SNIServerAKeyFile = filename:join([proplists:get_value(priv_dir, Config), "a.server", "key.pem"]),
SNIServerBCertFile = filename:join([proplists:get_value(priv_dir, Config), "b.server", "cert.pem"]),
SNIServerBKeyFile = filename:join([proplists:get_value(priv_dir, Config), "b.server", "key.pem"]),
- [{client_opts, []},
+ [{client_opts, [{cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile},
+ {keyfile, ClientKeyFile}]},
{client_verification_opts, [{cacertfile, ServerCaCertFile},
{certfile, ClientCertFile},
{keyfile, ClientKeyFile},
@@ -394,29 +399,24 @@ cert_options(Config) ->
{certfile, ClientCertFileDigitalSignatureOnly},
{keyfile, ClientKeyFile},
{ssl_imp, new}]},
- {server_opts, [{ssl_imp, new},{reuseaddr, true},
+ {server_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
- {server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]},
- {client_psk, [{ssl_imp, new},{reuseaddr, true},
+ {client_psk, [{ssl_imp, new},
{psk_identity, "Test-User"},
{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
{server_psk, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
- {ciphers, psk_suites()}]},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
{server_psk_hint, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{psk_identity, "HINT"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
- {ciphers, psk_suites()}]},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
{server_psk_anon, [{ssl_imp, new},{reuseaddr, true},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
- {ciphers, psk_anon_suites()}]},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
{server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true},
{psk_identity, "HINT"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
- {ciphers, psk_anon_suites()}]},
- {client_srp, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
+ {client_srp, [{ssl_imp, new},
{srp_identity, {"Test-User", "secret"}}]},
{server_srp, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
@@ -460,9 +460,10 @@ cert_options(Config) ->
make_dsa_cert(Config) ->
-
- {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa, dsa, ""),
- {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, dsa, dsa, ""),
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} =
+ make_cert_files("server", Config, dsa, dsa, "", []),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} =
+ make_cert_files("client", Config, dsa, dsa, "", []),
[{server_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -470,7 +471,7 @@ make_dsa_cert(Config) ->
{cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{verify, verify_peer}]},
- {client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {client_dsa_opts, [{ssl_imp, new},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]},
{server_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
@@ -478,7 +479,7 @@ make_dsa_cert(Config) ->
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{user_lookup_fun, {fun user_lookup/3, undefined}},
{ciphers, srp_dss_suites()}]},
- {client_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {client_srp_dsa, [{ssl_imp, new},
{srp_identity, {"Test-User", "secret"}},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
@@ -488,16 +489,18 @@ make_ecdsa_cert(Config) ->
CryptoSupport = crypto:supports(),
case proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)) of
true ->
- {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""),
- {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""),
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} =
+ make_cert_files("server", Config, ec, ec, "", [{digest, appropriate_sha(CryptoSupport)}]),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} =
+ make_cert_files("client", Config, ec, ec, "", [{digest, appropriate_sha(CryptoSupport)}]),
[{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
- {cacertfile, ServerCaCertFile},
+ {cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{verify, verify_peer}]},
- {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {client_ecdsa_opts, [{ssl_imp, new},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config];
@@ -505,6 +508,14 @@ make_ecdsa_cert(Config) ->
Config
end.
+appropriate_sha(CryptoSupport) ->
+ case proplists:get_bool(sha256, CryptoSupport) of
+ true ->
+ sha256;
+ false ->
+ sha1
+ end.
+
%% RFC 4492, Sect. 2.3. ECDH_RSA
%%
%% This key exchange algorithm is the same as ECDH_ECDSA except that the
@@ -513,16 +524,18 @@ make_ecdh_rsa_cert(Config) ->
CryptoSupport = crypto:supports(),
case proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)) of
true ->
- {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"),
- {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"),
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} =
+ make_cert_files("server", Config, rsa, ec, "rsa_", []),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} =
+ make_cert_files("client", Config, rsa, ec, "rsa_",[]),
[{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
- {cacertfile, ServerCaCertFile},
+ {cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{verify, verify_peer}]},
- {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {client_ecdh_rsa_opts, [{ssl_imp, new},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config];
@@ -532,9 +545,9 @@ make_ecdh_rsa_cert(Config) ->
make_mix_cert(Config) ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa,
- rsa, "mix"),
+ rsa, "mix", []),
{ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, dsa,
- rsa, "mix"),
+ rsa, "mix", []),
[{server_mix_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -542,16 +555,16 @@ make_mix_cert(Config) ->
{cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{verify, verify_peer}]},
- {client_mix_opts, [{ssl_imp, new},{reuseaddr, true},
+ {client_mix_opts, [{ssl_imp, new},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
-make_cert_files(RoleStr, Config, Alg1, Alg2, Prefix) ->
+make_cert_files(RoleStr, Config, Alg1, Alg2, Prefix, Opts) ->
Alg1Str = atom_to_list(Alg1),
Alg2Str = atom_to_list(Alg2),
- CaInfo = {CaCert, _} = erl_make_certs:make_cert([{key, Alg1}]),
- {Cert, CertKey} = erl_make_certs:make_cert([{key, Alg2}, {issuer, CaInfo}]),
+ CaInfo = {CaCert, _} = erl_make_certs:make_cert([{key, Alg1}| Opts]),
+ {Cert, CertKey} = erl_make_certs:make_cert([{key, Alg2}, {issuer, CaInfo} | Opts]),
CaCertFile = filename:join([proplists:get_value(priv_dir, Config),
RoleStr, Prefix ++ Alg1Str ++ "_cacerts.pem"]),
CertFile = filename:join([proplists:get_value(priv_dir, Config),
@@ -805,16 +818,24 @@ send_selected_port(_,_,_) ->
rsa_suites(CounterPart) ->
ECC = is_sane_ecc(CounterPart),
FIPS = is_fips(CounterPart),
+ CryptoSupport = crypto:supports(),
+ Ciphers = proplists:get_value(ciphers, CryptoSupport),
lists:filter(fun({rsa, des_cbc, sha}) when FIPS == true ->
false;
({dhe_rsa, des_cbc, sha}) when FIPS == true ->
false;
- ({rsa, _, _}) ->
- true;
- ({dhe_rsa, _, _}) ->
- true;
- ({ecdhe_rsa, _, _}) when ECC == true ->
- true;
+ ({rsa, Cipher, _}) ->
+ lists:member(cipher_atom(Cipher), Ciphers);
+ ({dhe_rsa, Cipher, _}) ->
+ lists:member(cipher_atom(Cipher), Ciphers);
+ ({ecdhe_rsa, Cipher, _}) when ECC == true ->
+ lists:member(cipher_atom(Cipher), Ciphers);
+ ({rsa, Cipher, _, _}) ->
+ lists:member(cipher_atom(Cipher), Ciphers);
+ ({dhe_rsa, Cipher, _,_}) ->
+ lists:member(cipher_atom(Cipher), Ciphers);
+ ({ecdhe_rsa, Cipher, _,_}) when ECC == true ->
+ lists:member(cipher_atom(Cipher), Ciphers);
(_) ->
false
end,
@@ -830,37 +851,42 @@ common_ciphers(openssl) ->
lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites)
].
-rsa_non_signed_suites() ->
+available_suites(Version) ->
+ [ssl_cipher:erl_suite_definition(Suite) ||
+ Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))].
+
+
+rsa_non_signed_suites(Version) ->
lists:filter(fun({rsa, _, _}) ->
true;
(_) ->
false
end,
- ssl:cipher_suites()).
+ available_suites(Version)).
-dsa_suites() ->
+dsa_suites(Version) ->
lists:filter(fun({dhe_dss, _, _}) ->
true;
(_) ->
false
end,
- ssl:cipher_suites()).
+ available_suites(Version)).
-ecdsa_suites() ->
+ecdsa_suites(Version) ->
lists:filter(fun({ecdhe_ecdsa, _, _}) ->
true;
(_) ->
false
end,
- ssl:cipher_suites()).
+ available_suites(Version)).
-ecdh_rsa_suites() ->
+ecdh_rsa_suites(Version) ->
lists:filter(fun({ecdh_rsa, _, _}) ->
true;
(_) ->
false
end,
- ssl:cipher_suites()).
+ available_suites(Version)).
openssl_rsa_suites(CounterPart) ->
Ciphers = ssl:cipher_suites(openssl),
@@ -898,59 +924,16 @@ string_regex_filter(Str, Search) when is_list(Str) ->
string_regex_filter(_Str, _Search) ->
false.
-anonymous_suites() ->
- Suites =
- [{dh_anon, rc4_128, md5},
- {dh_anon, des_cbc, sha},
- {dh_anon, '3des_ede_cbc', sha},
- {dh_anon, aes_128_cbc, sha},
- {dh_anon, aes_256_cbc, sha},
- {dh_anon, aes_128_gcm, null, sha256},
- {dh_anon, aes_256_gcm, null, sha384},
- {ecdh_anon,rc4_128,sha},
- {ecdh_anon,'3des_ede_cbc',sha},
- {ecdh_anon,aes_128_cbc,sha},
- {ecdh_anon,aes_256_cbc,sha}],
+anonymous_suites(Version) ->
+ Suites = ssl_cipher:anonymous_suites(Version),
ssl_cipher:filter_suites(Suites).
-psk_suites() ->
- Suites =
- [{psk, rc4_128, sha},
- {psk, '3des_ede_cbc', sha},
- {psk, aes_128_cbc, sha},
- {psk, aes_256_cbc, sha},
- {psk, aes_128_cbc, sha256},
- {psk, aes_256_cbc, sha384},
- {dhe_psk, rc4_128, sha},
- {dhe_psk, '3des_ede_cbc', sha},
- {dhe_psk, aes_128_cbc, sha},
- {dhe_psk, aes_256_cbc, sha},
- {dhe_psk, aes_128_cbc, sha256},
- {dhe_psk, aes_256_cbc, sha384},
- {rsa_psk, rc4_128, sha},
- {rsa_psk, '3des_ede_cbc', sha},
- {rsa_psk, aes_128_cbc, sha},
- {rsa_psk, aes_256_cbc, sha},
- {rsa_psk, aes_128_cbc, sha256},
- {rsa_psk, aes_256_cbc, sha384},
- {psk, aes_128_gcm, null, sha256},
- {psk, aes_256_gcm, null, sha384},
- {dhe_psk, aes_128_gcm, null, sha256},
- {dhe_psk, aes_256_gcm, null, sha384},
- {rsa_psk, aes_128_gcm, null, sha256},
- {rsa_psk, aes_256_gcm, null, sha384}],
+psk_suites(Version) ->
+ Suites = ssl_cipher:psk_suites(Version),
ssl_cipher:filter_suites(Suites).
-psk_anon_suites() ->
- Suites =
- [{psk, rc4_128, sha},
- {psk, '3des_ede_cbc', sha},
- {psk, aes_128_cbc, sha},
- {psk, aes_256_cbc, sha},
- {dhe_psk, rc4_128, sha},
- {dhe_psk, '3des_ede_cbc', sha},
- {dhe_psk, aes_128_cbc, sha},
- {dhe_psk, aes_256_cbc, sha}],
+psk_anon_suites(Version) ->
+ Suites = [Suite || Suite <- psk_suites(Version), is_psk_anon_suite(Suite)],
ssl_cipher:filter_suites(Suites).
srp_suites() ->
@@ -1072,14 +1055,16 @@ init_tls_version(Version, Config)
application:load(ssl),
application:set_env(ssl, dtls_protocol_version, Version),
ssl:start(),
- [{protocol, dtls}, {protocol_opts, [{protocol, dtls}]}|Config];
+ NewConfig = proplists:delete(protocol_opts, proplists:delete(protocol, Config)),
+ [{protocol, dtls}, {protocol_opts, [{protocol, dtls}]} | NewConfig];
init_tls_version(Version, Config) ->
ssl:stop(),
application:load(ssl),
application:set_env(ssl, protocol_version, Version),
ssl:start(),
- [{protocol, tls}|Config].
+ NewConfig = proplists:delete(protocol_opts, proplists:delete(protocol, Config)),
+ [{protocol, tls} | NewConfig].
sufficient_crypto_support(Version)
when Version == 'tlsv1.2'; Version == 'dtlsv1.2' ->
@@ -1175,14 +1160,15 @@ is_fips(_) ->
false.
cipher_restriction(Config0) ->
+ Version = tls_record:protocol_version(protocol_version(Config0)),
case is_sane_ecc(openssl) of
false ->
Opts = proplists:get_value(server_opts, Config0),
Config1 = proplists:delete(server_opts, Config0),
VerOpts = proplists:get_value(server_verification_opts, Config1),
Config = proplists:delete(server_verification_opts, Config1),
- Restricted0 = ssl:cipher_suites() -- ecdsa_suites(),
- Restricted = Restricted0 -- ecdh_rsa_suites(),
+ Restricted0 = ssl:cipher_suites() -- ecdsa_suites(Version),
+ Restricted = Restricted0 -- ecdh_rsa_suites(Version),
[{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config];
true ->
Config0
@@ -1213,19 +1199,37 @@ check_sane_openssl_version(Version) ->
enough_openssl_crl_support("OpenSSL 0." ++ _) -> false;
enough_openssl_crl_support(_) -> true.
-wait_for_openssl_server(Port) ->
- wait_for_openssl_server(Port, 10).
-wait_for_openssl_server(_, 0) ->
+wait_for_openssl_server(Port, tls) ->
+ do_wait_for_openssl_tls_server(Port, 10);
+wait_for_openssl_server(Port, dtls) ->
+ do_wait_for_openssl_dtls_server(Port, 10).
+
+do_wait_for_openssl_tls_server(_, 0) ->
exit(failed_to_connect_to_openssl);
-wait_for_openssl_server(Port, N) ->
+do_wait_for_openssl_tls_server(Port, N) ->
case gen_tcp:connect("localhost", Port, []) of
{ok, S} ->
gen_tcp:close(S);
_ ->
ct:sleep(?SLEEP),
- wait_for_openssl_server(Port, N-1)
+ do_wait_for_openssl_tls_server(Port, N-1)
end.
+do_wait_for_openssl_dtls_server(_, 0) ->
+ %%exit(failed_to_connect_to_openssl);
+ ok;
+do_wait_for_openssl_dtls_server(Port, N) ->
+ %% case gen_udp:open(0) of
+ %% {ok, S} ->
+ %% gen_udp:connect(S, "localhost", Port),
+ %% gen_udp:close(S);
+ %% _ ->
+ %% ct:sleep(?SLEEP),
+ %% do_wait_for_openssl_dtls_server(Port, N-1)
+ %% end.
+ ct:sleep(500),
+ do_wait_for_openssl_dtls_server(Port, N-1).
+
version_flag(tlsv1) ->
"-tls1";
version_flag('tlsv1.1') ->
@@ -1235,10 +1239,14 @@ version_flag('tlsv1.2') ->
version_flag(sslv3) ->
"-ssl3";
version_flag(sslv2) ->
- "-ssl2".
-
-filter_suites(Ciphers0) ->
- Version = tls_record:highest_protocol_version([]),
+ "-ssl2";
+version_flag('dtlsv1.2') ->
+ "-dtls1_2";
+version_flag('dtlsv1') ->
+ "-dtls1".
+
+filter_suites(Ciphers0, AtomVersion) ->
+ Version = tls_version(AtomVersion),
Supported0 = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites(Version)
++ ssl_cipher:psk_suites(Version)
@@ -1320,7 +1328,7 @@ protocol_version(Config) ->
protocol_version(Config, tuple) ->
case proplists:get_value(protocol, Config) of
dtls ->
- dtls_record:protocol_version(dtls_record:highest_protocol_version([]));
+ dtls_record:highest_protocol_version(dtls_record:supported_protocol_versions());
_ ->
tls_record:highest_protocol_version(tls_record:supported_protocol_versions())
end;
@@ -1345,3 +1353,122 @@ ct_log_supported_protocol_versions(Config) ->
_ ->
ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()])
end.
+
+clean_env() ->
+ application:unset_env(ssl, protocol_version),
+ application:unset_env(ssl, session_lifetime),
+ application:unset_env(ssl, session_cb),
+ application:unset_env(ssl, session_cb_init_args),
+ application:unset_env(ssl, session_cache_client_max),
+ application:unset_env(ssl, session_cache_server_max),
+ application:unset_env(ssl, ssl_pem_cache_clean),
+ application:unset_env(ssl, bypass_pem_cache),
+ application:unset_env(ssl, alert_timeout).
+
+clean_start() ->
+ ssl:stop(),
+ application:load(ssl),
+ clean_env(),
+ ssl:start().
+
+is_psk_anon_suite({psk, _,_}) ->
+ true;
+is_psk_anon_suite({dhe_psk,_,_}) ->
+ true;
+is_psk_anon_suite({psk, _,_,_}) ->
+ true;
+is_psk_anon_suite({dhe_psk, _,_,_}) ->
+ true;
+is_psk_anon_suite(_) ->
+ false.
+
+cipher_atom(aes_256_cbc) ->
+ aes_cbc256;
+cipher_atom(aes_128_cbc) ->
+ aes_cbc128;
+cipher_atom('3des_ede_cbc') ->
+ des_ede3;
+cipher_atom(Atom) ->
+ Atom.
+tls_version('dtlsv1' = Atom) ->
+ dtls_v1:corresponding_tls_version(dtls_record:protocol_version(Atom));
+tls_version('dtlsv1.2' = Atom) ->
+ dtls_v1:corresponding_tls_version(dtls_record:protocol_version(Atom));
+tls_version(Atom) ->
+ tls_record:protocol_version(Atom).
+
+dtls_hello() ->
+ [1,
+ <<0,1,4>>,
+ <<0,0>>,
+ <<0,0,0>>,
+ <<0,1,4>>,
+ <<254,253,88,
+ 156,129,61,
+ 131,216,15,
+ 131,194,242,
+ 46,154,190,
+ 20,228,234,
+ 234,150,44,
+ 62,96,96,103,
+ 127,95,103,
+ 23,24,42,138,
+ 13,142,32,57,
+ 230,177,32,
+ 210,154,152,
+ 188,121,134,
+ 136,53,105,
+ 118,96,106,
+ 103,231,223,
+ 133,10,165,
+ 50,32,211,
+ 227,193,14,
+ 181,143,48,
+ 66,0,0,100,0,
+ 255,192,44,
+ 192,48,192,
+ 36,192,40,
+ 192,46,192,
+ 50,192,38,
+ 192,42,0,159,
+ 0,163,0,107,
+ 0,106,0,157,
+ 0,61,192,43,
+ 192,47,192,
+ 35,192,39,
+ 192,45,192,
+ 49,192,37,
+ 192,41,0,158,
+ 0,162,0,103,
+ 0,64,0,156,0,
+ 60,192,10,
+ 192,20,0,57,
+ 0,56,192,5,
+ 192,15,0,53,
+ 192,8,192,18,
+ 0,22,0,19,
+ 192,3,192,13,
+ 0,10,192,9,
+ 192,19,0,51,
+ 0,50,192,4,
+ 192,14,0,47,
+ 1,0,0,86,0,0,
+ 0,14,0,12,0,
+ 0,9,108,111,
+ 99,97,108,
+ 104,111,115,
+ 116,0,10,0,
+ 58,0,56,0,14,
+ 0,13,0,25,0,
+ 28,0,11,0,12,
+ 0,27,0,24,0,
+ 9,0,10,0,26,
+ 0,22,0,23,0,
+ 8,0,6,0,7,0,
+ 20,0,21,0,4,
+ 0,5,0,18,0,
+ 19,0,1,0,2,0,
+ 3,0,15,0,16,
+ 0,17,0,11,0,
+ 2,1,0>>].
+
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index b3109b5de9..42cc8b57ad 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,9 @@ all() ->
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
- {group, 'sslv3'}
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
].
groups() ->
@@ -50,12 +52,17 @@ groups() ->
{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'sslv3', [], all_versions_tests()}].
+ {'sslv3', [], all_versions_tests()},
+ {'dtlsv1.2', [], dtls_all_versions_tests()},
+ {'dtlsv1', [], dtls_all_versions_tests()}
+ ].
basic_tests() ->
[basic_erlang_client_openssl_server,
basic_erlang_server_openssl_client,
- expired_session].
+ expired_session,
+ ssl2_erlang_server_openssl_client_comp
+ ].
all_versions_tests() ->
[
@@ -74,7 +81,27 @@ all_versions_tests() ->
ciphers_dsa_signed_certs,
erlang_client_bad_openssl_server,
expired_session,
- ssl2_erlang_server_openssl_client].
+ ssl2_erlang_server_openssl_client
+ ].
+dtls_all_versions_tests() ->
+ [
+ %%erlang_client_openssl_server,
+ erlang_server_openssl_client,
+ %%erlang_client_openssl_server_dsa_cert,
+ erlang_server_openssl_client_dsa_cert
+ %% This one works but gets port EXIT first some times
+ %%erlang_server_openssl_client_reuse_session
+ %%erlang_client_openssl_server_renegotiate,
+ %%erlang_client_openssl_server_nowrap_seqnum,
+ %%erlang_server_openssl_client_nowrap_seqnum,
+ %%erlang_client_openssl_server_no_server_ca_cert,
+ %%erlang_client_openssl_server_client_cert,
+ %%erlang_server_openssl_client_client_cert
+ %%ciphers_rsa_signed_certs,
+ %%ciphers_dsa_signed_certs,
+ %%erlang_client_bad_openssl_server,
+ %%expired_session
+ ].
alpn_tests() ->
[erlang_client_alpn_openssl_server_alpn,
@@ -116,7 +143,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl:start(),
+ ssl_test_lib:clean_start(),
{ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
proplists:get_value(priv_dir, Config0)),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
@@ -180,7 +207,8 @@ special_init(TestCase, Config)
{ok, Version} = application:get_env(ssl, protocol_version),
check_sane_openssl_renegotaite(Config, Version);
-special_init(ssl2_erlang_server_openssl_client, Config) ->
+special_init(Case, Config) when Case == ssl2_erlang_server_openssl_client;
+ Case == ssl2_erlang_server_openssl_client_comp ->
case ssl_test_lib:supports_ssl_tls_version(sslv2) of
true ->
Config;
@@ -280,7 +308,8 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+
+ ssl_test_lib:wait_for_openssl_server(Port, tls),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -353,7 +382,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -427,7 +456,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -547,7 +576,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -596,7 +625,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -677,7 +706,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -720,7 +749,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -830,7 +859,7 @@ ciphers_dsa_signed_certs() ->
[{doc,"Test cipher suites that uses dsa certs"}].
ciphers_dsa_signed_certs(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:dsa_suites(),
+ Ciphers = ssl_test_lib:dsa_suites(tls_record:protocol_version(Version)),
run_suites(Ciphers, Version, Config, dsa).
%%--------------------------------------------------------------------
@@ -852,7 +881,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
"-cert", CertFile, "-key", KeyFile],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -907,7 +936,7 @@ expired_session(Config) when is_list(Config) ->
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, tls),
Client0 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -954,8 +983,52 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Exe = "openssl",
+ Args = ["s_client", "-connect", "localhost:" ++ integer_to_list(Port),
+ "-ssl2", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
+ receive
+ {'EXIT', OpenSslPort, _} = Exit ->
+ ct:log("Received: ~p ~n", [Exit]),
+ ok
+ end,
+ receive
+ {'EXIT', _, _} = UnkownExit ->
+ Msg = lists:flatten(io_lib:format("Received: ~p ~n", [UnkownExit])),
+ ct:log(Msg),
+ ct:comment(Msg),
+ ok
+ after 0 ->
+ ok
+ end,
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}),
+ process_flag(trap_exit, false).
+%%--------------------------------------------------------------------
+ssl2_erlang_server_openssl_client_comp() ->
+ [{doc,"Test that ssl v2 clients are rejected"}].
+
+ssl2_erlang_server_openssl_client_comp(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ V2Compat = proplists:get_value(v2_hello_compatible, Config),
+
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
- {options, ServerOpts}]),
+ {options, [{v2_hello_compatible, V2Compat} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Exe = "openssl",
@@ -1264,7 +1337,7 @@ client_check_result(Port, DataExpected, DataReceived) ->
_ ->
client_check_result(Port, DataExpected, NewData)
end
- after 3000 ->
+ after 20000 ->
ct:fail({"Time out on openSSL Client", {expected, DataExpected},
{got, DataReceived}})
end.
@@ -1351,7 +1424,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
ConnectionInfo = {ok, {Version, CipherSuite}},
@@ -1421,7 +1494,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -1457,7 +1530,7 @@ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callba
Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
"-cert", CertFile, "-key", KeyFile],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -1526,7 +1599,7 @@ start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Ca
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -1591,7 +1664,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
"-cert", CertFile, "-key", KeyFile],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl
index 113b3b4158..875399db76 100644
--- a/lib/ssl/test/ssl_upgrade_SUITE.erl
+++ b/lib/ssl/test/ssl_upgrade_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,8 @@
server,
client,
soft,
- result_proxy
+ result_proxy,
+ skip
}).
all() ->
@@ -73,8 +74,15 @@ major_upgrade(Config) when is_list(Config) ->
minor_upgrade(Config) when is_list(Config) ->
ct_release_test:upgrade(ssl, minor,{?MODULE, #state{config = Config}}, Config).
-upgrade_init(CTData, #state{config = Config} = State) ->
- {ok, {_, _, Up, _Down}} = ct_release_test:get_appup(CTData, ssl),
+upgrade_init(CtData, State) ->
+ {ok,{FromVsn,ToVsn}} = ct_release_test:get_app_vsns(CtData, ssl),
+ upgrade_init(FromVsn, ToVsn, CtData, State).
+
+upgrade_init(_, "8.0.2", _, State) ->
+ %% Requires stdlib upgrade so it will be a node upgrade!
+ State#state{skip = true};
+upgrade_init(_, _, CtData, #state{config = Config} = State) ->
+ {ok, {_, _, Up, _Down}} = ct_release_test:get_appup(CtData, ssl),
ct:pal("Up: ~p", [Up]),
Soft = is_soft(Up), %% It is symmetrical, if upgrade is soft so is downgrade
Pid = spawn(?MODULE, result_proxy_init, [[]]),
@@ -88,6 +96,8 @@ upgrade_init(CTData, #state{config = Config} = State) ->
State#state{soft = Soft, result_proxy = Pid}
end.
+upgrade_upgraded(_, #state{skip = true} = State) ->
+ State;
upgrade_upgraded(_, #state{soft = false, config = Config, result_proxy = Pid} = State) ->
ct:pal("Restart upgrade ~n", []),
{Server, Client} = restart_start_connection(Config, Pid),
@@ -96,7 +106,6 @@ upgrade_upgraded(_, #state{soft = false, config = Config, result_proxy = Pid} =
ssl_test_lib:close(Client),
ok = Result,
State;
-
upgrade_upgraded(_, #state{server = Server0, client = Client0,
config = Config, soft = true,
result_proxy = Pid} = State) ->
@@ -110,6 +119,8 @@ upgrade_upgraded(_, #state{server = Server0, client = Client0,
{Server, Client} = soft_start_connection(Config, Pid),
State#state{server = Server, client = Client}.
+upgrade_downgraded(_, #state{skip = true} = State) ->
+ State;
upgrade_downgraded(_, #state{soft = false, config = Config, result_proxy = Pid} = State) ->
ct:pal("Restart downgrade: ~n", []),
{Server, Client} = restart_start_connection(Config, Pid),
@@ -119,7 +130,6 @@ upgrade_downgraded(_, #state{soft = false, config = Config, result_proxy = Pid}
Pid ! stop,
ok = Result,
State;
-
upgrade_downgraded(_, #state{server = Server, client = Client, soft = true, result_proxy = Pid} = State) ->
ct:pal("Soft downgrade: ~n", []),
Server ! changed_version,
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 3b51fa8c6b..8d955cd080 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 8.0
+SSL_VSN = 8.1.3.1.1
diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml
index e2dfc2ab9b..cb91b1f126 100644
--- a/lib/stdlib/doc/src/assert_hrl.xml
+++ b/lib/stdlib/doc/src/assert_hrl.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>2012</year><year>2015</year>
+ <year>2012</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml
index 3b134d00b7..2e4261d72e 100644
--- a/lib/stdlib/doc/src/dets.xml
+++ b/lib/stdlib/doc/src/dets.xml
@@ -391,7 +391,7 @@
<item>
<p><c>{hash, Hash}</c> - Describes which BIF is
used to calculate the hash values of the objects stored in the
- <c>dets</c> table. Possible values of <c>Hash</c>:</p>
+ Dets table. Possible values of <c>Hash</c>:</p>
<list>
<item>
<p><c>hash</c> - Implies that the <c>erlang:hash/2</c> BIF
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index b8e262208d..5f5d2b7f36 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -369,7 +369,7 @@
variable that in turn is passed to the function.</p>
<p>The parse transform is provided in the <c>ms_transform</c>
module and the source <em>must</em> include
- file <c>ms_transform.hrl</c> in <c>STDLIB</c> for this
+ file <c>ms_transform.hrl</c> in STDLIB for this
pseudo function to work. Failing to include the hrl file in
the source results in a runtime error, not a compile
time error. The include file is easiest included by adding line
@@ -1458,7 +1458,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
specification returned <c>true</c>.</fsummary>
<desc>
<p>Matches the objects in table <c><anno>Tab</anno></c> using a
- <seealso marker="#match_spec">match specificationc</seealso>. If the
+ <seealso marker="#match_spec">match specification</seealso>. If the
match specification returns <c>true</c> for an object, that object
considered a match and is counted. For any other result from
the match specification the object is not considered a match and is
@@ -1644,7 +1644,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
</taglist>
<p>Whenever option <c>extended_info</c> is used, it
results in a file not readable by versions of ETS before
- that in <c>STDLIB</c> 1.15.1</p>
+ that in STDLIB 1.15.1</p>
<p>If option <c>sync</c> is set to <c>true</c>, it ensures that
the content of the file is written to the disk before
<c>tab2file</c> returns. Defaults to <c>{sync, false}</c>.</p>
@@ -1725,7 +1725,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
<p>A tuple <c>{<anno>Major</anno>,<anno>Minor</anno>}</c>
containing the major and
minor version of the file format for ETS table dumps. This
- version field was added beginning with <c>STDLIB</c> 1.5.1.
+ version field was added beginning with STDLIB 1.5.1.
Files dumped with older versions return <c>{0,0}</c> in this
field.</p>
</item>
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index 2a413835d0..f20500709c 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -511,6 +511,33 @@ true
</func>
<func>
+ <name name="safe_relative_path" arity="1"/>
+ <fsummary>Sanitize a relative path to avoid directory traversal attacks.</fsummary>
+ <desc>
+ <p>Sanitizes the relative path by eliminating ".." and "."
+ components to protect against directory traversal attacks.
+ Either returns the sanitized path name, or the atom
+ <c>unsafe</c> if the path is unsafe.
+ The path is considered unsafe in the following circumstances:</p>
+ <list type="bulleted">
+ <item><p>The path is not relative.</p></item>
+ <item><p>A ".." component would climb up above the root of
+ the relative path.</p></item>
+ </list>
+ <p><em>Examples:</em></p>
+ <pre>
+1> <input>filename:safe_relative_path("dir/sub_dir/..").</input>
+"dir"
+2> <input>filename:safe_relative_path("dir/..").</input>
+[]
+3> <input>filename:safe_relative_path("dir/../..").</input>
+unsafe
+4> <input>filename:safe_relative_path("/abs/path").</input>
+unsafe</pre>
+ </desc>
+ </func>
+
+ <func>
<name name="split" arity="1"/>
<fsummary>Split a filename into its path components.</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml
index d677dd6f83..7bfe477a11 100644
--- a/lib/stdlib/doc/src/gb_sets.xml
+++ b/lib/stdlib/doc/src/gb_sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml
index 9a49d66820..790d4b8bf1 100644
--- a/lib/stdlib/doc/src/gb_trees.xml
+++ b/lib/stdlib/doc/src/gb_trees.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index c57a31fa21..5eb13db1aa 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2016</year>
+ <year>2016-2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -54,7 +54,8 @@
<p>
This is a new behavior in Erlang/OTP 19.0.
It has been thoroughly reviewed, is stable enough
- to be used by at least two heavy OTP applications, and is here to stay.
+ to be used by at least two heavy OTP applications,
+ and is here to stay.
Depending on user feedback, we do not expect
but can find it necessary to make minor
not backward compatible changes into Erlang/OTP 20.0.
@@ -70,6 +71,7 @@
<item>The state can be any term.</item>
<item>Events can be postponed.</item>
<item>Events can be self-generated.</item>
+ <item>Automatic state enter code can be called.</item>
<item>A reply can be sent from a later state.</item>
<item>There can be multiple <c>sys</c> traceable replies.</item>
</list>
@@ -97,6 +99,9 @@ gen_statem module Callback module
gen_statem:start
gen_statem:start_link -----> Module:init/1
+Server start or code change
+ -----> Module:callback_mode/0
+
gen_statem:stop -----> Module:terminate/3
gen_statem:call
@@ -116,37 +121,40 @@ erlang:'!' -----> Module:StateName/3
</p>
<p>
If a callback function fails or returns a bad value,
- the <c>gen_statem</c> terminates. However, an exception of class
+ the <c>gen_statem</c> terminates, unless otherwise stated.
+ However, an exception of class
<seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>
- is not regarded as an error but as a valid return.
+ is not regarded as an error but as a valid return
+ from all callback functions.
</p>
- <marker id="state_function"/>
+ <marker id="state callback"/>
<p>
- The "<em>state function</em>" for a specific
+ The "<em>state callback</em>" for a specific
<seealso marker="#type-state">state</seealso>
in a <c>gen_statem</c> is the callback function that is called
for all events in this state. It is selected depending on which
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- that the implementation specifies when the server starts.
+ that the callback module defines with the callback function
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>.
</p>
<p>
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>, the state must be an atom and
- is used as the state function name; see
+ is used as the state callback name; see
<seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>.
This gathers all code for a specific state
in one function as the <c>gen_statem</c> engine
branches depending on state name.
- Notice that in this mode the mandatory callback function
+ Notice the fact that there is a mandatory callback function
<seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
- makes the state name <c>terminate</c> unusable.
+ makes the state name <c>terminate</c> unusable in this mode.
</p>
<p>
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>handle_event_function</c>, the state can be any term
- and the state function name is
+ and the state callback name is
<seealso marker="#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>.
This makes it easy to branch depending on state or event as you desire.
Be careful about which events you handle in which
@@ -156,8 +164,8 @@ erlang:'!' -----> Module:StateName/3
<p>
The <c>gen_statem</c> enqueues incoming events in order of arrival
and presents these to the
- <seealso marker="#state_function">state function</seealso>
- in that order. The state function can postpone an event
+ <seealso marker="#state callback">state callback</seealso>
+ in that order. The state callback can postpone an event
so it is not retried in the current state.
After a state change the queue restarts with the postponed events.
</p>
@@ -169,12 +177,12 @@ erlang:'!' -----> Module:StateName/3
to entering a new receive statement.
</p>
<p>
- The <seealso marker="#state_function">state function</seealso>
+ The <seealso marker="#state callback">state callback</seealso>
can insert events using the
<seealso marker="#type-action"><c>action()</c></seealso>
<c>next_event</c>
and such an event is inserted as the next to present
- to the state function. That is, as if it is
+ to the state callback. That is, as if it is
the oldest incoming event. A dedicated
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>internal</c> can be used for such events making them impossible
@@ -187,9 +195,19 @@ erlang:'!' -----> Module:StateName/3
<seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
to force processing an inserted event before others.
</p>
+ <p>
+ The <c>gen_statem</c> engine can automatically
+ make a specialized call to the
+ <seealso marker="#state callback">state callback</seealso>
+ whenever a new state is entered; see
+ <seealso marker="#type-state_enter"><c>state_enter()</c></seealso>.
+ This is for writing code common to all state entries.
+ Another way to do it is to insert events at state transitions,
+ but you have to do so everywhere it is needed.
+ </p>
<note>
<p>If you in <c>gen_statem</c>, for example, postpone
- an event in one state and then call another state function
+ an event in one state and then call another state callback
of yours, you have not changed states and hence the postponed event
is not retried, which is logical but can be confusing.
</p>
@@ -218,7 +236,7 @@ erlang:'!' -----> Module:StateName/3
The <c>gen_statem</c> process can go into hibernation; see
<seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>.
It is done when a
- <seealso marker="#state_function">state function</seealso> or
+ <seealso marker="#state callback">state callback</seealso> or
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
specifies <c>hibernate</c> in the returned
<seealso marker="#type-action"><c>Actions</c></seealso>
@@ -249,11 +267,10 @@ erlang:'!' -----> Module:StateName/3
-behaviour(gen_statem).
-export([start/0,push/0,get_count/0,stop/0]).
--export([terminate/3,code_change/4,init/1]).
+-export([terminate/3,code_change/4,init/1,callback_mode/0]).
-export([on/3,off/3]).
name() -> pushbutton_statem. % The registered server name
-callback_mode() -> state_functions.
%% API. This example uses a registered name name()
%% and does not link to the caller.
@@ -270,15 +287,14 @@ stop() ->
terminate(_Reason, _State, _Data) ->
void.
code_change(_Vsn, State, Data, _Extra) ->
- {callback_mode(),State,Data}.
+ {ok,State,Data}.
init([]) ->
- %% Set the callback mode and initial state + data.
- %% Data is used only as a counter.
+ %% Set the initial state + data. Data is used only as a counter.
State = off, Data = 0,
- {callback_mode(),State,Data}.
-
+ {ok,State,Data}.
+callback_mode() -> state_functions.
-%%% State functions
+%%% state callback(s)
off({call,From}, push, Data) ->
%% Go to 'on', increment count and reply
@@ -326,18 +342,13 @@ ok
To compare styles, here follows the same example using
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
<c>state_functions</c>, or rather the code to replace
- from function <c>init/1</c> of the <c>pushbutton.erl</c>
+ after function <c>init/1</c> of the <c>pushbutton.erl</c>
example file above:
</p>
<code type="erl">
-init([]) ->
- %% Set the callback mode and initial state + data.
- %% Data is used only as a counter.
- State = off, Data = 0,
- {handle_event_function,State,Data}.
+callback_mode() -> handle_event_function.
-
-%%% Event handling
+%%% state callback(s)
handle_event({call,From}, push, off, Data) ->
%% Go to 'on', increment count and reply
@@ -426,8 +437,8 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
Debug option that can be used when starting
- a <c>gen_statem</c> server through, for example,
- <seealso marker="#enter_loop/5"><c>enter_loop/5</c></seealso>.
+ a <c>gen_statem</c> server through,
+ <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>.
</p>
<p>
For every entry in <c><anno>Dbgs</anno></c>,
@@ -471,6 +482,10 @@ handle_event(_, _, State, Data) ->
<name name="state"/>
<desc>
<p>
+ If the
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
+ is <c>handle_event_function</c>,
+ the state can be any term.
After a state change (<c>NextState =/= State</c>),
all postponed events are retried.
</p>
@@ -484,6 +499,8 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>,
the state must be of this type.
+ After a state change (<c>NextState =/= State</c>),
+ all postponed events are retried.
</p>
</desc>
</datatype>
@@ -516,7 +533,22 @@ handle_event(_, _, State, Data) ->
Type <c>info</c> originates from regular process messages sent
to the <c>gen_statem</c>. Also, the state machine
implementation can generate events of types
- <c>timeout</c> and <c>internal</c> to itself.
+ <c>timeout</c>, <c>state_timeout</c>,
+ and <c>internal</c> to itself.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="callback_mode_result"/>
+ <desc>
+ <p>
+ This is the return type from
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
+ and selects
+ <seealso marker="#type-callback_mode">callback mode</seealso>
+ and whether to do
+ <seealso marker="#type-state_enter">state enter calls</seealso>,
+ or not.
</p>
</desc>
</datatype>
@@ -525,12 +557,9 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
The <em>callback mode</em> is selected when starting the
- <c>gen_statem</c> using the return value from
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
- or when calling
- <seealso marker="#enter_loop/5"><c>enter_loop/5,6,7</c></seealso>,
- and with the return value from
- <seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>.
+ <c>gen_statem</c> and after code change
+ using the return value from
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>.
</p>
<taglist>
<tag><c>state_functions</c></tag>
@@ -555,16 +584,93 @@ handle_event(_, _, State, Data) ->
</desc>
</datatype>
<datatype>
+ <name name="state_enter"/>
+ <desc>
+ <p>
+ Whether the state machine should use <em>state enter calls</em>
+ or not is selected when starting the <c>gen_statem</c>
+ and after code change using the return value from
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>.
+ </p>
+ <p>
+ If
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
+ returns a list containing <c>state_enter</c>,
+ the <c>gen_statem</c> engine will, at every state change,
+ call the
+ <seealso marker="#state callback">state callback</seealso>
+ with arguments <c>(enter, OldState, Data)</c>.
+ This may look like an event but is really a call
+ performed after the previous state callback returned
+ and before any event is delivered to the new state callback.
+ See
+ <seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>
+ and
+ <seealso marker="#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>.
+ Such a call can be repeated by returning a
+ <seealso marker="#type-state_callback_result">
+ <c>repeat_state</c>
+ </seealso>
+ or
+ <seealso marker="#type-state_callback_result">
+ <c>repeat_state_and_data</c>
+ </seealso>
+ tuple from the state callback.
+ </p>
+ <p>
+ If
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
+ does not return such a list, no state enter calls are done.
+ </p>
+ <p>
+ If
+ <seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>
+ should transform the state to a state with a different
+ name it is still regarded as the same state so this
+ does not cause a state enter call.
+ </p>
+ <p>
+ Note that a state enter call <em>will</em> be done
+ right before entering the initial state even though this
+ formally is not a state change.
+ In this case <c>OldState</c> will be the same as <c>State</c>,
+ which can not happen for a subsequent state change,
+ but will happen when repeating the state enter call.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="transition_option"/>
<desc>
<p>
Transition options can be set by
<seealso marker="#type-action">actions</seealso>
- and they modify the following in how
- the state transition is done:
+ and they modify how the state transition is done:
</p>
<list type="ordered">
<item>
+ <p>
+ If the state changes, is the initial state,
+ <seealso marker="#type-state_callback_result">
+ <c>repeat_state</c>
+ </seealso>
+ or
+ <seealso marker="#type-state_callback_result">
+ <c>repeat_state_and_data</c>
+ </seealso>
+ is used, and also
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>
+ are used, the <c>gen_statem</c> calls
+ the new state callback with arguments
+ <seealso marker="#type-state_enter">(enter, OldState, Data)</seealso>.
+ Any
+ <seealso marker="#type-enter_action"><c>actions</c></seealso>
+ returned from this call are handled as if they were
+ appended to the actions
+ returned by the state callback that changed states.
+ </p>
+ </item>
+ <item>
<p>
All
<seealso marker="#type-action">actions</seealso>
@@ -590,27 +696,46 @@ handle_event(_, _, State, Data) ->
All events stored with
<seealso marker="#type-action"><c>action()</c></seealso>
<c>next_event</c>
- are inserted in the queue to be processed before
- all other events.
+ are inserted to be processed before the other queued events.
</p>
</item>
<item>
<p>
- If an
+ Timeout timers
+ <seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
+ and
<seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
- is set through
- <seealso marker="#type-action"><c>action()</c></seealso>
- <c>timeout</c>,
- an event timer can be started or a time-out zero event
- can be enqueued.
+ are handled. Time-outs with zero time are guaranteed to be
+ delivered to the state machine before any external
+ not yet received event so if there is such a timeout requested,
+ the corresponding time-out zero event is enqueued as
+ the newest event.
+ </p>
+ <p>
+ Any event cancels an
+ <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
+ so a zero time event time-out is only generated
+ if the event queue is empty.
+ </p>
+ <p>
+ A state change cancels a
+ <seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
+ and any new transition option of this type
+ belongs to the new state.
</p>
</item>
<item>
<p>
- The (possibly new)
- <seealso marker="#state_function">state function</seealso>
- is called with the oldest enqueued event if there is any,
- otherwise the <c>gen_statem</c> goes into <c>receive</c>
+ If there are enqueued events the
+ <seealso marker="#state callback">state callback</seealso>
+ for the possibly new state
+ is called with the oldest enqueued event,
+ and we start again from the top of this list.
+ </p>
+ </item>
+ <item>
+ <p>
+ Otherwise the <c>gen_statem</c> goes into <c>receive</c>
or hibernation
(if
<seealso marker="#type-hibernate"><c>hibernate()</c></seealso>
@@ -618,8 +743,11 @@ handle_event(_, _, State, Data) ->
to wait for the next message. In hibernation the next
non-system event awakens the <c>gen_statem</c>, or rather
the next incoming message awakens the <c>gen_statem</c>,
- but if it is a system event
- it goes right back into hibernation.
+ but if it is a system event it goes right back into hibernation.
+ When a new message arrives the
+ <seealso marker="#state callback">state callback</seealso>
+ is called with the corresponding event,
+ and we start again from the top of this list.
</p>
</item>
</list>
@@ -661,37 +789,69 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>timeout</c>
after this time (in milliseconds) unless another
- event arrives in which case this time-out is cancelled.
- Notice that a retried or inserted event
- counts like a new in this respect.
+ event arrives or has arrived
+ in which case this time-out is cancelled.
+ Note that a retried or inserted event counts as arrived.
+ So does a state time-out zero event, if it was generated
+ before this timer is requested.
</p>
<p>
If the value is <c>infinity</c>, no timer is started, as
- it never triggers anyway.
+ it never would trigger anyway.
</p>
<p>
- If the value is <c>0</c>, the time-out event is immediately enqueued
- unless there already are enqueued events, as the
- time-out is then immediately cancelled.
- This is a feature ensuring that a time-out <c>0</c> event
- is processed before any not yet received external event.
+ If the value is <c>0</c> no timer is actually started,
+ instead the the time-out event is enqueued to ensure
+ that it gets processed before any not yet
+ received external event.
</p>
<p>
- Notice that it is not possible or needed to cancel this time-out,
+ Note that it is not possible or needed to cancel this time-out,
as it is cancelled automatically by any other event.
</p>
</desc>
</datatype>
<datatype>
+ <name name="state_timeout"/>
+ <desc>
+ <p>
+ Generates an event of
+ <seealso marker="#type-event_type"><c>event_type()</c></seealso>
+ <c>state_timeout</c>
+ after this time (in milliseconds) unless the <c>gen_statem</c>
+ changes states (<c>NewState =/= OldState</c>)
+ which case this time-out is cancelled.
+ </p>
+ <p>
+ If the value is <c>infinity</c>, no timer is started, as
+ it never would trigger anyway.
+ </p>
+ <p>
+ If the value is <c>0</c> no timer is actually started,
+ instead the the time-out event is enqueued to ensure
+ that it gets processed before any not yet
+ received external event.
+ </p>
+ <p>
+ Setting this timer while it is running will restart it with
+ the new time-out value. Therefore it is possible to cancel
+ this time-out by setting it to <c>infinity</c>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="action"/>
<desc>
<p>
These state transition actions can be invoked by
returning them from the
- <seealso marker="#state_function">state function</seealso>, from
+ <seealso marker="#state callback">state callback</seealso>
+ when it is called with an
+ <seealso marker="#type-event_type">event</seealso>,
+ from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving them to
- <seealso marker="#enter_loop/6"><c>enter_loop/6,7</c></seealso>.
+ <seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
</p>
<p>
Actions are executed in the containing list order.
@@ -702,8 +862,8 @@ handle_event(_, _, State, Data) ->
override any previous of the same type,
so the last in the containing list wins.
For example, the last
- <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
- overrides any other <c>event_timeout()</c> in the list.
+ <seealso marker="#type-postpone"><c>postpone()</c></seealso>
+ overrides any previous <c>postpone()</c> in the list.
</p>
<taglist>
<tag><c>postpone</c></tag>
@@ -720,6 +880,53 @@ handle_event(_, _, State, Data) ->
as there is no event to postpone in those cases.
</p>
</item>
+ <tag><c>next_event</c></tag>
+ <item>
+ <p>
+ Stores the specified <c><anno>EventType</anno></c>
+ and <c><anno>EventContent</anno></c> for insertion after all
+ actions have been executed.
+ </p>
+ <p>
+ The stored events are inserted in the queue as the next to process
+ before any already queued events. The order of these stored events
+ is preserved, so the first <c>next_event</c> in the containing
+ list becomes the first to process.
+ </p>
+ <p>
+ An event of type
+ <seealso marker="#type-event_type"><c>internal</c></seealso>
+ is to be used when you want to reliably distinguish
+ an event inserted this way from any external event.
+ </p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="enter_action"/>
+ <desc>
+ <p>
+ These state transition actions can be invoked by
+ returning them from the
+ <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ or by giving them to
+ <seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
+ </p>
+ <p>
+ Actions are executed in the containing list order.
+ </p>
+ <p>
+ Actions that set
+ <seealso marker="#type-transition_option">transition options</seealso>
+ override any previous of the same type,
+ so the last in the containing list wins.
+ For example, the last
+ <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
+ overrides any previous <c>event_timeout()</c> in the list.
+ </p>
+ <taglist>
<tag><c>hibernate</c></tag>
<item>
<p>
@@ -735,7 +942,7 @@ handle_event(_, _, State, Data) ->
Short for <c>{timeout,Timeout,Timeout}</c>, that is,
the time-out message is the time-out time.
This form exists to make the
- <seealso marker="#state_function">state function</seealso>
+ <seealso marker="#state callback">state callback</seealso>
return value <c>{next_state,NextState,NewData,Timeout}</c>
allowed like for <c>gen_fsm</c>'s
<seealso marker="gen_fsm#Module:StateName/2"><c>Module:StateName/2</c></seealso>.
@@ -750,30 +957,13 @@ handle_event(_, _, State, Data) ->
to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>.
</p>
</item>
- <tag><c>reply_action()</c></tag>
- <item>
- <p>
- Replies to a caller.
- </p>
- </item>
- <tag><c>next_event</c></tag>
+ <tag><c>state_timeout</c></tag>
<item>
<p>
- Stores the specified <c><anno>EventType</anno></c>
- and <c><anno>EventContent</anno></c> for insertion after all
- actions have been executed.
- </p>
- <p>
- The stored events are inserted in the queue as the next to process
- before any already queued events. The order of these stored events
- is preserved, so the first <c>next_event</c> in the containing
- list becomes the first to process.
- </p>
- <p>
- An event of type
- <seealso marker="#type-event_type"><c>internal</c></seealso>
- is to be used when you want to reliably distinguish
- an event inserted this way from any external event.
+ Sets the
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
+ <seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
+ to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>.
</p>
</item>
</taglist>
@@ -783,39 +973,97 @@ handle_event(_, _, State, Data) ->
<name name="reply_action"/>
<desc>
<p>
- Replies to a caller waiting for a reply in
+ This state transition action can be invoked by
+ returning it from the
+ <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ or by giving it to
+ <seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
+ </p>
+ <p>
+ It replies to a caller waiting for a reply in
<seealso marker="#call/2"><c>call/2</c></seealso>.
<c><anno>From</anno></c> must be the term from argument
<seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
- to the
- <seealso marker="#state_function">state function</seealso>.
+ in a call to a
+ <seealso marker="#state callback">state callback</seealso>.
+ </p>
+ <p>
+ Note that using this action from
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ or
+ <seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>
+ would be weird on the border of whichcraft
+ since there has been no earlier call to a
+ <seealso marker="#state callback">state callback</seealso>
+ in this server.
</p>
</desc>
</datatype>
<datatype>
- <name name="state_function_result"/>
+ <name name="init_result"/>
<desc>
+ <p>
+ For a succesful initialization,
+ <c><anno>State</anno></c> is the initial
+ <seealso marker="#type-state"><c>state()</c></seealso>
+ and <c><anno>Data</anno></c> the initial server
+ <seealso marker="#type-data"><c>data()</c></seealso>
+ of the <c>gen_statem</c>.
+ </p>
+ <p>
+ The <seealso marker="#type-action"><c>Actions</c></seealso>
+ are executed when entering the first
+ <seealso marker="#type-state">state</seealso> just as for a
+ <seealso marker="#state callback">state callback</seealso>,
+ except that the action <c>postpone</c> is forced to
+ <c>false</c> since there is no event to postpone.
+ </p>
+ <p>
+ For an unsuccesful initialization,
+ <c>{stop,<anno>Reason</anno>}</c>
+ or <c>ignore</c> should be used; see
+ <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="state_enter_result"/>
+ <desc>
+ <p>
+ <c><anno>State</anno></c> is the current state
+ and it can not be changed since the state callback
+ was called with a
+ <seealso marker="#type-state_enter"><em>state enter call</em></seealso>.
+ </p>
<taglist>
<tag><c>next_state</c></tag>
<item>
<p>
The <c>gen_statem</c> does a state transition to
- <c><anno>NextStateName</anno></c>
- (which can be the same as the current state),
+ <c><anno>State</anno></c>, which has to be
+ the current state,
sets <c><anno>NewData</anno></c>,
and executes all <c><anno>Actions</anno></c>.
</p>
</item>
</taglist>
- <p>
- All these terms are tuples or atoms and this property
- will hold in any future version of <c>gen_statem</c>.
- </p>
</desc>
</datatype>
<datatype>
- <name name="handle_event_result"/>
+ <name name="event_handler_result"/>
<desc>
+ <p>
+ <c><anno>StateType</anno></c> is
+ <seealso marker="#type-state_name"><c>state_name()</c></seealso>
+ if
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
+ is <c>state_functions</c>, or
+ <seealso marker="#type-state"><c>state()</c></seealso>
+ if
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
+ is <c>handle_event_function</c>.
+ </p>
<taglist>
<tag><c>next_state</c></tag>
<item>
@@ -828,55 +1076,91 @@ handle_event(_, _, State, Data) ->
</p>
</item>
</taglist>
- <p>
- All these terms are tuples or atoms and this property
- will hold in any future version of <c>gen_statem</c>.
- </p>
</desc>
</datatype>
<datatype>
- <name name="common_state_callback_result"/>
+ <name name="state_callback_result"/>
<desc>
+ <p>
+ <c><anno>ActionType</anno></c> is
+ <seealso marker="#type-enter_action"><c>enter_action()</c></seealso>
+ if the state callback was called with a
+ <seealso marker="#type-state_enter"><em>state enter call</em></seealso>
+ and
+ <seealso marker="#type-action"><c>action()</c></seealso>
+ if the state callback was called with an event.
+ </p>
<taglist>
- <tag><c>stop</c></tag>
+ <tag><c>keep_state</c></tag>
<item>
<p>
- Terminates the <c>gen_statem</c> by calling
- <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
- with <c>Reason</c> and
- <c><anno>NewData</anno></c>, if specified.
+ The <c>gen_statem</c> keeps the current state, or
+ does a state transition to the current state if you like,
+ sets <c><anno>NewData</anno></c>,
+ and executes all <c><anno>Actions</anno></c>.
+ This is the same as
+ <c>{next_state,CurrentState,<anno>NewData</anno>,<anno>Actions</anno>}</c>.
</p>
</item>
- <tag><c>stop_and_reply</c></tag>
+ <tag><c>keep_state_and_data</c></tag>
<item>
<p>
- Sends all <c><anno>Replies</anno></c>,
- then terminates the <c>gen_statem</c> by calling
- <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
- with <c>Reason</c> and
- <c><anno>NewData</anno></c>, if specified.
+ The <c>gen_statem</c> keeps the current state or
+ does a state transition to the current state if you like,
+ keeps the current server data,
+ and executes all <c><anno>Actions</anno></c>.
+ This is the same as
+ <c>{next_state,CurrentState,CurrentData,<anno>Actions</anno>}</c>.
</p>
</item>
- <tag><c>keep_state</c></tag>
+ <tag><c>repeat_state</c></tag>
<item>
<p>
The <c>gen_statem</c> keeps the current state, or
does a state transition to the current state if you like,
sets <c><anno>NewData</anno></c>,
and executes all <c><anno>Actions</anno></c>.
- This is the same as
- <c>{next_state,CurrentState,<anno>NewData</anno>,<anno>Actions</anno>}</c>.
+ If the <c>gen_statem</c> runs with
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
+ the state enter call is repeated, see type
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>,
+ otherwise <c>repeat_state</c> is the same as
+ <c>keep_state</c>.
</p>
</item>
- <tag><c>keep_state_and_data</c></tag>
+ <tag><c>repeat_state_and_data</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state or
+ The <c>gen_statem</c> keeps the current state and data, or
does a state transition to the current state if you like,
- keeps the current server data,
and executes all <c><anno>Actions</anno></c>.
This is the same as
- <c>{next_state,CurrentState,CurrentData,<anno>Actions</anno>}</c>.
+ <c>{repeat_state,CurrentData,<anno>Actions</anno>}</c>.
+ If the <c>gen_statem</c> runs with
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
+ the state enter call is repeated, see type
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>,
+ otherwise <c>repeat_state_and_data</c> is the same as
+ <c>keep_state_and_data</c>.
+ </p>
+ </item>
+ <tag><c>stop</c></tag>
+ <item>
+ <p>
+ Terminates the <c>gen_statem</c> by calling
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
+ with <c>Reason</c> and
+ <c><anno>NewData</anno></c>, if specified.
+ </p>
+ </item>
+ <tag><c>stop_and_reply</c></tag>
+ <item>
+ <p>
+ Sends all <c><anno>Replies</anno></c>,
+ then terminates the <c>gen_statem</c> by calling
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
+ with <c>Reason</c> and
+ <c><anno>NewData</anno></c>, if specified.
</p>
</item>
</taglist>
@@ -900,14 +1184,14 @@ handle_event(_, _, State, Data) ->
by sending a request
and waiting until its reply arrives.
The <c>gen_statem</c> calls the
- <seealso marker="#state_function">state function</seealso> with
+ <seealso marker="#state callback">state callback</seealso> with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>{call,From}</c> and event content
<c><anno>Request</anno></c>.
</p>
<p>
A <c><anno>Reply</anno></c> is generated when a
- <seealso marker="#state_function">state function</seealso>
+ <seealso marker="#state callback">state callback</seealso>
returns with
<c>{reply,From,<anno>Reply</anno>}</c> as one
<seealso marker="#type-action"><c>action()</c></seealso>,
@@ -923,17 +1207,40 @@ handle_event(_, _, State, Data) ->
</p>
<note>
<p>
- To avoid getting a late reply in the caller's
- inbox, this function spawns a proxy process that
+ For <c><anno>Timeout</anno> &lt; infinity</c>,
+ to avoid getting a late reply in the caller's
+ inbox if the caller should catch exceptions,
+ this function spawns a proxy process that
does the call. A late reply gets delivered to the
dead proxy process, hence gets discarded. This is
less efficient than using
- <c><anno>Timeout</anno> =:= infinity</c>.
+ <c><anno>Timeout</anno> == infinity</c>.
</p>
</note>
<p>
- The call can fail, for example, if the <c>gen_statem</c> dies
- before or during this function call.
+ <c><anno>Timeout</anno></c> can also be a tuple
+ <c>{clean_timeout,<anno>T</anno>}</c> or
+ <c>{dirty_timeout,<anno>T</anno>}</c>, where
+ <c><anno>T</anno></c> is the time-out time.
+ <c>{clean_timeout,<anno>T</anno>}</c> works like
+ just <c>T</c> described in the note above
+ and uses a proxy process for <c>T &lt; infinity</c>,
+ while <c>{dirty_timeout,<anno>T</anno>}</c>
+ bypasses the proxy process which is more lightweight.
+ </p>
+ <note>
+ <p>
+ If you combine catching exceptions from this function
+ with <c>{dirty_timeout,<anno>T</anno>}</c>
+ to avoid that the calling process dies when the call
+ times out, you will have to be prepared to handle
+ a late reply.
+ So why not just allow the calling process to die?
+ </p>
+ </note>
+ <p>
+ The call can also fail, for example, if the <c>gen_statem</c>
+ dies before or during this function call.
</p>
</desc>
</func>
@@ -949,7 +1256,7 @@ handle_event(_, _, State, Data) ->
ignoring if the destination node or <c>gen_statem</c>
does not exist.
The <c>gen_statem</c> calls the
- <seealso marker="#state_function">state function</seealso> with
+ <seealso marker="#state callback">state callback</seealso> with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>cast</c> and event content
<c><anno>Msg</anno></c>.
@@ -958,35 +1265,36 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="enter_loop" arity="5"/>
+ <name name="enter_loop" arity="4"/>
<fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
The same as
- <seealso marker="#enter_loop/7"><c>enter_loop/7</c></seealso>
- except that no
+ <seealso marker="#enter_loop/6"><c>enter_loop/6</c></seealso>
+ with <c>Actions = []</c> except that no
<seealso marker="#type-server_name"><c>server_name()</c></seealso>
- must have been registered.
+ must have been registered. This creates an anonymous server.
</p>
</desc>
</func>
<func>
- <name name="enter_loop" arity="6"/>
+ <name name="enter_loop" arity="5"/>
<fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
If <c><anno>Server_or_Actions</anno></c> is a <c>list()</c>,
the same as
- <seealso marker="#enter_loop/7"><c>enter_loop/7</c></seealso>
+ <seealso marker="#enter_loop/6"><c>enter_loop/6</c></seealso>
except that no
<seealso marker="#type-server_name"><c>server_name()</c></seealso>
must have been registered and
<c>Actions = <anno>Server_or_Actions</anno></c>.
+ This creates an anonymous server.
</p>
<p>
Otherwise the same as
- <seealso marker="#enter_loop/7"><c>enter_loop/7</c></seealso>
+ <seealso marker="#enter_loop/6"><c>enter_loop/6</c></seealso>
with
<c>Server = <anno>Server_or_Actions</anno></c> and
<c>Actions = []</c>.
@@ -995,7 +1303,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="enter_loop" arity="7"/>
+ <name name="enter_loop" arity="6"/>
<fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
@@ -1015,21 +1323,31 @@ handle_event(_, _, State, Data) ->
the <c>gen_statem</c> behavior provides.
</p>
<p>
- <c><anno>Module</anno></c>, <c><anno>Opts</anno></c>, and
- <c><anno>Server</anno></c> have the same meanings
- as when calling
+ <c><anno>Module</anno></c>, <c><anno>Opts</anno></c>
+ have the same meaning as when calling
<seealso marker="#start_link/3"><c>start[_link]/3,4</c></seealso>.
+ </p>
+ <p>
+ If <c><anno>Server</anno></c> is <c>self()</c> an anonymous
+ server is created just as when using
+ <seealso marker="#start_link/3"><c>start[_link]/3</c></seealso>.
+ If <c><anno>Server</anno></c> is a
+ <seealso marker="#type-server_name"><c>server_name()</c></seealso>
+ a named server is created just as when using
+ <seealso marker="#start_link/4"><c>start[_link]/4</c></seealso>.
However, the
<seealso marker="#type-server_name"><c>server_name()</c></seealso>
name must have been registered accordingly
- <em>before</em> this function is called.</p>
+ <em>before</em> this function is called.
+ </p>
<p>
- <c><anno>CallbackMode</anno></c>, <c><anno>State</anno></c>,
- <c><anno>Data</anno></c>, and <c><anno>Actions</anno></c>
+ <c><anno>State</anno></c>, <c><anno>Data</anno></c>,
+ and <c><anno>Actions</anno></c>
have the same meanings as in the return value of
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>.
- Also, the callback module <c><anno>Module</anno></c>
- does not need to export an <c>init/1</c> function.
+ Also, the callback module does not need to export a
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ function.
</p>
<p>
The function fails if the calling process was not started by a
@@ -1052,17 +1370,18 @@ handle_event(_, _, State, Data) ->
<seealso marker="#call/2"><c>call/2</c></seealso>
when the reply cannot be defined in
the return value of a
- <seealso marker="#state_function">state function</seealso>.
+ <seealso marker="#state callback">state callback</seealso>.
</p>
<p>
<c><anno>From</anno></c> must be the term from argument
<seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
to the
- <seealso marker="#state_function">state function</seealso>.
- <c><anno>From</anno></c> and <c><anno>Reply</anno></c>
- can also be specified using a
- <seealso marker="#type-reply_action"><c>reply_action()</c></seealso>
- and multiple replies with a list of them.
+ <seealso marker="#state callback">state callback</seealso>.
+ A reply or multiple replies canalso be sent
+ using one or several
+ <seealso marker="#type-reply_action"><c>reply_action()</c></seealso>s
+ from a
+ <seealso marker="#state callback">state callback</seealso>.
</p>
<note>
<p>
@@ -1253,6 +1572,57 @@ handle_event(_, _, State, Data) ->
<funcs>
<func>
+ <name>Module:callback_mode() -> CallbackMode</name>
+ <fsummary>Update the internal state during upgrade/downgrade.</fsummary>
+ <type>
+ <v>
+ CallbackMode =
+ <seealso marker="#type-callback_mode">callback_mode()</seealso> |
+ [ <seealso marker="#type-callback_mode">callback_mode()</seealso>
+ | <seealso marker="#type-state_enter">state_enter()</seealso> ]
+ </v>
+ </type>
+ <desc>
+ <p>
+ This function is called by a <c>gen_statem</c>
+ when it needs to find out the
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
+ of the callback module. The value is cached by <c>gen_statem</c>
+ for efficiency reasons, so this function is only called
+ once after server start and after code change,
+ but before the first
+ <seealso marker="#state callback">state callback</seealso>
+ in the current code version is called.
+ More occasions may be added in future versions
+ of <c>gen_statem</c>.
+ </p>
+ <p>
+ Server start happens either when
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ returns or when
+ <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>
+ is called. Code change happens when
+ <seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>
+ returns.
+ </p>
+ <p>
+ The <c>CallbackMode</c> is either just
+ <seealso marker="#type-callback_mode"><c>callback_mode()</c></seealso>
+ or a list containing
+ <seealso marker="#type-callback_mode"><c>callback_mode()</c></seealso>
+ and possibly the atom
+ <seealso marker="#type-state_enter"><c>state_enter</c></seealso>.
+ </p>
+ <note>
+ <p>
+ If this function's body does not return an inline constant
+ value the callback module is doing something strange.
+ </p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
<name>Module:code_change(OldVsn, OldState, OldData, Extra) ->
Result
</name>
@@ -1262,11 +1632,7 @@ handle_event(_, _, State, Data) ->
<v>&nbsp;&nbsp;Vsn = term()</v>
<v>OldState = NewState = term()</v>
<v>Extra = term()</v>
- <v>Result = {NewCallbackMode,NewState,NewData} | Reason</v>
- <v>
- NewCallbackMode =
- <seealso marker="#type-callback_mode">callback_mode()</seealso>
- </v>
+ <v>Result = {ok,NewState,NewData} | Reason</v>
<v>
OldState = NewState =
<seealso marker="#type-state">state()</seealso>
@@ -1295,21 +1661,6 @@ handle_event(_, _, State, Data) ->
<c>Module</c>. If no such attribute is defined, the version
is the checksum of the Beam file.
</p>
- <note>
- <p>
- If you would dare to change
- <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- during release upgrade/downgrade, the upgrade is no problem,
- as the new code surely knows what <em>callback mode</em>
- it needs. However, for a downgrade this function must
- know from argument <c>Extra</c> that comes from the
- <seealso marker="sasl:appup"><c>sasl:appup</c></seealso>
- file what <em>callback mode</em> the old code did use.
- It can also be possible to figure this out
- from argument <c>{down,Vsn}</c>, as <c>Vsn</c>
- in effect defines the old callback module version.
- </p>
- </note>
<p>
<c>OldState</c> and <c>OldData</c> is the internal state
of the <c>gen_statem</c>.
@@ -1321,41 +1672,46 @@ handle_event(_, _, State, Data) ->
<p>
If successful, the function must return the updated
internal state in an
- <c>{NewCallbackMode,NewState,NewData}</c> tuple.
- </p>
- <p>
- If the function returns <c>Reason</c>, the ongoing
- upgrade fails and rolls back to the old release.</p>
- <p>
- This function can use
- <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
- to return <c>Result</c> or <c>Reason</c>.
+ <c>{ok,NewState,NewData}</c> tuple.
+ </p>
+ <p>
+ If the function returns a failure <c>Reason</c>, the ongoing
+ upgrade fails and rolls back to the old release.
+ Note that <c>Reason</c> can not be an <c>{ok,_,_}</c> tuple
+ since that will be regarded as a
+ <c>{ok,NewState,NewData}</c> tuple,
+ and that a tuple matching <c>{ok,_}</c>
+ is an also invalid failure <c>Reason</c>.
+ It is recommended to use an atom as <c>Reason</c> since
+ it will be wrapped in an <c>{error,Reason}</c> tuple.
+ </p>
+ <p>
+ Also note when upgrading a <c>gen_statem</c>,
+ this function and hence
+ the <c>Change={advanced,Extra}</c> parameter in the
+ <seealso marker="sasl:appup"><c>appup</c></seealso> file
+ is not only needed to update the internal state
+ or to act on the <c>Extra</c> argument.
+ It is also needed if an upgrade or downgrade should change
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>,
+ or else the callback mode after the code change
+ will not be honoured,
+ most probably causing a server crash.
</p>
</desc>
</func>
<func>
- <name>Module:init(Args) -> Result</name>
- <fsummary>Initialize process and internal state.</fsummary>
+ <name>Module:init(Args) -> Result(StateType)</name>
+ <fsummary>
+ Optional function for initializing process and internal state.
+ </fsummary>
<type>
<v>Args = term()</v>
- <v>Result = {CallbackMode,State,Data}</v>
- <v>&nbsp;| {CallbackMode,State,Data,Actions}</v>
- <v>&nbsp;| {stop,Reason} | ignore</v>
<v>
- CallbackMode =
- <seealso marker="#type-callback_mode">callback_mode()</seealso>
+ Result(StateType) =
+ <seealso marker="#type-init_result">init_result(StateType)</seealso>
</v>
- <v>State = <seealso marker="#type-state">state()</seealso></v>
- <v>
- Data = <seealso marker="#type-data">data()</seealso>
- </v>
- <v>
- Actions =
- [<seealso marker="#type-action">action()</seealso>] |
- <seealso marker="#type-action">action()</seealso>
- </v>
- <v>Reason = term()</v>
</type>
<desc>
<marker id="Module:init-1"/>
@@ -1364,42 +1720,23 @@ handle_event(_, _, State, Data) ->
<seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>
or
<seealso marker="#start/3"><c>start/3,4</c></seealso>,
- this function is called by the new process to initialize
+ this optional function is called by the new process to initialize
the implementation state and server data.
</p>
<p>
- <c>Args</c> is the <c>Args</c> argument provided to the start
+ <c>Args</c> is the <c>Args</c> argument provided to that start
function.
</p>
- <p>
- If the initialization is successful, the function is to
- return <c>{CallbackMode,State,Data}</c> or
- <c>{CallbackMode,State,Data,Actions}</c>.
- <c>CallbackMode</c> selects the
- <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
- of the <c>gen_statem</c>.
- <c>State</c> is the initial
- <seealso marker="#type-state"><c>state()</c></seealso>
- and <c>Data</c> the initial server
- <seealso marker="#type-data"><c>data()</c></seealso>.
- </p>
- <p>
- The <seealso marker="#type-action"><c>Actions</c></seealso>
- are executed when entering the first
- <seealso marker="#type-state">state</seealso> just as for a
- <seealso marker="#state_function">state function</seealso>.
- </p>
- <p>
- If the initialization fails,
- the function is to return <c>{stop,Reason}</c>
- or <c>ignore</c>; see
- <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.
- </p>
- <p>
- This function can use
- <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
- to return <c>Result</c>.
- </p>
+ <note>
+ <p>
+ This callback is optional, so a callback module does not need
+ to export it, but most do. If this function is not exported,
+ the <c>gen_statem</c> should be started through
+ <seealso marker="proc_lib"><c>proc_lib</c></seealso>
+ and
+ <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>.
+ </p>
+ </note>
</desc>
</func>
@@ -1430,10 +1767,14 @@ handle_event(_, _, State, Data) ->
This callback is optional, so a callback module does not need
to export it. The <c>gen_statem</c> module provides a default
implementation of this function that returns
- <c>{State,Data}</c>. If this callback fails, the default
- function returns <c>{State,Info}</c>,
- where <c>Info</c> informs of the crash but no details,
- to hide possibly sensitive data.
+ <c>{State,Data}</c>.
+ </p>
+ <p>
+ If this callback is exported but fails,
+ to hide possibly sensitive data,
+ the default function will instead return <c>{State,Info}</c>,
+ where <c>Info</c> says nothing but the fact that
+ <c>format_status/2</c> has crashed.
</p>
</note>
<p>This function is called by a <c>gen_statem</c> process when
@@ -1474,7 +1815,8 @@ handle_event(_, _, State, Data) ->
</p>
<p>
The function is to return <c>Status</c>, a term that
- changes the details of the current state and status of
+ contains the appropriate details
+ of the current state and status of
the <c>gen_statem</c>. There are no restrictions on the
form <c>Status</c> can take, but for the
<seealso marker="sys#get_status/1"><c>sys:get_status/1,2</c></seealso>
@@ -1494,20 +1836,21 @@ handle_event(_, _, State, Data) ->
printed in log files. Another use is to hide sensitive data from
being written to the error log.
</p>
- <p>
- This function can use
- <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
- to return <c>Status</c>.
- </p>
</desc>
</func>
<func>
+ <name>Module:StateName(enter, OldState, Data) ->
+ StateEnterResult(StateName)
+ </name>
<name>Module:StateName(EventType, EventContent, Data) ->
StateFunctionResult
</name>
- <name>Module:handle_event(EventType, EventContent,
- State, Data) -> HandleEventResult
+ <name>Module:handle_event(enter, OldState, State, Data) ->
+ StateEnterResult(State)
+ </name>
+ <name>Module:handle_event(EventType, EventContent, State, Data) ->
+ HandleEventResult
</name>
<fsummary>Handle an event.</fsummary>
<type>
@@ -1525,12 +1868,20 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-data">data()</seealso>
</v>
<v>
+ StateEnterResult(StateName) =
+ <seealso marker="#type-state_enter_result">state_enter_result(StateName)</seealso>
+ </v>
+ <v>
StateFunctionResult =
- <seealso marker="#type-state_function_result">state_function_result()</seealso>
+ <seealso marker="#type-event_handler_result">event_handler_result</seealso>(<seealso marker="#type-state_name">state_name()</seealso>)
+ </v>
+ <v>
+ StateEnterResult(State) =
+ <seealso marker="#type-state_enter_result">state_enter_result(State)</seealso>
</v>
<v>
HandleEventResult =
- <seealso marker="#type-handle_event_result">handle_event_result()</seealso>
+ <seealso marker="#type-event_handler_result">event_handler_result</seealso>(<seealso marker="#type-state">state()</seealso>)
</v>
</type>
<desc>
@@ -1549,7 +1900,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-event_type"><c>{call,From}</c></seealso>,
the caller waits for a reply. The reply can be sent
from this or from any other
- <seealso marker="#state_function">state function</seealso>
+ <seealso marker="#state callback">state callback</seealso>
by returning with <c>{reply,From,Reply}</c> in
<seealso marker="#type-action"><c>Actions</c></seealso>, in
<seealso marker="#type-reply_action"><c>Replies</c></seealso>,
@@ -1573,9 +1924,41 @@ handle_event(_, _, State, Data) ->
see <seealso marker="#type-action"><c>action()</c></seealso>.
</p>
<p>
- These functions can use
- <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>,
- to return the result.
+ When the <c>gen_statem</c> runs with
+ <seealso marker="#type-state_enter">state enter calls</seealso>,
+ these functions are also called with arguments
+ <c>(enter, OldState, ...)</c> whenever the state changes.
+ In this case there are some restrictions on the
+ <seealso marker="#type-enter_action">actions</seealso>
+ that may be returned:
+ <seealso marker="#type-postpone"><c>postpone()</c></seealso>
+ is not allowed since a <em>state enter call</em> is not
+ an event so there is no event to postpone, and
+ <seealso marker="#type-action"><c>{next_event,_,_}</c></seealso>
+ is not allowed since using <em>state enter calls</em>
+ should not affect how events are consumed and produced.
+ You may also not change states from this call.
+ Should you return <c>{next_state,NextState, ...}</c>
+ with <c>NextState =/= State</c> the <c>gen_statem</c> crashes.
+ It is possible to use <c>{repeat_state, ...}</c>,
+ <c>{repeat_state_and_data,_}</c> or
+ <c>repeat_state_and_data</c> but all of them makes little
+ sense since you immediately will be called again with a new
+ <em>state enter call</em> making this just a weird way
+ of looping, and there are better ways to loop in Erlang.
+ You are advised to use <c>{keep_state,...}</c>,
+ <c>{keep_state_and_data,_}</c> or
+ <c>keep_state_and_data</c> since you can not change states
+ from a <em>state enter call</em> anyway.
+ </p>
+ <p>
+ Note the fact that you can use
+ <seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>
+ to return the result, which can be useful.
+ For example to bail out with <c>throw(keep_state_and_data)</c>
+ from deep within complex code that can not
+ return <c>{next_state,State,Data}</c> because
+ <c>State</c> or <c>Data</c> is no longer in scope.
</p>
</desc>
</func>
@@ -1590,6 +1973,11 @@ handle_event(_, _, State, Data) ->
<v>Ignored = term()</v>
</type>
<desc>
+ <note>
+ <p>This callback is optional, so callback modules need not
+ export it. The <c>gen_statem</c> module provides a default
+ implementation without cleanup.</p>
+ </note>
<p>
This function is called by a <c>gen_statem</c>
when it is about to terminate. It is to be the opposite of
@@ -1648,11 +2036,6 @@ handle_event(_, _, State, Data) ->
and an error report is issued using
<seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
</p>
- <p>
- This function can use
- <seealso marker="erts:erlang#throw/1"><c>erlang:throw/1</c></seealso>
- to return <c>Ignored</c>, which is ignored anyway.
- </p>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/introduction.xml b/lib/stdlib/doc/src/introduction.xml
index 5bf545c65f..642ca02430 100644
--- a/lib/stdlib/doc/src/introduction.xml
+++ b/lib/stdlib/doc/src/introduction.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1999</year>
- <year>2013</year>
+ <year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index e1edbadcd3..8c7270816b 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -160,7 +160,7 @@ val1
<p><em>Example:</em></p>
<code type="none">
> Map = #{"42" => value}.
-#{"42"> => value}
+#{"42" => value}
> maps:is_key("42",Map).
true
> maps:is_key(value,Map).
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index ad2599c5a0..bb35224182 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,227 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>An escript with only two lines would not work.</p>
+ <p>
+ Own Id: OTP-14098</p>
+ </item>
+ <item>
+ <p> Characters (<c>$char</c>) can be used in constant
+ pattern expressions. They can also be used in types and
+ contracts. </p>
+ <p>
+ Own Id: OTP-14103 Aux Id: ERL-313 </p>
+ </item>
+ <item>
+ <p> The signatures of <c>erl_parse:anno_to_term/1</c> and
+ <c>erl_parse:anno_from_term/1</c> are corrected. Using
+ these functions no longer results in false Dialyzer
+ warnings. </p>
+ <p>
+ Own Id: OTP-14131</p>
+ </item>
+ <item>
+ <p>Pretty-printing of maps is improved. </p>
+ <p>
+ Own Id: OTP-14175 Aux Id: seq13277 </p>
+ </item>
+ <item>
+ <p>If any of the following functions in the <c>zip</c>
+ module crashed, a file would be left open:
+ <c>extract()</c>, <c>unzip()</c>, <c>create()</c>, or
+ <c>zip()</c>. This has been corrected.</p>
+ <p>A <c>zip</c> file having a "Unix header" could not be
+ unpacked.</p>
+ <p>
+ Own Id: OTP-14189 Aux Id: ERL-348, ERL-349 </p>
+ </item>
+ <item>
+ <p> Improve the Erlang shell's tab-completion of long
+ names. </p>
+ <p>
+ Own Id: OTP-14200 Aux Id: ERL-352 </p>
+ </item>
+ <item>
+ <p>
+ The reference manual for <c>sys</c> had some faulty
+ information about the 'get_modules' message used by
+ processes where modules change dynamically during
+ runtime. The documentation is now corrected.</p>
+ <p>
+ Own Id: OTP-14248 Aux Id: ERL-367 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Bug fixes, new features and improvements to gen_statem:</p>
+ <p>
+ A new type init_result/1 has replaced the old
+ init_result/0, so if you used that old type (that was
+ never documented) you have to change your code, which may
+ be regarded as a potential incompatibility.</p>
+ <p>
+ Changing callback modes after code change did not work
+ since the new callback mode was not recorded. This bug
+ has been fixed.</p>
+ <p>
+ The event types state_timeout and {call,From} could not
+ be generated with a {next_event,EventType,EventContent}
+ action since they did not pass the runtime type check.
+ This bug has now been corrected.</p>
+ <p>
+ State entry calls can now be repeated using (new) state
+ callback returns {repeat_state,...},
+ {repeat_state_and_data,_} and repeat_state_and_data.</p>
+ <p>
+ There have been lots of code cleanup in particular
+ regarding timer handling. For example is async
+ cancel_timer now used. Error handling has also been
+ cleaned up.</p>
+ <p>
+ To align with probable future changes to the rest of
+ gen_*, terminate/3 has now got a fallback and
+ code_change/4 is not mandatory.</p>
+ <p>
+ Own Id: OTP-14114</p>
+ </item>
+ <item>
+ <p><c>filename:safe_relative_path/1</c> to sanitize a
+ relative path has been added.</p>
+ <p>
+ Own Id: OTP-14215</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When a simple_one_for_one supervisor is shutting down,
+ and a child exits with an exit reason of the form
+ {shutdown, Term}, an error report was earlier printed.
+ This is now corrected.</p>
+ <p>
+ Own Id: OTP-13907 Aux Id: PR-1158, ERL-163 </p>
+ </item>
+ <item>
+ <p> Allow empty list as parameter of the fun used with
+ <c>dbg:fun2ms/1</c>. </p>
+ <p>
+ Own Id: OTP-13974</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The new behaviour gen_statem has been improved with 3 new
+ features: the possibility to use old style non-proxy
+ timeouts for gen_statem:call/2,3, state entry code, and
+ state timeouts. These are backwards compatible. Minor
+ code and documentation improvements has been performed
+ including a borderline semantics correction of timeout
+ zero handling.</p>
+ <p>
+ Own Id: OTP-13929 Aux Id: PR-1170, ERL-284 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The <c>zip:unzip/1,2</c> and <c>zip:extract/1,2</c>
+ functions have been updated to handle directory traversal
+ exploits. Any element in the zip file that contains a
+ path that points to a directory above the top level
+ working directory, <c>cwd</c>, will instead be extracted
+ in <c>cwd</c>. An error message is printed for any such
+ element in the zip file during the unzip operation. The
+ <c>keep_old_files</c> option determines if a file will
+ overwrite a previous file with the same name within the
+ zip file.</p>
+ <p>
+ Own Id: OTP-13633</p>
+ </item>
+ <item>
+ <p> Correct the contracts for
+ <c>ets:match_object/1,3</c>. </p>
+ <p>
+ Own Id: OTP-13721 Aux Id: PR-1113 </p>
+ </item>
+ <item>
+ <p>
+ Errors in type specification and Emacs template
+ generation for <c>gen_statem:code_change/4</c> has been
+ fixed from bugs.erlang.org's Jira cases ERL-172 and
+ ERL-187.</p>
+ <p>
+ Own Id: OTP-13746 Aux Id: ERL-172, ERL-187 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ gen_statem has been changed to set the callback mode for
+ a server to what Module:callback_mode/0 returns. This
+ facilitates e.g code downgrade since the callback mode
+ now becomes a property of the currently active code, not
+ of the server process.</p>
+ <p>
+ Exception handling from Module:init/1 has also been
+ improved.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13752</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Correct a bug regarding typed records in the Erlang
+ shell. The bug was introduced in OTP-19.0. </p>
+ <p>
+ Own Id: OTP-13719 Aux Id: ERL-182 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -511,7 +732,7 @@
</item>
<item>
<p>
- The <c>stdlib</c> reference manual is updated to show
+ The STDLIB reference manual is updated to show
correct information about the return value of
<c>gen_fsm:reply/2</c>.</p>
<p>
@@ -6221,7 +6442,7 @@
documentation for <c>compile</c> on how to provide the key
for encrypting, and the documentation for <c>beam_lib</c>
on how to provide the key for decryption so that tools such
- as the Debugger, <c>xref</c>, or <c>cover</c> can be used.</p>
+ as the Debugger, Xref, or Cover can be used.</p>
<p>The <c>beam_lib:chunks/2</c> functions now accepts an
additional chunk type <c>compile_info</c> to retrieve
the compilation information directly as a term. (Thanks
diff --git a/lib/stdlib/doc/src/orddict.xml b/lib/stdlib/doc/src/orddict.xml
index 076b06fc38..d048983c61 100644
--- a/lib/stdlib/doc/src/orddict.xml
+++ b/lib/stdlib/doc/src/orddict.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2000</year><year>2015</year>
+ <year>2000</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml
index 58ca5644cf..da03c39a26 100644
--- a/lib/stdlib/doc/src/proc_lib.xml
+++ b/lib/stdlib/doc/src/proc_lib.xml
@@ -59,9 +59,9 @@
<p>When a process that is started using <c>proc_lib</c> terminates
abnormally (that is, with another exit reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c>), a <em>crash report</em>
- is generated, which is written to terminal by the default <c>SASL</c>
+ is generated, which is written to terminal by the default SASL
event handler. That is, the crash report is normally only visible
- if the <c>SASL</c> application is started; see
+ if the SASL application is started; see
<seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso> and section
<seealso marker="sasl:error_logging">SASL Error Logging</seealso>
in the SASL User's Guide.</p>
diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml
index a46ca47033..9f3aff03a3 100644
--- a/lib/stdlib/doc/src/queue.xml
+++ b/lib/stdlib/doc/src/queue.xml
@@ -401,7 +401,7 @@
</func>
<func>
- <name name="liat" arity="1"/>v
+ <name name="liat" arity="1"/>
<fsummary>Remove the tail item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml
index 1dcc3de000..eb7870e367 100644
--- a/lib/stdlib/doc/src/rand.xml
+++ b/lib/stdlib/doc/src/rand.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2015</year>
+ <year>2015</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml
index f7668af1ed..44dc104645 100644
--- a/lib/stdlib/doc/src/sets.xml
+++ b/lib/stdlib/doc/src/sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2000</year><year>2015</year>
+ <year>2000</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/shell_default.xml b/lib/stdlib/doc/src/shell_default.xml
index 81c99bce10..75bf89ba8d 100644
--- a/lib/stdlib/doc/src/shell_default.xml
+++ b/lib/stdlib/doc/src/shell_default.xml
@@ -51,7 +51,7 @@
<p>In command one, module <seealso marker="lists"><c>lists</c></seealso> is
called. In command two, no module name is specified. The shell searches
module <c>user_default</c> followed by module <c>shell_default</c> for
- function <c>foo/1</c>.</p>
+ function <c>c/1</c>.</p>
<p><c>shell_default</c> is intended for "system wide"
customizations to the shell. <c>user_default</c> is intended for
diff --git a/lib/stdlib/doc/src/stdlib_app.xml b/lib/stdlib/doc/src/stdlib_app.xml
index cde73269a8..f857cc394b 100644
--- a/lib/stdlib/doc/src/stdlib_app.xml
+++ b/lib/stdlib/doc/src/stdlib_app.xml
@@ -31,14 +31,14 @@
<app>STDLIB</app>
<appsummary>The STDLIB application.</appsummary>
<description>
- <p>The <c>STDLIB</c> application is mandatory in the sense that the minimal
- system based on Erlang/OTP consists of <c>Kernel</c> and <c>STDLIB</c>.
- The <c>STDLIB</c> application contains no services.</p>
+ <p>The STDLIB application is mandatory in the sense that the minimal
+ system based on Erlang/OTP consists of Kernel and STDLIB.
+ The STDLIB application contains no services.</p>
</description>
<section>
<title>Configuration</title>
- <p>The following configuration parameters are defined for the <c>STDLIB</c>
+ <p>The following configuration parameters are defined for the STDLIB
application. For more information about configuration parameters, see the
<seealso marker="kernel:app"><c>app(4)</c></seealso> module in Kernel.</p>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 1120b926d5..0fed649660 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2014</year>
+ <year>1996</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -83,8 +83,8 @@
<p>If the modules used to implement the process change dynamically
during runtime, the process must understand one more message. An
example is the <seealso marker="gen_event"><c>gen_event</c></seealso>
- processes. The message is <c>{get_modules, From}</c>.
- The reply to this message is <c>From ! {modules, Modules}</c>, where
+ processes. The message is <c>{_Label, {From, Ref}, get_modules}</c>.
+ The reply to this message is <c>From ! {Ref, Modules}</c>, where
<c>Modules</c> is a list of the currently active modules in the
process.</p>
<p>This message is used by the release handler to find which
diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml
index 8f2ce36b06..fcaccdb2cb 100644
--- a/lib/stdlib/doc/src/timer.xml
+++ b/lib/stdlib/doc/src/timer.xml
@@ -253,7 +253,7 @@
is needed. This is useful during development, but in a
target system the server is to be started explicitly. Use
configuration parameters for
- <seealso marker="kernel:index"><c>Kernel</c></seealso> for this.</p>
+ <seealso marker="kernel:index">Kernel</seealso> for this.</p>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index 7f79ac88a1..efc8b75075 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -274,8 +274,8 @@
marker="stdlib:io"><c>io</c></seealso> module, the file
handling, the <seealso
marker="stdlib:unicode"><c>unicode</c></seealso> module, and
- the bit syntax). Today most modules in <c>Kernel</c> and
- <c>STDLIB</c>, as well as the VM are Unicode-aware.</p>
+ the bit syntax). Today most modules in Kernel and
+ STDLIB, as well as the VM are Unicode-aware.</p>
</item>
<tag>File I/O</tag>
<item>
@@ -765,7 +765,7 @@ Eshell V5.10.1 (abort with ^G)
file system). The Unicode character list is used to denote
filenames or directory names. If the file system content is
listed, you also get Unicode lists as return value. The support
- lies in the <c>Kernel</c> and <c>STDLIB</c> modules, which is why
+ lies in the Kernel and STDLIB modules, which is why
most applications (that does not explicitly require the filenames
to be in the ISO Latin-1 range) benefit from the Unicode support
without change.</p>
@@ -843,7 +843,7 @@ Eshell V5.10.1 (abort with ^G)
<title>Notes About Raw Filenames</title>
<marker id="notes-about-raw-filenames"/>
<p>Raw filenames were introduced together with Unicode filename support
- in <c>ERTS</c> 5.8.2 (Erlang/OTP R14B01). The reason &quot;raw
+ in ERTS 5.8.2 (Erlang/OTP R14B01). The reason &quot;raw
filenames&quot; were introduced in the system was
to be able to represent
filenames, specified in different encodings on the same system,
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index de23608046..0b5eac1e16 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -138,7 +138,7 @@
<p>File information as in
<seealso marker="kernel:file#read_file_info/1">
<c>file:read_file_info/1</c></seealso>
- in <c>Kernel</c></p>
+ in Kernel</p>
</item>
<tag><c>comment</c></tag>
<item>
@@ -345,7 +345,7 @@
prepended to filenames when extracting them from the
zip archive. (Acting like
<seealso marker="kernel:file#set_cwd/1">
- <c>file:set_cwd/1</c></seealso> in <c>Kernel</c>,
+ <c>file:set_cwd/1</c></seealso> in Kernel,
but without changing the global <c>cwd</c> property.)</p>
</item>
</taglist>
@@ -420,7 +420,7 @@
(<c>cwd</c>). This is prepended to filenames when adding them,
although not in the zip archive (acting like
<seealso marker="kernel:file#set_cwd/1">
- <c>file:set_cwd/1</c></seealso> in <c>Kernel</c>, but without
+ <c>file:set_cwd/1</c></seealso> in Kernel, but without
changing the global <c>cwd</c> property.).</p>
</item>
<tag><c>{compress, <anno>What</anno>}</c></tag>
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index fe9df601eb..d7ee5c1f5d 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -55,7 +55,7 @@
-type beam() :: module() | file:filename() | binary().
--type forms() :: [erl_parse:abstract_form()].
+-type forms() :: [erl_parse:abstract_form() | erl_parse:form_info()].
-type abst_code() :: {AbstVersion :: atom(), forms()} | 'no_abstract_code'.
-type dataB() :: binary().
diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl
index ec64470461..a1a97af4c5 100644
--- a/lib/stdlib/src/edlin_expand.erl
+++ b/lib/stdlib/src/edlin_expand.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -101,44 +101,77 @@ match(Prefix, Alts, Extra0) ->
%% Return the list of names L in multiple columns.
format_matches(L) ->
- S = format_col(lists:sort(L), []),
+ {S1, Dots} = format_col(lists:sort(L), []),
+ S = case Dots of
+ true ->
+ {_, Prefix} = longest_common_head(vals(L)),
+ PrefixLen = length(Prefix),
+ case PrefixLen =< 3 of
+ true -> S1; % Do not replace the prefix with "...".
+ false ->
+ LeadingDotsL = leading_dots(L, PrefixLen),
+ {S2, _} = format_col(lists:sort(LeadingDotsL), []),
+ S2
+ end;
+ false -> S1
+ end,
["\n" | S].
format_col([], _) -> [];
-format_col(L, Acc) -> format_col(L, field_width(L), 0, Acc).
-
-format_col(X, Width, Len, Acc) when Width + Len > 79 ->
- format_col(X, Width, 0, ["\n" | Acc]);
-format_col([A|T], Width, Len, Acc0) ->
- H = case A of
- %% If it's a tuple {string(), integer()}, we assume it's an
- %% arity, and meant to be printed.
- {H0, I} when is_integer(I) ->
- H0 ++ "/" ++ integer_to_list(I);
- {H1, _} -> H1;
- H2 -> H2
- end,
- Acc = [io_lib:format("~-*s", [Width,H]) | Acc0],
- format_col(T, Width, Len+Width, Acc);
-format_col([], _, _, Acc) ->
- lists:reverse(Acc, "\n").
-
-field_width(L) -> field_width(L, 0).
-
-field_width([{H,_}|T], W) ->
+format_col(L, Acc) ->
+ LL = 79,
+ format_col(L, field_width(L, LL), 0, Acc, LL, false).
+
+format_col(X, Width, Len, Acc, LL, Dots) when Width + Len > LL ->
+ format_col(X, Width, 0, ["\n" | Acc], LL, Dots);
+format_col([A|T], Width, Len, Acc0, LL, Dots) ->
+ {H0, R} = format_val(A),
+ Hmax = LL - length(R),
+ {H, NewDots} =
+ case length(H0) > Hmax of
+ true -> {io_lib:format("~-*ts", [Hmax - 3, H0]) ++ "...", true};
+ false -> {H0, Dots}
+ end,
+ Acc = [io_lib:format("~-*ts", [Width, H ++ R]) | Acc0],
+ format_col(T, Width, Len+Width, Acc, LL, NewDots);
+format_col([], _, _, Acc, _LL, Dots) ->
+ {lists:reverse(Acc, "\n"), Dots}.
+
+format_val({H, I}) when is_integer(I) ->
+ %% If it's a tuple {string(), integer()}, we assume it's an
+ %% arity, and meant to be printed.
+ {H, "/" ++ integer_to_list(I)};
+format_val({H, _}) ->
+ {H, ""};
+format_val(H) ->
+ {H, ""}.
+
+field_width(L, LL) -> field_width(L, 0, LL).
+
+field_width([{H,_}|T], W, LL) ->
case length(H) of
- L when L > W -> field_width(T, L);
- _ -> field_width(T, W)
+ L when L > W -> field_width(T, L, LL);
+ _ -> field_width(T, W, LL)
end;
-field_width([H|T], W) ->
+field_width([H|T], W, LL) ->
case length(H) of
- L when L > W -> field_width(T, L);
- _ -> field_width(T, W)
+ L when L > W -> field_width(T, L, LL);
+ _ -> field_width(T, W, LL)
end;
-field_width([], W) when W < 40 ->
+field_width([], W, LL) when W < LL - 3 ->
W + 4;
-field_width([], _) ->
- 40.
+field_width([], _, LL) ->
+ LL.
+
+vals([]) -> [];
+vals([{S, _}|L]) -> [S|vals(L)];
+vals([S|L]) -> [S|vals(L)].
+
+leading_dots([], _Len) -> [];
+leading_dots([{H, I}|L], Len) ->
+ [{"..." ++ nthtail(Len, H), I}|leading_dots(L, Len)];
+leading_dots([H|L], Len) ->
+ ["..." ++ nthtail(Len, H)|leading_dots(L, Len)].
longest_common_head([]) ->
no;
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 40a34aa30f..eafee346eb 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -1306,6 +1306,7 @@ partial_eval(Expr) ->
ev_expr({op,_,Op,L,R}) -> erlang:Op(ev_expr(L), ev_expr(R));
ev_expr({op,_,Op,A}) -> erlang:Op(ev_expr(A));
ev_expr({integer,_,X}) -> X;
+ev_expr({char,_,X}) -> X;
ev_expr({float,_,X}) -> X;
ev_expr({atom,_,X}) -> X;
ev_expr({tuple,_,Es}) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 85b2816451..d2dd2848b5 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -156,6 +156,7 @@ type -> '#' atom '{' field_types '}' : {type, ?anno('$1'),
record, ['$2'|'$4']}.
type -> binary_type : '$1'.
type -> integer : '$1'.
+type -> char : '$1'.
type -> 'fun' '(' ')' : {type, ?anno('$1'), 'fun', []}.
type -> 'fun' '(' fun_type_100 ')' : '$3'.
@@ -612,11 +613,11 @@ Erlang code.
| af_bin(abstract_expr())
| af_binary_op(abstract_expr())
| af_unary_op(abstract_expr())
- | af_record_access(abstract_expr())
+ | af_record_creation(abstract_expr())
| af_record_update(abstract_expr())
| af_record_index()
| af_record_field_access(abstract_expr())
- | af_map_access(abstract_expr())
+ | af_map_creation(abstract_expr())
| af_map_update(abstract_expr())
| af_catch()
| af_local_call()
@@ -720,26 +721,25 @@ Erlang code.
| af_bin(af_guard_test())
| af_binary_op(af_guard_test())
| af_unary_op(af_guard_test())
- | af_record_access(af_guard_test())
+ | af_record_creation(af_guard_test())
| af_record_index()
| af_record_field_access(af_guard_test())
- | af_map_access(abstract_expr()) % FIXME
- | af_map_update(abstract_expr()) % FIXME
+ | af_map_creation(abstract_expr())
+ | af_map_update(abstract_expr())
| af_guard_call()
| af_remote_guard_call().
-type af_record_field_access(T) ::
{'record_field', anno(), T, record_name(), af_field_name()}.
--type af_map_access(T) :: {'map', anno(), [af_map_field(T)]}.
-
--type af_map_update(T) :: {'map', anno(), T, [af_map_field(T)]}.
+-type af_map_creation(T) :: {'map', anno(), [af_assoc(T)]}.
--type af_map_field(T) :: af_map_field_assoc(T) | af_map_field_exact(T).
+-type af_map_update(T) :: {'map', anno(), T, [af_assoc(T)]}.
--type af_map_field_assoc(T) :: {'map_field_assoc', anno(), T, T}.
+-type af_assoc(T) :: {'map_field_assoc', anno(), T, T}
+ | af_assoc_exact(T).
--type af_map_field_exact(T) :: {'map_field_exact', anno(), T, T}.
+-type af_assoc_exact(T) :: {'map_field_exact', anno(), T, T}.
-type af_guard_call() :: {'call', anno(), function_name(), [af_guard_test()]}.
@@ -757,20 +757,20 @@ Erlang code.
| af_bin(af_pattern())
| af_binary_op(af_pattern())
| af_unary_op(af_pattern())
- | af_record_access(af_pattern())
+ | af_record_creation(af_pattern())
| af_record_index()
| af_map_pattern().
-type af_record_index() ::
{'record_index', anno(), record_name(), af_field_name()}.
--type af_record_access(T) ::
+-type af_record_creation(T) ::
{'record', anno(), record_name(), [af_record_field(T)]}.
-type af_record_field(T) :: {'record_field', anno(), af_field_name(), T}.
-type af_map_pattern() ::
- {'map', anno(), [af_map_field_exact(abstract_expr)]}. % FIXME?
+ {'map', anno(), [af_assoc_exact(abstract_expr)]}.
-type abstract_type() :: af_annotated_type()
| af_atom()
@@ -807,9 +807,9 @@ Erlang code.
{'type', anno(), 'range', [af_singleton_integer_type()]}.
-type af_map_type() :: {'type', anno(), 'map', 'any'}
- | {'type', anno(), 'map', [af_map_pair_type()]}.
+ | {'type', anno(), 'map', [af_assoc_type()]}.
--type af_map_pair_type() ::
+-type af_assoc_type() ::
{'type', anno(), 'map_field_assoc', [abstract_type()]}
| {'type', anno(), 'map_field_exact', [abstract_type()]}.
@@ -1558,13 +1558,17 @@ new_anno(Term) ->
Abstr :: erl_parse_tree().
anno_to_term(Abstract) ->
- map_anno(fun erl_anno:to_term/1, Abstract).
+ F = fun(Anno, Acc) -> {erl_anno:to_term(Anno), Acc} end,
+ {NewAbstract, []} = modify_anno1(Abstract, [], F),
+ NewAbstract.
-spec anno_from_term(Term) -> erl_parse_tree() when
Term :: term().
anno_from_term(Term) ->
- map_anno(fun erl_anno:from_term/1, Term).
+ F = fun(T, Acc) -> {erl_anno:from_term(T), Acc} end,
+ {NewTerm, []} = modify_anno1(Term, [], F),
+ NewTerm.
%% Forms.
%% Recognize what sys_pre_expand does:
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index f53b0e2246..c42ae981e7 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -481,46 +481,49 @@ find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, Sections) ->
%% Look for special comment on second line
Line2 = get_line(Fd),
{ok, HeaderSz2} = file:position(Fd, cur),
- case classify_line(Line2) of
- emu_args ->
- %% Skip special comment on second line
- Line3 = get_line(Fd),
- {HeaderSz2, LineNo + 2, Fd,
- Sections#sections{type = guess_type(Line3),
- comment = undefined,
- emu_args = Line2}};
- Line2Type ->
- %% Look for special comment on third line
- Line3 = get_line(Fd),
- {ok, HeaderSz3} = file:position(Fd, cur),
- Line3Type = classify_line(Line3),
- if
- Line3Type =:= emu_args ->
- %% Skip special comment on third line
- Line4 = get_line(Fd),
- {HeaderSz3, LineNo + 3, Fd,
- Sections#sections{type = guess_type(Line4),
- comment = Line2,
- emu_args = Line3}};
- Sections#sections.shebang =:= undefined,
- KeepFirst =:= true ->
- %% No shebang. Use the entire file
- {HeaderSz0, LineNo, Fd,
- Sections#sections{type = guess_type(Line2)}};
- Sections#sections.shebang =:= undefined ->
- %% No shebang. Skip the first line
- {HeaderSz1, LineNo, Fd,
- Sections#sections{type = guess_type(Line2)}};
- Line2Type =:= comment ->
- %% Skip shebang on first line and comment on second
- {HeaderSz2, LineNo + 2, Fd,
- Sections#sections{type = guess_type(Line3),
- comment = Line2}};
- true ->
- %% Just skip shebang on first line
- {HeaderSz1, LineNo + 1, Fd,
- Sections#sections{type = guess_type(Line2)}}
- end
+ if
+ Sections#sections.shebang =:= undefined,
+ KeepFirst =:= true ->
+ %% No shebang. Use the entire file
+ {HeaderSz0, LineNo, Fd,
+ Sections#sections{type = guess_type(Line2)}};
+ Sections#sections.shebang =:= undefined ->
+ %% No shebang. Skip the first line
+ {HeaderSz1, LineNo, Fd,
+ Sections#sections{type = guess_type(Line2)}};
+ true ->
+ case classify_line(Line2) of
+ emu_args ->
+ %% Skip special comment on second line
+ Line3 = get_line(Fd),
+ {HeaderSz2, LineNo + 2, Fd,
+ Sections#sections{type = guess_type(Line3),
+ comment = undefined,
+ emu_args = Line2}};
+ comment ->
+ %% Look for special comment on third line
+ Line3 = get_line(Fd),
+ {ok, HeaderSz3} = file:position(Fd, cur),
+ Line3Type = classify_line(Line3),
+ if
+ Line3Type =:= emu_args ->
+ %% Skip special comment on third line
+ Line4 = get_line(Fd),
+ {HeaderSz3, LineNo + 3, Fd,
+ Sections#sections{type = guess_type(Line4),
+ comment = Line2,
+ emu_args = Line3}};
+ true ->
+ %% Skip shebang on first line and comment on second
+ {HeaderSz2, LineNo + 2, Fd,
+ Sections#sections{type = guess_type(Line3),
+ comment = Line2}}
+ end;
+ _ ->
+ %% Just skip shebang on first line
+ {HeaderSz1, LineNo + 1, Fd,
+ Sections#sections{type = guess_type(Line2)}}
+ end
end.
classify_line(Line) ->
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 3f74e01692..20de06fd0b 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -232,20 +232,20 @@ match(_) ->
match_object(_, _) ->
erlang:nif_error(undef).
--spec match_object(Tab, Pattern, Limit) -> {[Match], Continuation} |
+-spec match_object(Tab, Pattern, Limit) -> {[Object], Continuation} |
'$end_of_table' when
Tab :: tab(),
Pattern :: match_pattern(),
Limit :: pos_integer(),
- Match :: [term()],
+ Object :: tuple(),
Continuation :: continuation().
match_object(_, _, _) ->
erlang:nif_error(undef).
--spec match_object(Continuation) -> {[Match], Continuation} |
+-spec match_object(Continuation) -> {[Object], Continuation} |
'$end_of_table' when
- Match :: [term()],
+ Object :: tuple(),
Continuation :: continuation().
match_object(_) ->
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index c4586171ca..9eeba874e1 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,8 @@
-export([absname/1, absname/2, absname_join/2,
basename/1, basename/2, dirname/1,
extension/1, join/1, join/2, pathtype/1,
- rootname/1, rootname/2, split/1, nativename/1]).
+ rootname/1, rootname/2, split/1, nativename/1,
+ safe_relative_path/1]).
-export([find_src/1, find_src/2, flatten/1]).
-export([basedir/2, basedir/3]).
@@ -750,6 +751,39 @@ separators() ->
_ -> {false, false}
end.
+-spec safe_relative_path(Filename) -> 'unsafe' | SafeFilename when
+ Filename :: file:name_all(),
+ SafeFilename :: file:name_all().
+
+safe_relative_path(Path) ->
+ case pathtype(Path) of
+ relative ->
+ Cs0 = split(Path),
+ safe_relative_path_1(Cs0, []);
+ _ ->
+ unsafe
+ end.
+
+safe_relative_path_1(["."|T], Acc) ->
+ safe_relative_path_1(T, Acc);
+safe_relative_path_1([<<".">>|T], Acc) ->
+ safe_relative_path_1(T, Acc);
+safe_relative_path_1([".."|T], Acc) ->
+ climb(T, Acc);
+safe_relative_path_1([<<"..">>|T], Acc) ->
+ climb(T, Acc);
+safe_relative_path_1([H|T], Acc) ->
+ safe_relative_path_1(T, [H|Acc]);
+safe_relative_path_1([], []) ->
+ [];
+safe_relative_path_1([], Acc) ->
+ join(lists:reverse(Acc)).
+
+climb(_, []) ->
+ unsafe;
+climb(T, [_|Acc]) ->
+ safe_relative_path_1(T, Acc).
+
%% find_src(Module) --
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index ccacf658e9..0ded1e9fa6 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -742,7 +742,7 @@ stop_handlers([], _) ->
[].
%% Message from the release_handler.
-%% The list of modules got to be a set !
+%% The list of modules got to be a set, i.e. no duplicate elements!
get_modules(MSL) ->
Mods = [Handler#handler.module || Handler <- MSL],
ordsets:to_list(ordsets:from_list(Mods)).
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 23bddafeed..cacc932ec4 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
[start/3,start/4,start_link/3,start_link/4,
stop/1,stop/3,
cast/2,call/2,call/3,
- enter_loop/5,enter_loop/6,enter_loop/7,
+ enter_loop/4,enter_loop/5,enter_loop/6,
reply/1,reply/2]).
%% gen callbacks
@@ -44,15 +44,22 @@
-export(
[wakeup_from_hibernate/3]).
-%% Type exports for templates
+%% Type exports for templates and callback modules
-export_type(
[event_type/0,
- callback_mode/0,
- state_function_result/0,
- handle_event_result/0,
+ callback_mode_result/0,
+ init_result/1,
+ state_enter_result/1,
+ event_handler_result/1,
+ reply_action/0,
+ enter_action/0,
action/0]).
+%% Old types, not advertised
+-export_type(
+ [state_function_result/0,
+ handle_event_result/0]).
-%% Fix problem for doc build
+%% Type that is exported just to be documented
-export_type([transition_option/0]).
%%%==========================================================================
@@ -63,8 +70,8 @@
{To :: pid(), Tag :: term()}. % Reply-to specifier for call
-type state() ::
- state_name() | % For state callback function StateName/5
- term(). % For state callback function handle_event/5
+ state_name() | % For StateName/3 callback functions
+ term(). % For handle_event/4 callback function
-type state_name() :: atom().
@@ -72,12 +79,16 @@
-type event_type() ::
{'call',From :: from()} | 'cast' |
- 'info' | 'timeout' | 'internal'.
+ 'info' | 'timeout' | 'state_timeout' | 'internal'.
+-type callback_mode_result() ::
+ callback_mode() | [callback_mode() | state_enter()].
-type callback_mode() :: 'state_functions' | 'handle_event_function'.
+-type state_enter() :: 'state_enter'.
-type transition_option() ::
- postpone() | hibernate() | event_timeout().
+ postpone() | hibernate() |
+ event_timeout() | state_timeout().
-type postpone() ::
%% If 'true' postpone the current event
%% and retry it when the state changes (=/=)
@@ -89,6 +100,10 @@
%% Generate a ('timeout', EventContent, ...) event after Time
%% unless some other event is delivered
Time :: timeout().
+-type state_timeout() ::
+ %% Generate a ('state_timeout', EventContent, ...) event after Time
+ %% unless the state is changed
+ Time :: timeout().
-type action() ::
%% During a state change:
@@ -96,7 +111,7 @@
%% * All action()s are executed in order of apperance.
%% * Postponing the current event is performed
%% iff 'postpone' is 'true'.
- %% * A state timer is started iff 'timeout' is set.
+ %% * A state timeout is started iff 'timeout' is set.
%% * Pending events are handled or if there are
%% no pending events the server goes into receive
%% or hibernate (iff 'hibernate' is 'true')
@@ -108,100 +123,137 @@
'postpone' | % Set the postpone option
{'postpone', Postpone :: postpone()} |
%%
+ %% All 'next_event' events are kept in a list and then
+ %% inserted at state changes so the first in the
+ %% action() list is the first to be delivered.
+ {'next_event', % Insert event as the next to handle
+ EventType :: event_type(),
+ EventContent :: term()} |
+ enter_action().
+-type enter_action() ::
'hibernate' | % Set the hibernate option
{'hibernate', Hibernate :: hibernate()} |
%%
(Timeout :: event_timeout()) | % {timeout,Timeout}
- {'timeout', % Set the event timeout option
+ {'timeout', % Set the event_timeout option
Time :: event_timeout(), EventContent :: term()} |
+ {'state_timeout', % Set the state_timeout option
+ Time :: state_timeout(), EventContent :: term()} |
%%
- reply_action() |
- %%
- %% All 'next_event' events are kept in a list and then
- %% inserted at state changes so the first in the
- %% action() list is the first to be delivered.
- {'next_event', % Insert event as the next to handle
- EventType :: event_type(),
- EventContent :: term()}.
+ reply_action().
-type reply_action() ::
{'reply', % Reply to a caller
From :: from(), Reply :: term()}.
+-type init_result(StateType) ::
+ {ok, State :: StateType, Data :: data()} |
+ {ok, State :: StateType, Data :: data(),
+ Actions :: [action()] | action()} |
+ 'ignore' |
+ {'stop', Reason :: term()}.
+
+%% Old, not advertised
-type state_function_result() ::
- {'next_state', % {next_state,NextStateName,NewData,[]}
- NextStateName :: state_name(),
+ event_handler_result(state_name()).
+-type handle_event_result() ::
+ event_handler_result(state()).
+%%
+-type state_enter_result(State) ::
+ {'next_state', % {next_state,NextState,NewData,[]}
+ State,
NewData :: data()} |
{'next_state', % State transition, maybe to the same state
- NextStateName :: state_name(),
+ State,
NewData :: data(),
- Actions :: [action()] | action()} |
- common_state_callback_result().
--type handle_event_result() ::
+ Actions :: [enter_action()] | enter_action()} |
+ state_callback_result(enter_action()).
+-type event_handler_result(StateType) ::
{'next_state', % {next_state,NextState,NewData,[]}
- NextState :: state(),
+ NextState :: StateType,
NewData :: data()} |
{'next_state', % State transition, maybe to the same state
- NextState :: state(),
+ NextState :: StateType,
NewData :: data(),
Actions :: [action()] | action()} |
- common_state_callback_result().
--type common_state_callback_result() ::
+ state_callback_result(action()).
+-type state_callback_result(ActionType) ::
+ {'keep_state', % {keep_state,NewData,[]}
+ NewData :: data()} |
+ {'keep_state', % Keep state, change data
+ NewData :: data(),
+ Actions :: [ActionType] | ActionType} |
+ 'keep_state_and_data' | % {keep_state_and_data,[]}
+ {'keep_state_and_data', % Keep state and data -> only actions
+ Actions :: [ActionType] | ActionType} |
+ %%
+ {'repeat_state', % {repeat_state,NewData,[]}
+ NewData :: data()} |
+ {'repeat_state', % Repeat state, change data
+ NewData :: data(),
+ Actions :: [ActionType] | ActionType} |
+ 'repeat_state_and_data' | % {repeat_state_and_data,[]}
+ {'repeat_state_and_data', % Repeat state and data -> only actions
+ Actions :: [ActionType] | ActionType} |
+ %%
'stop' | % {stop,normal}
{'stop', % Stop the server
Reason :: term()} |
{'stop', % Stop the server
Reason :: term(),
NewData :: data()} |
+ %%
{'stop_and_reply', % Reply then stop the server
Reason :: term(),
Replies :: [reply_action()] | reply_action()} |
{'stop_and_reply', % Reply then stop the server
Reason :: term(),
Replies :: [reply_action()] | reply_action(),
- NewData :: data()} |
- {'keep_state', % {keep_state,NewData,[]}
- NewData :: data()} |
- {'keep_state', % Keep state, change data
- NewData :: data(),
- Actions :: [action()] | action()} |
- 'keep_state_and_data' | % {keep_state_and_data,[]}
- {'keep_state_and_data', % Keep state and data -> only actions
- Actions :: [action()] | action()}.
+ NewData :: data()}.
%% The state machine init function. It is called only once and
%% the server is not running until this function has returned
%% an {ok, ...} tuple. Thereafter the state callbacks are called
%% for all events to this server.
--callback init(Args :: term()) ->
- {callback_mode(), state(), data()} |
- {callback_mode(), state(), data(), [action()] | action()} |
- 'ignore' |
- {'stop', Reason :: term()}.
+-callback init(Args :: term()) -> init_result(state()).
+
+%% This callback shall return the callback mode of the callback module.
+%%
+%% It is called once after init/0 and code_change/4 but before
+%% the first state callback StateName/3 or handle_event/4.
+-callback callback_mode() -> callback_mode_result().
-%% Example state callback for callback_mode() =:= state_functions
-%% state name 'state_name'.
+%% Example state callback for StateName = 'state_name'
+%% when callback_mode() =:= state_functions.
%%
-%% In this mode all states has to be type state_name() i.e atom().
+%% In this mode all states has to be of type state_name() i.e atom().
%%
-%% Note that state callbacks and only state callbacks have arity 5
-%% and that is intended.
+%% Note that the only callbacks that have arity 3 are these
+%% StateName/3 callbacks and terminate/3, so the state name
+%% 'terminate' is unusable in this mode.
-callback state_name(
- event_type(),
+ 'enter',
+ OldStateName :: state_name(),
+ Data :: data()) ->
+ state_enter_result('state_name');
+ (event_type(),
EventContent :: term(),
Data :: data()) ->
- state_function_result().
+ event_handler_result(state_name()).
%%
-%% State callback for callback_mode() =:= handle_event_function.
-%%
-%% Note that state callbacks and only state callbacks have arity 5
-%% and that is intended.
+%% State callback for all states
+%% when callback_mode() =:= handle_event_function.
-callback handle_event(
- event_type(),
+ 'enter',
+ OldState :: state(),
+ State, % Current state
+ Data :: data()) ->
+ state_enter_result(State);
+ (event_type(),
EventContent :: term(),
State :: state(), % Current state
Data :: data()) ->
- handle_event_result().
+ event_handler_result(state()).
%% Clean up before the server terminates.
-callback terminate(
@@ -219,9 +271,8 @@
OldState :: state(),
OldData :: data(),
Extra :: term()) ->
- {NewCallbackMode :: callback_mode(),
- NewState :: state(),
- NewData :: data()}.
+ {ok, NewState :: state(), NewData :: data()} |
+ (Reason :: term()).
%% Format the callback module state in some sensible that is
%% often condensed way. For StatusOption =:= 'normal' the perferred
@@ -238,11 +289,16 @@
-optional_callbacks(
[init/1, % One may use enter_loop/5,6,7 instead
format_status/2, % Has got a default implementation
+ terminate/3, % Has got a default implementation
+ code_change/4, % Only needed by advanced soft upgrade
%%
- state_name/3, % Example for callback_mode =:= state_functions:
- %% there has to be a StateName/5 callback function for every StateName.
+ state_name/3, % Example for callback_mode() =:= state_functions:
+ %% there has to be a StateName/3 callback function
+ %% for every StateName in your state machine but the state name
+ %% 'state_name' does of course not have to be used.
%%
- handle_event/4]). % For callback_mode =:= handle_event_function
+ handle_event/4 % For callback_mode() =:= handle_event_function
+ ]).
%% Type validation functions
callback_mode(CallbackMode) ->
@@ -264,12 +320,16 @@ event_type({call,From}) ->
from(From);
event_type(Type) ->
case Type of
+ {call,From} ->
+ from(From);
cast ->
true;
info ->
true;
timeout ->
true;
+ state_timeout ->
+ true;
internal ->
true;
_ ->
@@ -378,53 +438,79 @@ call(ServerRef, Request) ->
-spec call(
ServerRef :: server_ref(),
Request :: term(),
- Timeout :: timeout()) ->
+ Timeout ::
+ timeout() |
+ {'clean_timeout',T :: timeout()} |
+ {'dirty_timeout',T :: timeout()}) ->
Reply :: term().
-call(ServerRef, Request, infinity) ->
- try gen:call(ServerRef, '$gen_call', Request, infinity) of
- {ok,Reply} ->
- Reply
- catch
- Class:Reason ->
- erlang:raise(
- Class,
- {Reason,{?MODULE,call,[ServerRef,Request,infinity]}},
- erlang:get_stacktrace())
- end;
call(ServerRef, Request, Timeout) ->
- %% Call server through proxy process to dodge any late reply
- Ref = make_ref(),
- Self = self(),
- Pid = spawn(
- fun () ->
- Self !
- try gen:call(
- ServerRef, '$gen_call', Request, Timeout) of
- Result ->
- {Ref,Result}
- catch Class:Reason ->
- {Ref,Class,Reason,erlang:get_stacktrace()}
- end
- end),
- Mref = monitor(process, Pid),
- receive
- {Ref,Result} ->
- demonitor(Mref, [flush]),
- case Result of
+ case parse_timeout(Timeout) of
+ {dirty_timeout,T} ->
+ try gen:call(ServerRef, '$gen_call', Request, T) of
{ok,Reply} ->
Reply
+ catch
+ Class:Reason ->
+ erlang:raise(
+ Class,
+ {Reason,{?MODULE,call,[ServerRef,Request,Timeout]}},
+ erlang:get_stacktrace())
+ end;
+ {clean_timeout,T} ->
+ %% Call server through proxy process to dodge any late reply
+ Ref = make_ref(),
+ Self = self(),
+ Pid = spawn(
+ fun () ->
+ Self !
+ try gen:call(
+ ServerRef, '$gen_call', Request, T) of
+ Result ->
+ {Ref,Result}
+ catch Class:Reason ->
+ {Ref,Class,Reason,
+ erlang:get_stacktrace()}
+ end
+ end),
+ Mref = monitor(process, Pid),
+ receive
+ {Ref,Result} ->
+ demonitor(Mref, [flush]),
+ case Result of
+ {ok,Reply} ->
+ Reply
+ end;
+ {Ref,Class,Reason,Stacktrace} ->
+ demonitor(Mref, [flush]),
+ erlang:raise(
+ Class,
+ {Reason,{?MODULE,call,[ServerRef,Request,Timeout]}},
+ Stacktrace);
+ {'DOWN',Mref,_,_,Reason} ->
+ %% There is a theoretical possibility that the
+ %% proxy process gets killed between try--of and !
+ %% so this clause is in case of that
+ exit(Reason)
end;
- {Ref,Class,Reason,Stacktrace} ->
- demonitor(Mref, [flush]),
- erlang:raise(
- Class,
- {Reason,{?MODULE,call,[ServerRef,Request,Timeout]}},
- Stacktrace);
- {'DOWN',Mref,_,_,Reason} ->
- %% There is a theoretical possibility that the
- %% proxy process gets killed between try--of and !
- %% so this clause is in case of that
- exit(Reason)
+ Error when is_atom(Error) ->
+ erlang:error(Error, [ServerRef,Request,Timeout])
+ end.
+
+parse_timeout(Timeout) ->
+ case Timeout of
+ {clean_timeout,infinity} ->
+ {dirty_timeout,infinity};
+ {clean_timeout,_} ->
+ Timeout;
+ {dirty_timeout,_} ->
+ Timeout;
+ {_,_} ->
+ %% Be nice and throw a badarg for speling errors
+ badarg;
+ infinity ->
+ {dirty_timeout,infinity};
+ T ->
+ {clean_timeout,T}
end.
%% Reply from a state machine callback to whom awaits in call/2
@@ -450,43 +536,35 @@ reply({To,Tag}, Reply) when is_pid(To) ->
%% the same arguments as you would have returned from init/1
-spec enter_loop(
Module :: module(), Opts :: [debug_opt()],
- CallbackMode :: callback_mode(),
State :: state(), Data :: data()) ->
no_return().
-enter_loop(Module, Opts, CallbackMode, State, Data) ->
- enter_loop(Module, Opts, CallbackMode, State, Data, self()).
+enter_loop(Module, Opts, State, Data) ->
+ enter_loop(Module, Opts, State, Data, self()).
%%
-spec enter_loop(
Module :: module(), Opts :: [debug_opt()],
- CallbackMode :: callback_mode(),
State :: state(), Data :: data(),
Server_or_Actions ::
server_name() | pid() | [action()]) ->
no_return().
-enter_loop(Module, Opts, CallbackMode, State, Data, Server_or_Actions) ->
+enter_loop(Module, Opts, State, Data, Server_or_Actions) ->
if
is_list(Server_or_Actions) ->
- enter_loop(
- Module, Opts, CallbackMode, State, Data,
- self(), Server_or_Actions);
+ enter_loop(Module, Opts, State, Data, self(), Server_or_Actions);
true ->
- enter_loop(
- Module, Opts, CallbackMode, State, Data,
- Server_or_Actions, [])
+ enter_loop(Module, Opts, State, Data, Server_or_Actions, [])
end.
%%
-spec enter_loop(
Module :: module(), Opts :: [debug_opt()],
- CallbackMode :: callback_mode(),
State :: state(), Data :: data(),
Server :: server_name() | pid(),
Actions :: [action()] | action()) ->
no_return().
-enter_loop(Module, Opts, CallbackMode, State, Data, Server, Actions) ->
+enter_loop(Module, Opts, State, Data, Server, Actions) ->
is_atom(Module) orelse error({atom,Module}),
- callback_mode(CallbackMode) orelse error({callback_mode,CallbackMode}),
Parent = gen:get_parent(),
- enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent).
+ enter(Module, Opts, State, Data, Server, Actions, Parent).
%%---------------------------------------------------------------------------
%% API helpers
@@ -514,12 +592,13 @@ send(Proc, Msg) ->
end.
%% Here the init_it/6 and enter_loop/5,6,7 functions converge
-enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) ->
+enter(Module, Opts, State, Data, Server, Actions, Parent) ->
%% The values should already have been type checked
Name = gen:get_proc_name(Server),
Debug = gen:debug_options(Name, Opts),
- P = Events = [],
- Event = {internal,initial_state},
+ Events = [],
+ P = [],
+ Event = {internal,init_state},
%% We enforce {postpone,false} to ensure that
%% our fake Event gets discarded, thought it might get logged
NewActions =
@@ -529,21 +608,50 @@ enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) ->
true ->
[Actions,{postpone,false}]
end,
+ TimerRefs = #{},
+ %% Key: timer ref
+ %% Value: the timer type i.e the timer's event type
+ %%
+ TimerTypes = #{},
+ %% Key: timer type i.e the timer's event type
+ %% Value: timer ref
+ %%
+ %% We add a timer to both timer_refs and timer_types
+ %% when we start it. When we request an asynchronous
+ %% timer cancel we remove it from timer_types. When
+ %% the timer cancel message arrives we remove it from
+ %% timer_refs.
+ %%
+ Hibernate = false,
+ CancelTimers = 0,
S = #{
- callback_mode => CallbackMode,
+ callback_mode => undefined,
+ state_enter => false,
module => Module,
name => Name,
- %% All fields below will be replaced according to the arguments to
- %% loop_event_actions/10 when it finally loops back to loop/3
state => State,
data => Data,
postponed => P,
- hibernate => false,
- timer => undefined},
+ %%
+ %% The following fields are finally set from to the arguments to
+ %% loop_event_actions/9 when it finally loops back to loop/3
+ %% in loop_event_result/11
+ timer_refs => TimerRefs,
+ timer_types => TimerTypes,
+ hibernate => Hibernate,
+ cancel_timers => CancelTimers
+ },
NewDebug = sys_debug(Debug, S, State, {enter,Event,State}),
- loop_event_actions(
- Parent, NewDebug, S, Events,
- State, Data, P, Event, State, NewActions).
+ case call_callback_mode(S) of
+ {ok,NewS} ->
+ loop_event_actions(
+ Parent, NewDebug, NewS,
+ Events, Event, State, Data, NewActions, true);
+ {Class,Reason,Stacktrace} ->
+ terminate(
+ Class, Reason, Stacktrace, NewDebug,
+ S, [Event|Events])
+ end.
%%%==========================================================================
%%% gen callbacks
@@ -558,9 +666,17 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
Result ->
init_result(Starter, Parent, ServerRef, Module, Result, Opts);
Class:Reason ->
+ Stacktrace = erlang:get_stacktrace(),
+ Name = gen:get_proc_name(ServerRef),
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ error_info(
+ Class, Reason, Stacktrace,
+ #{name => Name,
+ callback_mode => undefined,
+ state_enter => false},
+ [], [], undefined),
+ erlang:raise(Class, Reason, Stacktrace)
end.
%%---------------------------------------------------------------------------
@@ -568,30 +684,12 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
case Result of
- {CallbackMode,State,Data} ->
- case callback_mode(CallbackMode) of
- true ->
- proc_lib:init_ack(Starter, {ok,self()}),
- enter(
- Module, Opts, CallbackMode, State, Data,
- ServerRef, [], Parent);
- false ->
- Error = {callback_mode,CallbackMode},
- proc_lib:init_ack(Starter, {error,Error}),
- exit(Error)
- end;
- {CallbackMode,State,Data,Actions} ->
- case callback_mode(CallbackMode) of
- true ->
- proc_lib:init_ack(Starter, {ok,self()}),
- enter(
- Module, Opts, CallbackMode, State, Data,
- ServerRef, Actions, Parent);
- false ->
- Error = {callback_mode,CallbackMode},
- proc_lib:init_ack(Starter, {error,Error}),
- exit(Error)
- end;
+ {ok,State,Data} ->
+ proc_lib:init_ack(Starter, {ok,self()}),
+ enter(Module, Opts, State, Data, ServerRef, [], Parent);
+ {ok,State,Data,Actions} ->
+ proc_lib:init_ack(Starter, {ok,self()}),
+ enter(Module, Opts, State, Data, ServerRef, Actions, Parent);
{stop,Reason} ->
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
@@ -601,8 +699,16 @@ init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
proc_lib:init_ack(Starter, ignore),
exit(normal);
_ ->
- Error = {bad_return_value,Result},
+ Name = gen:get_proc_name(ServerRef),
+ gen:unregister_name(ServerRef),
+ Error = {bad_return_from_init,Result},
proc_lib:init_ack(Starter, {error,Error}),
+ error_info(
+ error, Error, ?STACKTRACE(),
+ #{name => Name,
+ callback_mode => undefined,
+ state_enter => false},
+ [], [], undefined),
exit(Error)
end.
@@ -612,12 +718,8 @@ init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
system_continue(Parent, Debug, S) ->
loop(Parent, Debug, S).
-system_terminate(
- Reason, _Parent, Debug,
- #{state := State, data := Data, postponed := P} = S) ->
- terminate(
- exit, Reason, ?STACKTRACE(),
- Debug, S, [], State, Data, P).
+system_terminate(Reason, _Parent, Debug, S) ->
+ terminate(exit, Reason, ?STACKTRACE(), Debug, S, []).
system_code_change(
#{module := Module,
@@ -630,11 +732,9 @@ system_code_change(
Result -> Result
end
of
- {NewCallbackMode,NewState,NewData} ->
- callback_mode(NewCallbackMode) orelse
- error({callback_mode,NewCallbackMode}),
+ {ok,NewState,NewData} ->
{ok,
- S#{callback_mode := NewCallbackMode,
+ S#{callback_mode := undefined,
state := NewState,
data := NewData}};
{ok,_} = Error ->
@@ -656,7 +756,7 @@ system_replace_state(
format_status(
Opt,
[PDict,SysState,Parent,Debug,
- #{name := Name, postponed := P, state := State, data := Data} = S]) ->
+ #{name := Name, postponed := P} = S]) ->
Header = gen:format_status_header("Status for state machine", Name),
Log = sys:get_debug(log, Debug, []),
[{header,Header},
@@ -665,7 +765,7 @@ format_status(
{"Parent",Parent},
{"Logged Events",Log},
{"Postponed",P}]} |
- case format_status(Opt, PDict, S, State, Data) of
+ case format_status(Opt, PDict, S) of
L when is_list(L) -> L;
T -> [T]
end].
@@ -675,14 +775,18 @@ format_status(
%% them, not as the real erlang messages. Use trace for that.
%%---------------------------------------------------------------------------
-print_event(Dev, {in,Event}, {Name,_}) ->
+print_event(Dev, {in,Event}, {Name,State}) ->
+ io:format(
+ Dev, "*DBG* ~p receive ~s in state ~p~n",
+ [Name,event_string(Event),State]);
+print_event(Dev, {out,Reply,{To,_Tag}}, {Name,State}) ->
io:format(
- Dev, "*DBG* ~p received ~s~n",
- [Name,event_string(Event)]);
-print_event(Dev, {out,Reply,{To,_Tag}}, {Name,_}) ->
+ Dev, "*DBG* ~p send ~p to ~p from state ~p~n",
+ [Name,Reply,To,State]);
+print_event(Dev, {terminate,Reason}, {Name,State}) ->
io:format(
- Dev, "*DBG* ~p sent ~p to ~p~n",
- [Name,Reply,To]);
+ Dev, "*DBG* ~p terminate ~p in state ~p~n",
+ [Name,Reason,State]);
print_event(Dev, {Tag,Event,NextState}, {Name,State}) ->
StateString =
case NextState of
@@ -726,22 +830,22 @@ wakeup_from_hibernate(Parent, Debug, S) ->
%% and detours through sys:handle_system_message/7 and proc_lib:hibernate/3
%% Entry point for system_continue/3
-loop(Parent, Debug, #{hibernate := Hibernate} = S) ->
- case Hibernate of
- true ->
- %% Does not return but restarts process at
- %% wakeup_from_hibernate/3 that jumps to loop_receive/3
- proc_lib:hibernate(
- ?MODULE, wakeup_from_hibernate, [Parent,Debug,S]),
- error(
- {should_not_have_arrived_here_but_instead_in,
- {wakeup_from_hibernate,3}});
- false ->
- loop_receive(Parent, Debug, S)
- end.
+loop(Parent, Debug, #{hibernate := true, cancel_timers := 0} = S) ->
+ loop_hibernate(Parent, Debug, S);
+loop(Parent, Debug, S) ->
+ loop_receive(Parent, Debug, S).
+
+loop_hibernate(Parent, Debug, S) ->
+ %% Does not return but restarts process at
+ %% wakeup_from_hibernate/3 that jumps to loop_receive/3
+ proc_lib:hibernate(
+ ?MODULE, wakeup_from_hibernate, [Parent,Debug,S]),
+ error(
+ {should_not_have_arrived_here_but_instead_in,
+ {wakeup_from_hibernate,3}}).
%% Entry point for wakeup_from_hibernate/3
-loop_receive(Parent, Debug, #{timer := Timer} = S) ->
+loop_receive(Parent, Debug, S) ->
receive
Msg ->
case Msg of
@@ -750,36 +854,87 @@ loop_receive(Parent, Debug, #{timer := Timer} = S) ->
%% Does not return but tail recursively calls
%% system_continue/3 that jumps to loop/3
sys:handle_system_msg(
- Req, Pid, Parent, ?MODULE, Debug, S, Hibernate);
+ Req, Pid, Parent, ?MODULE, Debug, S,
+ Hibernate);
{'EXIT',Parent,Reason} = EXIT ->
- #{state := State, data := Data, postponed := P} = S,
- %% EXIT is not a 2-tuple and therefore
- %% not an event and has no event_type(),
- %% but this will stand out in the crash report...
- terminate(
- exit, Reason, ?STACKTRACE(),
- Debug, S, [EXIT], State, Data, P);
- {timeout,Timer,Content} when Timer =/= undefined ->
- loop_receive_result(
- Parent, Debug, S, {timeout,Content});
- _ ->
- %% Cancel Timer if running
- case Timer of
- undefined ->
- ok;
+ %% EXIT is not a 2-tuple therefore
+ %% not an event but this will stand out
+ %% in the crash report...
+ Q = [EXIT],
+ terminate(exit, Reason, ?STACKTRACE(), Debug, S, Q);
+ {timeout,TimerRef,TimerMsg} ->
+ #{timer_refs := TimerRefs,
+ timer_types := TimerTypes,
+ hibernate := Hibernate} = S,
+ case TimerRefs of
+ #{TimerRef := TimerType} ->
+ %% We know of this timer; is it a running
+ %% timer or a timer being cancelled that
+ %% managed to send a late timeout message?
+ case TimerTypes of
+ #{TimerType := TimerRef} ->
+ %% The timer type maps back to this
+ %% timer ref, so it was a running timer
+ Event = {TimerType,TimerMsg},
+ %% Unregister the triggered timeout
+ NewTimerRefs =
+ maps:remove(TimerRef, TimerRefs),
+ NewTimerTypes =
+ maps:remove(TimerType, TimerTypes),
+ loop_receive_result(
+ Parent, Debug,
+ S#{
+ timer_refs := NewTimerRefs,
+ timer_types := NewTimerTypes},
+ Hibernate,
+ Event);
+ _ ->
+ %% This was a late timeout message
+ %% from timer being cancelled, so
+ %% ignore it and expect a cancel_timer
+ %% msg shortly
+ loop_receive(Parent, Debug, S)
+ end;
+ _ ->
+ %% Not our timer; present it as an event
+ Event = {info,Msg},
+ loop_receive_result(
+ Parent, Debug, S, Hibernate, Event)
+ end;
+ {cancel_timer,TimerRef,_} ->
+ #{timer_refs := TimerRefs,
+ cancel_timers := CancelTimers,
+ hibernate := Hibernate} = S,
+ case TimerRefs of
+ #{TimerRef := _} ->
+ %% We must have requested a cancel
+ %% of this timer so it is already
+ %% removed from TimerTypes
+ NewTimerRefs =
+ maps:remove(TimerRef, TimerRefs),
+ NewCancelTimers = CancelTimers - 1,
+ NewS =
+ S#{
+ timer_refs := NewTimerRefs,
+ cancel_timers := NewCancelTimers},
+ if
+ Hibernate =:= true, NewCancelTimers =:= 0 ->
+ %% No more cancel_timer msgs to expect;
+ %% we can hibernate
+ loop_hibernate(Parent, Debug, NewS);
+ NewCancelTimers >= 0 -> % Assert
+ loop_receive(Parent, Debug, NewS)
+ end;
_ ->
- case erlang:cancel_timer(Timer) of
- TimeLeft when is_integer(TimeLeft) ->
- ok;
- false ->
- receive
- {timeout,Timer,_} ->
- ok
- after 0 ->
- ok
- end
- end
- end,
+ %% Not our cancel_timer msg;
+ %% present it as an event
+ Event = {info,Msg},
+ loop_receive_result(
+ Parent, Debug, S, Hibernate, Event)
+ end;
+ _ ->
+ %% External msg
+ #{hibernate := Hibernate} = S,
Event =
case Msg of
{'$gen_call',From,Request} ->
@@ -789,388 +944,613 @@ loop_receive(Parent, Debug, #{timer := Timer} = S) ->
_ ->
{info,Msg}
end,
- loop_receive_result(Parent, Debug, S, Event)
+ loop_receive_result(
+ Parent, Debug, S, Hibernate, Event)
end
end.
loop_receive_result(
Parent, Debug,
#{state := State,
- data := Data,
- postponed := P} = S,
- Event) ->
- %% The engine state map S is now dismantled
- %% and will not be restored until we return to loop/3.
- %%
- %% The fields 'callback_mode', 'module', and 'name' are still valid.
- %% The fields 'state', 'data', and 'postponed' are held in arguments.
- %% The fields 'timer' and 'hibernate' will be recalculated.
- %%
+ timer_types := TimerTypes, cancel_timers := CancelTimers} = S,
+ Hibernate, Event) ->
+ %% From now the 'hibernate' field in S is invalid
+ %% and will be restored when looping back
+ %% in loop_event_result/11
NewDebug = sys_debug(Debug, S, State, {in,Event}),
- %% Here the queue of not yet handled events is created
+ %% Here is the queue of not yet handled events created
Events = [],
- Hibernate = false,
- loop_event(
- Parent, NewDebug, S, Events, State, Data, P, Event, Hibernate).
-
-%% Process the event queue, or if it is empty
-%% loop back to loop/3 to receive a new event
-loop_events(
- Parent, Debug, S, [Event|Events],
- State, Data, P, Hibernate, _Timeout) ->
- %%
- %% If there was a state timer requested we just ignore that
- %% since we have events to handle which cancels the timer
- loop_event(
- Parent, Debug, S, Events, State, Data, P, Event, Hibernate);
-loop_events(
- Parent, Debug, S, [],
- State, Data, P, Hibernate, Timeout) ->
- case Timeout of
- {timeout,0,EventContent} ->
- %% Immediate timeout - simulate it
- %% so we do not get the timeout message
- %% after any received event
- loop_event(
- Parent, Debug, S, [],
- State, Data, P, {timeout,EventContent}, Hibernate);
- {timeout,Time,EventContent} ->
- %% Actually start a timer
- Timer = erlang:start_timer(Time, self(), EventContent),
- loop_events_done(
- Parent, Debug, S, Timer, State, Data, P, Hibernate);
- undefined ->
- %% No state timeout has been requested
- Timer = undefined,
- loop_events_done(
- Parent, Debug, S, Timer, State, Data, P, Hibernate)
+ %% Cancel any running event timer
+ case
+ cancel_timer_by_type(timeout, TimerTypes, CancelTimers)
+ of
+ {_,CancelTimers} ->
+ %% No timer cancelled
+ loop_event(Parent, NewDebug, S, Events, Event, Hibernate);
+ {NewTimerTypes,NewCancelTimers} ->
+ %% The timer is removed from NewTimerTypes but
+ %% remains in TimerRefs until we get
+ %% the cancel_timer msg
+ NewS =
+ S#{
+ timer_types := NewTimerTypes,
+ cancel_timers := NewCancelTimers},
+ loop_event(Parent, NewDebug, NewS, Events, Event, Hibernate)
end.
-%%
-loop_events_done(Parent, Debug, S, Timer, State, Data, P, Hibernate) ->
- NewS =
- S#{
- state := State,
- data := Data,
- postponed := P,
- hibernate := Hibernate,
- timer := Timer},
- loop(Parent, Debug, NewS).
+%% Entry point for handling an event, received or enqueued
loop_event(
Parent, Debug,
- #{callback_mode := CallbackMode,
- module := Module} = S,
- Events,
- State, Data, P, {Type,Content} = Event, Hibernate) ->
+ #{state := State, data := Data} = S,
+ Events, {Type,Content} = Event, Hibernate) ->
%%
- %% If Hibernate is true here it can only be
+ %% If (this old) Hibernate is true here it can only be
%% because it was set from an event action
- %% and we did not go into hibernation since there
- %% were events in queue, so we do what the user
- %% might depend on i.e collect garbage which
+ %% and we did not go into hibernation since there were
+ %% events in queue, so we do what the user
+ %% might rely on i.e collect garbage which
%% would have happened if we actually hibernated
%% and immediately was awakened
Hibernate andalso garbage_collect(),
+ case call_state_function(S, Type, Content, State, Data) of
+ {ok,Result,NewS} ->
+ {NextState,NewData,Actions,EnterCall} =
+ parse_event_result(
+ true, Debug, NewS,
+ Events, Event, State, Data, Result),
+ loop_event_actions(
+ Parent, Debug, NewS,
+ Events, Event, NextState, NewData, Actions, EnterCall);
+ {Class,Reason,Stacktrace} ->
+ terminate(
+ Class, Reason, Stacktrace, Debug, S,
+ [Event|Events])
+ end.
+
+loop_event_actions(
+ Parent, Debug,
+ #{state := State, state_enter := StateEnter} = S,
+ Events, Event, NextState, NewData,
+ Actions, EnterCall) ->
+ %% Hibernate is reborn here as false being
+ %% the default value from parse_actions/4
+ case parse_actions(Debug, S, State, Actions) of
+ {ok,NewDebug,Hibernate,TimeoutsR,Postpone,NextEventsR} ->
+ if
+ StateEnter, EnterCall ->
+ loop_event_enter(
+ Parent, NewDebug, S,
+ Events, Event, NextState, NewData,
+ Hibernate, TimeoutsR, Postpone, NextEventsR);
+ true ->
+ loop_event_result(
+ Parent, NewDebug, S,
+ Events, Event, NextState, NewData,
+ Hibernate, TimeoutsR, Postpone, NextEventsR)
+ end;
+ {Class,Reason,Stacktrace} ->
+ terminate(
+ Class, Reason, Stacktrace, Debug, S,
+ [Event|Events])
+ end.
+
+loop_event_enter(
+ Parent, Debug, #{state := State} = S,
+ Events, Event, NextState, NewData,
+ Hibernate, TimeoutsR, Postpone, NextEventsR) ->
+ case call_state_function(S, enter, State, NextState, NewData) of
+ {ok,Result,NewS} ->
+ case parse_event_result(
+ false, Debug, NewS,
+ Events, Event, NextState, NewData, Result) of
+ {_,NewerData,Actions,EnterCall} ->
+ loop_event_enter_actions(
+ Parent, Debug, NewS,
+ Events, Event, NextState, NewerData,
+ Hibernate, TimeoutsR, Postpone, NextEventsR,
+ Actions, EnterCall)
+ end;
+ {Class,Reason,Stacktrace} ->
+ terminate(
+ Class, Reason, Stacktrace, Debug,
+ S#{
+ state := NextState,
+ data := NewData,
+ hibernate := Hibernate},
+ [Event|Events])
+ end.
+
+loop_event_enter_actions(
+ Parent, Debug, #{state_enter := StateEnter} = S,
+ Events, Event, NextState, NewData,
+ Hibernate, TimeoutsR, Postpone, NextEventsR,
+ Actions, EnterCall) ->
+ case
+ parse_enter_actions(
+ Debug, S, NextState, Actions, Hibernate, TimeoutsR)
+ of
+ {ok,NewDebug,NewHibernate,NewTimeoutsR,_,_} ->
+ if
+ StateEnter, EnterCall ->
+ loop_event_enter(
+ Parent, NewDebug, S,
+ Events, Event, NextState, NewData,
+ NewHibernate, NewTimeoutsR, Postpone, NextEventsR);
+ true ->
+ loop_event_result(
+ Parent, NewDebug, S,
+ Events, Event, NextState, NewData,
+ NewHibernate, NewTimeoutsR, Postpone, NextEventsR)
+ end;
+ {Class,Reason,Stacktrace} ->
+ terminate(
+ Class, Reason, Stacktrace, Debug,
+ S#{
+ state := NextState,
+ data := NewData,
+ hibernate := Hibernate},
+ [Event|Events])
+ end.
+
+loop_event_result(
+ Parent, Debug_0,
+ #{state := State, postponed := P_0,
+ timer_refs := TimerRefs_0, timer_types := TimerTypes_0,
+ cancel_timers := CancelTimers_0} = S_0,
+ Events_0, Event_0, NextState, NewData,
+ Hibernate, TimeoutsR, Postpone, NextEventsR) ->
%%
+ %% All options have been collected and next_events are buffered.
+ %% Do the actual state transition.
+ %%
+ {Debug_1,P_1} = % Move current event to postponed if Postpone
+ case Postpone of
+ true ->
+ {sys_debug(Debug_0, S_0, State, {postpone,Event_0,State}),
+ [Event_0|P_0]};
+ false ->
+ {sys_debug(Debug_0, S_0, State, {consume,Event_0,State}),
+ P_0}
+ end,
+ {Events_1,P_2,{TimerTypes_1,CancelTimers_1}} =
+ %% Move all postponed events to queue and cancel the
+ %% state timeout if the state changes
+ if
+ NextState =:= State ->
+ {Events_0,P_1,{TimerTypes_0,CancelTimers_0}};
+ true ->
+ {lists:reverse(P_1, Events_0),
+ [],
+ cancel_timer_by_type(
+ state_timeout, TimerTypes_0, CancelTimers_0)}
+ %% The state timer is removed from TimerTypes_1
+ %% but remains in TimerRefs_0 until we get
+ %% the cancel_timer msg
+ end,
+ {TimerRefs_2,TimerTypes_2,CancelTimers_2,TimeoutEvents} =
+ %% Stop and start non-event timers
+ parse_timers(TimerRefs_0, TimerTypes_1, CancelTimers_1, TimeoutsR),
+ %% Place next events last in reversed queue
+ Events_2R = lists:reverse(Events_1, NextEventsR),
+ %% Enqueue immediate timeout events and start event timer
+ Events_3R = prepend_timeout_events(TimeoutEvents, Events_2R),
+ S_1 =
+ S_0#{
+ state := NextState,
+ data := NewData,
+ postponed := P_2,
+ timer_refs := TimerRefs_2,
+ timer_types := TimerTypes_2,
+ cancel_timers := CancelTimers_2,
+ hibernate := Hibernate},
+ case lists:reverse(Events_3R) of
+ [] ->
+ %% Get a new event
+ loop(Parent, Debug_1, S_1);
+ [Event|Events] ->
+ %% Loop until out of enqueued events
+ loop_event(Parent, Debug_1, S_1, Events, Event, Hibernate)
+ end.
+
+
+%%---------------------------------------------------------------------------
+%% Server loop helpers
+
+call_callback_mode(#{module := Module} = S) ->
+ try Module:callback_mode() of
+ CallbackMode ->
+ callback_mode_result(S, CallbackMode)
+ catch
+ CallbackMode ->
+ callback_mode_result(S, CallbackMode);
+ Class:Reason ->
+ {Class,Reason,erlang:get_stacktrace()}
+ end.
+
+callback_mode_result(S, CallbackMode) ->
+ case
+ parse_callback_mode(
+ if
+ is_atom(CallbackMode) ->
+ [CallbackMode];
+ true ->
+ CallbackMode
+ end, undefined, false)
+ of
+ {undefined,_} ->
+ {error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE()};
+ {CBMode,StateEnter} ->
+ {ok,
+ S#{
+ callback_mode := CBMode,
+ state_enter := StateEnter}}
+ end.
+
+parse_callback_mode([], CBMode, StateEnter) ->
+ {CBMode,StateEnter};
+parse_callback_mode([H|T], CBMode, StateEnter) ->
+ case callback_mode(H) of
+ true ->
+ parse_callback_mode(T, H, StateEnter);
+ false ->
+ case H of
+ state_enter ->
+ parse_callback_mode(T, CBMode, true);
+ _ ->
+ {undefined,StateEnter}
+ end
+ end;
+parse_callback_mode(_, _CBMode, StateEnter) ->
+ {undefined,StateEnter}.
+
+
+call_state_function(
+ #{callback_mode := undefined} = S, Type, Content, State, Data) ->
+ case call_callback_mode(S) of
+ {ok,NewS} ->
+ call_state_function(NewS, Type, Content, State, Data);
+ Error ->
+ Error
+ end;
+call_state_function(
+ #{callback_mode := CallbackMode, module := Module} = S,
+ Type, Content, State, Data) ->
try
case CallbackMode of
state_functions ->
Module:State(Type, Content, Data);
handle_event_function ->
Module:handle_event(Type, Content, State, Data)
- end of
+ end
+ of
Result ->
- loop_event_result(
- Parent, Debug, S, Events, State, Data, P, Event, Result)
+ {ok,Result,S}
catch
Result ->
- loop_event_result(
- Parent, Debug, S, Events, State, Data, P, Event, Result);
- error:badarg when CallbackMode =:= state_functions ->
- case erlang:get_stacktrace() of
- [{erlang,apply,[Module,State,_],_}|Stacktrace] ->
- Args = [Type,Content,Data],
- terminate(
- error,
- {undef_state_function,{Module,State,Args}},
- Stacktrace,
- Debug, S, [Event|Events], State, Data, P);
- Stacktrace ->
- terminate(
- error, badarg, Stacktrace,
- Debug, S, [Event|Events], State, Data, P)
- end;
- error:undef ->
- %% Process an undef to check for the simple mistake
- %% of calling a nonexistent state function
- case erlang:get_stacktrace() of
- [{Module,State,
- [Type,Content,Data]=Args,
- _}
- |Stacktrace]
- when CallbackMode =:= state_functions ->
- terminate(
- error,
- {undef_state_function,{Module,State,Args}},
- Stacktrace,
- Debug, S, [Event|Events], State, Data, P);
- [{Module,handle_event,
- [Type,Content,State,Data]=Args,
- _}
- |Stacktrace]
- when CallbackMode =:= handle_event_function ->
- terminate(
- error,
- {undef_state_function,{Module,handle_event,Args}},
- Stacktrace,
- Debug, S, [Event|Events], State, Data, P);
- Stacktrace ->
- terminate(
- error, undef, Stacktrace,
- Debug, S, [Event|Events], State, Data, P)
- end;
+ {ok,Result,S};
Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
- terminate(
- Class, Reason, Stacktrace,
- Debug, S, [Event|Events], State, Data, P)
+ {Class,Reason,erlang:get_stacktrace()}
end.
+
%% Interpret all callback return variants
-loop_event_result(
- Parent, Debug, S, Events, State, Data, P, Event, Result) ->
+parse_event_result(
+ AllowStateChange, Debug, S,
+ Events, Event, State, Data, Result) ->
case Result of
stop ->
terminate(
- exit, normal, ?STACKTRACE(),
- Debug, S, [Event|Events], State, Data, P);
+ exit, normal, ?STACKTRACE(), Debug,
+ S#{state := State, data := Data},
+ [Event|Events]);
{stop,Reason} ->
terminate(
- exit, Reason, ?STACKTRACE(),
- Debug, S, [Event|Events], State, Data, P);
+ exit, Reason, ?STACKTRACE(), Debug,
+ S#{state := State, data := Data},
+ [Event|Events]);
{stop,Reason,NewData} ->
terminate(
- exit, Reason, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P);
+ exit, Reason, ?STACKTRACE(), Debug,
+ S#{state := State, data := NewData},
+ [Event|Events]);
+ %%
{stop_and_reply,Reason,Replies} ->
- Q = [Event|Events],
reply_then_terminate(
- exit, Reason, ?STACKTRACE(),
- Debug, S, Q, State, Data, P, Replies);
+ exit, Reason, ?STACKTRACE(), Debug,
+ S#{state := State, data := Data},
+ [Event|Events], Replies);
{stop_and_reply,Reason,Replies,NewData} ->
- Q = [Event|Events],
reply_then_terminate(
- exit, Reason, ?STACKTRACE(),
- Debug, S, Q, State, NewData, P, Replies);
- {next_state,NextState,NewData} ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, []);
- {next_state,NextState,NewData,Actions} ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions);
+ exit, Reason, ?STACKTRACE(), Debug,
+ S#{state := State, data := NewData},
+ [Event|Events], Replies);
+ %%
+ {next_state,State,NewData} ->
+ {State,NewData,[],false};
+ {next_state,NextState,NewData} when AllowStateChange ->
+ {NextState,NewData,[],true};
+ {next_state,State,NewData,Actions} ->
+ {State,NewData,Actions,false};
+ {next_state,NextState,NewData,Actions} when AllowStateChange ->
+ {NextState,NewData,Actions,true};
+ %%
{keep_state,NewData} ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, State, []);
+ {State,NewData,[],false};
{keep_state,NewData,Actions} ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, State, Actions);
+ {State,NewData,Actions,false};
keep_state_and_data ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, Data, P, Event, State, []);
+ {State,Data,[],false};
{keep_state_and_data,Actions} ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, Data, P, Event, State, Actions);
+ {State,Data,Actions,false};
+ %%
+ {repeat_state,NewData} ->
+ {State,NewData,[],true};
+ {repeat_state,NewData,Actions} ->
+ {State,NewData,Actions,true};
+ repeat_state_and_data ->
+ {State,Data,[],true};
+ {repeat_state_and_data,Actions} ->
+ {State,Data,Actions,true};
+ %%
_ ->
terminate(
- error, {bad_return_value,Result}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, Data, P)
+ error,
+ {bad_return_from_state_function,Result},
+ ?STACKTRACE(), Debug,
+ S#{state := State, data := Data},
+ [Event|Events])
end.
-loop_event_actions(
- Parent, Debug, S, Events, State, NewData, P, Event, NextState, Actions) ->
- Postpone = false, % Shall we postpone this event; boolean()
+
+parse_enter_actions(Debug, S, State, Actions, Hibernate, TimeoutsR) ->
+ Postpone = forbidden,
+ NextEventsR = forbidden,
+ parse_actions(
+ Debug, S, State, listify(Actions),
+ Hibernate, TimeoutsR, Postpone, NextEventsR).
+
+parse_actions(Debug, S, State, Actions) ->
Hibernate = false,
- Timeout = undefined,
- NextEvents = [],
- loop_event_actions(
- Parent, Debug, S, Events, State, NewData, P, Event, NextState,
- if
- is_list(Actions) ->
- Actions;
- true ->
- [Actions]
- end,
- Postpone, Hibernate, Timeout, NextEvents).
+ TimeoutsR = [{timeout,infinity,infinity}], %% Will cancel event timer
+ Postpone = false,
+ NextEventsR = [],
+ parse_actions(
+ Debug, S, State, listify(Actions),
+ Hibernate, TimeoutsR, Postpone, NextEventsR).
%%
-%% Process all actions
-loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, [Action|Actions],
- Postpone, Hibernate, Timeout, NextEvents) ->
+parse_actions(
+ Debug, _S, _State, [],
+ Hibernate, TimeoutsR, Postpone, NextEventsR) ->
+ {ok,Debug,Hibernate,TimeoutsR,Postpone,NextEventsR};
+parse_actions(
+ Debug, S, State, [Action|Actions],
+ Hibernate, TimeoutsR, Postpone, NextEventsR) ->
case Action of
%% Actual actions
{reply,From,Reply} ->
case from(From) of
true ->
NewDebug = do_reply(Debug, S, State, From, Reply),
- loop_event_actions(
- Parent, NewDebug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, Hibernate, Timeout, NextEvents);
- false ->
- terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P)
- end;
- {next_event,Type,Content} ->
- case event_type(Type) of
- true ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, Hibernate, Timeout,
- [{Type,Content}|NextEvents]);
+ parse_actions(
+ NewDebug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR);
false ->
- terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P)
+ {error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE()}
end;
+ %%
%% Actions that set options
- {postpone,NewPostpone} when is_boolean(NewPostpone) ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- NewPostpone, Hibernate, Timeout, NextEvents);
- {postpone,_} ->
- terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P);
- postpone ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- true, Hibernate, Timeout, NextEvents);
{hibernate,NewHibernate} when is_boolean(NewHibernate) ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, NewHibernate, Timeout, NextEvents);
- {hibernate,_} ->
- terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P);
+ parse_actions(
+ Debug, S, State, Actions,
+ NewHibernate, TimeoutsR, Postpone, NextEventsR);
hibernate ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, true, Timeout, NextEvents);
- {timeout,infinity,_} -> % Clear timer - it will never trigger
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, Hibernate, undefined, NextEvents);
- {timeout,Time,_} = NewTimeout when is_integer(Time), Time >= 0 ->
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, Hibernate, NewTimeout, NextEvents);
- {timeout,_,_} ->
- terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P);
- infinity -> % Clear timer - it will never trigger
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, Hibernate, undefined, NextEvents);
- Time when is_integer(Time), Time >= 0 ->
- NewTimeout = {timeout,Time,Time},
- loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P, Event, NextState, Actions,
- Postpone, Hibernate, NewTimeout, NextEvents);
- _ ->
- terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
- Debug, S, [Event|Events], State, NewData, P)
- end;
-%%
-%% End of actions list
-loop_event_actions(
- Parent, Debug, S, Events,
- State, NewData, P0, Event, NextState, [],
- Postpone, Hibernate, Timeout, NextEvents) ->
- %%
- %% All options have been collected and next_events are buffered.
- %% Do the actual state transition.
- %%
- P1 = % Move current event to postponed if Postpone
- case Postpone of
- true ->
- [Event|P0];
- false ->
- P0
- end,
- {Q2,P} = % Move all postponed events to queue if state change
- if
- NextState =:= State ->
- {Events,P1};
- true ->
- {lists:reverse(P1, Events),[]}
+ NewHibernate = true,
+ parse_actions(
+ Debug, S, State, Actions,
+ NewHibernate, TimeoutsR, Postpone, NextEventsR);
+ %%
+ {postpone,NewPostpone}
+ when is_boolean(NewPostpone), Postpone =/= forbidden ->
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, NewPostpone, NextEventsR);
+ postpone when Postpone =/= forbidden ->
+ NewPostpone = true,
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, NewPostpone, NextEventsR);
+ %%
+ {next_event,Type,Content} ->
+ case event_type(Type) of
+ true when NextEventsR =/= forbidden ->
+ NewDebug =
+ sys_debug(Debug, S, State, {in,{Type,Content}}),
+ parse_actions(
+ NewDebug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone,
+ [{Type,Content}|NextEventsR]);
+ _ ->
+ {error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE()}
+ end;
+ %%
+ {state_timeout,_,_} = Timeout ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
+ {timeout,_,_} = Timeout ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
+ Time ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Time)
+ end.
+
+parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout) ->
+ Time =
+ case Timeout of
+ {_,T,_} -> T;
+ T -> T
end,
- %% Place next events first in queue
- Q = lists:reverse(NextEvents, Q2),
- %%
- NewDebug =
- sys_debug(
- Debug, S, State,
- case Postpone of
- true ->
- {postpone,Event,NextState};
- false ->
- {consume,Event,NextState}
- end),
- loop_events(
- Parent, NewDebug, S, Q, NextState, NewData, P, Hibernate, Timeout).
+ case validate_time(Time) of
+ true ->
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, [Timeout|TimeoutsR],
+ Postpone, NextEventsR);
+ false ->
+ {error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE()}
+ end.
+
+validate_time(Time) when is_integer(Time), Time >= 0 -> true;
+validate_time(infinity) -> true;
+validate_time(_) -> false.
+
+%% Stop and start timers as well as create timeout zero events
+%% and pending event timer
+%%
+%% Stop and start timers non-event timers
+parse_timers(TimerRefs, TimerTypes, CancelTimers, TimeoutsR) ->
+ parse_timers(TimerRefs, TimerTypes, CancelTimers, TimeoutsR, #{}, []).
+%%
+parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, [], _Seen, TimeoutEvents) ->
+ {TimerRefs,TimerTypes,CancelTimers,TimeoutEvents};
+parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, [Timeout|TimeoutsR],
+ Seen, TimeoutEvents) ->
+ case Timeout of
+ {TimerType,Time,TimerMsg} ->
+ parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ TimerType, Time, TimerMsg);
+ Time ->
+ parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ timeout, Time, Time)
+ end.
+
+parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ TimerType, Time, TimerMsg) ->
+ case Seen of
+ #{TimerType := _} ->
+ %% Type seen before - ignore
+ parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents);
+ #{} ->
+ %% Unseen type - handle
+ NewSeen = Seen#{TimerType => true},
+ case Time of
+ infinity ->
+ %% Cancel any running timer
+ {NewTimerTypes,NewCancelTimers} =
+ cancel_timer_by_type(
+ TimerType, TimerTypes, CancelTimers),
+ parse_timers(
+ TimerRefs, NewTimerTypes, NewCancelTimers, TimeoutsR,
+ NewSeen, TimeoutEvents);
+ 0 ->
+ %% Cancel any running timer
+ {NewTimerTypes,NewCancelTimers} =
+ cancel_timer_by_type(
+ TimerType, TimerTypes, CancelTimers),
+ %% Handle zero time timeouts later
+ TimeoutEvent = {TimerType,TimerMsg},
+ parse_timers(
+ TimerRefs, NewTimerTypes, NewCancelTimers, TimeoutsR,
+ NewSeen, [TimeoutEvent|TimeoutEvents]);
+ _ ->
+ %% (Re)start the timer
+ TimerRef =
+ erlang:start_timer(Time, self(), TimerMsg),
+ case TimerTypes of
+ #{TimerType := OldTimerRef} ->
+ %% Cancel the running timer
+ cancel_timer(OldTimerRef),
+ NewCancelTimers = CancelTimers + 1,
+ %% Insert the new timer into
+ %% both TimerRefs and TimerTypes
+ parse_timers(
+ TimerRefs#{TimerRef => TimerType},
+ TimerTypes#{TimerType => TimerRef},
+ NewCancelTimers, TimeoutsR,
+ NewSeen, TimeoutEvents);
+ #{} ->
+ parse_timers(
+ TimerRefs#{TimerRef => TimerType},
+ TimerTypes#{TimerType => TimerRef},
+ CancelTimers, TimeoutsR,
+ NewSeen, TimeoutEvents)
+ end
+ end
+ end.
+
+%% Enqueue immediate timeout events (timeout 0 events)
+%%
+%% Event timer timeout 0 events gets special treatment since
+%% an event timer is cancelled by any received event,
+%% so if there are enqueued events before the event timer
+%% timeout 0 event - the event timer is cancelled hence no event.
+%%
+%% Other (state_timeout) timeout 0 events that are after
+%% the event timer timeout 0 events are considered to
+%% belong to timers that were started after the event timer
+%% timeout 0 event fired, so they do not cancel the event timer.
+%%
+prepend_timeout_events([], EventsR) ->
+ EventsR;
+prepend_timeout_events([{timeout,_} = TimeoutEvent|TimeoutEvents], []) ->
+ prepend_timeout_events(TimeoutEvents, [TimeoutEvent]);
+prepend_timeout_events([{timeout,_}|TimeoutEvents], EventsR) ->
+ prepend_timeout_events(TimeoutEvents, EventsR);
+prepend_timeout_events([TimeoutEvent|TimeoutEvents], EventsR) ->
+ %% Just prepend all others
+ prepend_timeout_events(TimeoutEvents, [TimeoutEvent|EventsR]).
+
+
%%---------------------------------------------------------------------------
%% Server helpers
reply_then_terminate(
- Class, Reason, Stacktrace,
- Debug, S, Q, State, Data, P, Replies) ->
- if
- is_list(Replies) ->
- do_reply_then_terminate(
- Class, Reason, Stacktrace,
- Debug, S, Q, State, Data, P, Replies);
- true ->
- do_reply_then_terminate(
- Class, Reason, Stacktrace,
- Debug, S, Q, State, Data, P, [Replies])
- end.
+ Class, Reason, Stacktrace, Debug,
+ #{state := State} = S, Q, Replies) ->
+ do_reply_then_terminate(
+ Class, Reason, Stacktrace, Debug,
+ S, Q, listify(Replies), State).
%%
do_reply_then_terminate(
- Class, Reason, Stacktrace, Debug, S, Q, State, Data, P, []) ->
- terminate(Class, Reason, Stacktrace, Debug, S, Q, State, Data, P);
+ Class, Reason, Stacktrace, Debug, S, Q, [], _State) ->
+ terminate(Class, Reason, Stacktrace, Debug, S, Q);
do_reply_then_terminate(
- Class, Reason, Stacktrace, Debug, S, Q, State, Data, P, [R|Rs]) ->
+ Class, Reason, Stacktrace, Debug, S, Q, [R|Rs], State) ->
case R of
{reply,{_To,_Tag}=From,Reply} ->
NewDebug = do_reply(Debug, S, State, From, Reply),
do_reply_then_terminate(
- Class, Reason, Stacktrace,
- NewDebug, S, Q, State, Data, P, Rs);
+ Class, Reason, Stacktrace, NewDebug, S, Q, Rs, State);
_ ->
terminate(
- error, {bad_action,R}, ?STACKTRACE(),
- Debug, S, Q, State, Data, P)
+ error,
+ {bad_reply_action_from_state_function,R},
+ ?STACKTRACE(),
+ Debug, S, Q)
end.
do_reply(Debug, S, State, From, Reply) ->
@@ -1179,28 +1559,40 @@ do_reply(Debug, S, State, From, Reply) ->
terminate(
- Class, Reason, Stacktrace,
- Debug, #{module := Module} = S, Q, State, Data, P) ->
- try Module:terminate(Reason, State, Data) of
- _ -> ok
- catch
- _ -> ok;
- C:R ->
- ST = erlang:get_stacktrace(),
- error_info(
- C, R, ST, Debug, S, Q, P,
- format_status(terminate, get(), S, State, Data)),
- erlang:raise(C, R, ST)
- end,
- case Reason of
- normal -> ok;
- shutdown -> ok;
- {shutdown,_} -> ok;
- _ ->
- error_info(
- Class, Reason, Stacktrace, Debug, S, Q, P,
- format_status(terminate, get(), S, State, Data))
+ Class, Reason, Stacktrace, Debug,
+ #{module := Module, state := State, data := Data, postponed := P} = S,
+ Q) ->
+ case erlang:function_exported(Module, terminate, 3) of
+ true ->
+ try Module:terminate(Reason, State, Data) of
+ _ -> ok
+ catch
+ _ -> ok;
+ C:R ->
+ ST = erlang:get_stacktrace(),
+ error_info(
+ C, R, ST, S, Q, P,
+ format_status(terminate, get(), S)),
+ sys:print_log(Debug),
+ erlang:raise(C, R, ST)
+ end;
+ false ->
+ ok
end,
+ _ =
+ case Reason of
+ normal ->
+ sys_debug(Debug, S, State, {terminate,Reason});
+ shutdown ->
+ sys_debug(Debug, S, State, {terminate,Reason});
+ {shutdown,_} ->
+ sys_debug(Debug, S, State, {terminate,Reason});
+ _ ->
+ error_info(
+ Class, Reason, Stacktrace, S, Q, P,
+ format_status(terminate, get(), S)),
+ sys:print_log(Debug)
+ end,
case Stacktrace of
[] ->
erlang:Class(Reason);
@@ -1209,8 +1601,10 @@ terminate(
end.
error_info(
- Class, Reason, Stacktrace, Debug,
- #{name := Name, callback_mode := CallbackMode},
+ Class, Reason, Stacktrace,
+ #{name := Name,
+ callback_mode := CallbackMode,
+ state_enter := StateEnter},
Q, P, FmtData) ->
{FixedReason,FixedStacktrace} =
case Stacktrace of
@@ -1237,6 +1631,13 @@ error_info(
end;
_ -> {Reason,Stacktrace}
end,
+ CBMode =
+ case StateEnter of
+ true ->
+ [CallbackMode,state_enter];
+ false ->
+ CallbackMode
+ end,
error_logger:format(
"** State machine ~p terminating~n" ++
case Q of
@@ -1263,8 +1664,9 @@ error_info(
[] -> [];
[Event|_] -> [Event]
end] ++
- [FmtData,Class,FixedReason,
- CallbackMode] ++
+ [FmtData,
+ Class,FixedReason,
+ CBMode] ++
case Q of
[_|[_|_] = Events] -> [Events];
_ -> []
@@ -1276,13 +1678,13 @@ error_info(
case FixedStacktrace of
[] -> [];
_ -> [FixedStacktrace]
- end),
- sys:print_log(Debug),
- ok.
+ end).
%% Call Module:format_status/2 or return a default value
-format_status(Opt, PDict, #{module := Module}, State, Data) ->
+format_status(
+ Opt, PDict,
+ #{module := Module, state := State, data := Data}) ->
case erlang:function_exported(Module, format_status, 2) of
true ->
try Module:format_status(Opt, [PDict,State,Data])
@@ -1291,7 +1693,7 @@ format_status(Opt, PDict, #{module := Module}, State, Data) ->
_:_ ->
format_status_default(
Opt, State,
- "Module:format_status/2 crashed")
+ atom_to_list(Module) ++ ":format_status/2 crashed")
end;
false ->
format_status_default(Opt, State, Data)
@@ -1299,10 +1701,35 @@ format_status(Opt, PDict, #{module := Module}, State, Data) ->
%% The default Module:format_status/2
format_status_default(Opt, State, Data) ->
- SSD = {State,Data},
+ StateData = {State,Data},
case Opt of
terminate ->
- SSD;
+ StateData;
_ ->
- [{data,[{"State",SSD}]}]
+ [{data,[{"State",StateData}]}]
+ end.
+
+listify(Item) when is_list(Item) ->
+ Item;
+listify(Item) ->
+ [Item].
+
+%% Cancel timer if running, otherwise no op
+%%
+%% This is an asynchronous cancel so the timer is not really cancelled
+%% until we get a cancel_timer msg i.e {cancel_timer,TimerRef,_}.
+%% In the mean time we might get a timeout message.
+%%
+%% Remove the timer from TimerTypes.
+%% When we get the cancel_timer msg we remove it from TimerRefs.
+cancel_timer_by_type(TimerType, TimerTypes, CancelTimers) ->
+ case TimerTypes of
+ #{TimerType := TimerRef} ->
+ cancel_timer(TimerRef),
+ {maps:remove(TimerType, TimerTypes),CancelTimers + 1};
+ #{} ->
+ {TimerTypes,CancelTimers}
end.
+
+cancel_timer(TimerRef) ->
+ ok = erlang:cancel_timer(TimerRef, [{async,true}]).
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 16ca2f41dc..ba2cffdcb3 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -128,6 +128,10 @@ max_cs(M, _Len) ->
M.
-define(ATM(T), is_list(element(1, T))).
+-define(ATM_PAIR(Pair),
+ ?ATM(element(2, element(1, Pair))) % Key
+ andalso
+ ?ATM(element(3, element(1, Pair)))). % Value
-define(ATM_FLD(Field), ?ATM(element(4, element(1, Field)))).
pp({_S, Len} = If, Col, Ll, M, _TInd, _Ind, LD, W)
@@ -140,9 +144,8 @@ pp({{tuple,true,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
pp({{tuple,false,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
[${, pp_list(L, Col + 1, Ll, M, TInd, indent(1, Ind), LD, $,, W + 1), $}];
pp({{map,Pairs},_Len}, Col, Ll, M, TInd, Ind, LD, W) ->
- [$#,${, pp_list(Pairs, Col + 2, Ll, M, TInd, indent(2, Ind), LD, $,, W + 1), $}];
-pp({{map_pair,K,V},_Len}, Col, Ll, M, TInd, Ind, LD, W) ->
- [pp(K, Col, Ll, M, TInd, Ind, LD, W), " => ", pp(V, Col, Ll, M, TInd, Ind, LD, W)];
+ [$#, ${, pp_map(Pairs, Col + 2, Ll, M, TInd, indent(2, Ind), LD, W + 1),
+ $}];
pp({{record,[{Name,NLen} | L]}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
[Name, ${, pp_record(L, NLen, Col, Ll, M, TInd, Ind, LD, W + NLen+1), $}];
pp({{bin,S}, _Len}, Col, Ll, M, _TInd, Ind, LD, W) ->
@@ -166,6 +169,46 @@ pp_tag_tuple([{Tag,Tlen} | L], Col, Ll, M, TInd, Ind, LD, W) ->
[Tag, S | pp_list(L, Tcol, Ll, M, TInd, Indent, LD, S, W+Tlen+1)]
end.
+pp_map([], _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
+ "";
+pp_map({dots, _}, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
+ "...";
+pp_map([P | Ps], Col, Ll, M, TInd, Ind, LD, W) ->
+ {PS, PW} = pp_pair(P, Col, Ll, M, TInd, Ind, last_depth(Ps, LD), W),
+ [PS | pp_pairs_tail(Ps, Col, Col + PW, Ll, M, TInd, Ind, LD, PW)].
+
+pp_pairs_tail([], _Col0, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
+ "";
+pp_pairs_tail({dots, _}, _Col0, _Col, _M, _Ll, _TInd, _Ind, _LD, _W) ->
+ ",...";
+pp_pairs_tail([{_, Len}=P | Ps], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
+ LD1 = last_depth(Ps, LD),
+ ELen = 1 + Len,
+ if
+ LD1 =:= 0, ELen + 1 < Ll - Col, W + ELen + 1 =< M, ?ATM_PAIR(P);
+ LD1 > 0, ELen < Ll - Col - LD1, W + ELen + LD1 =< M, ?ATM_PAIR(P) ->
+ [$,, write_pair(P) |
+ pp_pairs_tail(Ps, Col0, Col+ELen, Ll, M, TInd, Ind, LD, W+ELen)];
+ true ->
+ {PS, PW} = pp_pair(P, Col0, Ll, M, TInd, Ind, LD1, 0),
+ [$,, $\n, Ind, PS |
+ pp_pairs_tail(Ps, Col0, Col0 + PW, Ll, M, TInd, Ind, LD, PW)]
+ end.
+
+pp_pair({_, Len}=Pair, Col, Ll, M, _TInd, _Ind, LD, W)
+ when Len < Ll - Col - LD, Len + W + LD =< M ->
+ {write_pair(Pair), if
+ ?ATM_PAIR(Pair) ->
+ Len;
+ true ->
+ Ll % force nl
+ end};
+pp_pair({{map_pair, K, V}, _Len}, Col0, Ll, M, TInd, Ind0, LD, W) ->
+ I = map_value_indent(TInd),
+ Ind = indent(I, Ind0),
+ {[pp(K, Col0, Ll, M, TInd, Ind0, LD, W), " =>\n",
+ Ind | pp(V, Col0 + I, Ll, M, TInd, Ind, LD, 0)], Ll}. % force nl
+
pp_record([], _Nlen, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
"";
pp_record({dots, _}, _Nlen, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
@@ -204,7 +247,11 @@ pp_field({_, Len}=Fl, Col, Ll, M, _TInd, _Ind, LD, W)
end};
pp_field({{field, Name, NameL, F}, _Len}, Col0, Ll, M, TInd, Ind0, LD, W0) ->
{Col, Ind, S, W} = rec_indent(NameL, TInd, Col0, Ind0, W0 + NameL),
- {[Name, " = ", S | pp(F, Col, Ll, M, TInd, Ind, LD, W)], Ll}. % force nl
+ Sep = case S of
+ [$\n | _] -> " =";
+ _ -> " = "
+ end,
+ {[Name, Sep, S | pp(F, Col, Ll, M, TInd, Ind, LD, W)], Ll}. % force nl
rec_indent(RInd, TInd, Col0, Ind0, W0) ->
Nl = (TInd > 0) and (RInd > TInd),
@@ -291,8 +338,8 @@ write({{list, L}, _}) ->
[$[, write_list(L, $|), $]];
write({{map, Pairs}, _}) ->
[$#,${, write_list(Pairs, $,), $}];
-write({{map_pair, K, V}, _}) ->
- [write(K)," => ",write(V)];
+write({{map_pair, _K, _V}, _}=Pair) ->
+ write_pair(Pair);
write({{record, [{Name,_} | L]}, _}) ->
[Name, ${, write_fields(L), $}];
write({{bin, S}, _}) ->
@@ -300,6 +347,9 @@ write({{bin, S}, _}) ->
write({S, _}) ->
S.
+write_pair({{map_pair, K, V}, _}) ->
+ [write(K), " => ", write(V)].
+
write_fields([]) ->
"";
write_fields({dots, _}) ->
@@ -333,7 +383,7 @@ write_tail(E, S) ->
%% The depth (D) is used for extracting and counting the characters to
%% print. The structure is kept so that the returned intermediate
-%% format can be formatted. The separators (list, tuple, record) are
+%% format can be formatted. The separators (list, tuple, record, map) are
%% counted but need to be added later.
%% D =/= 0
@@ -406,21 +456,32 @@ print_length(Term, _D, _RF, _Enc, _Str) ->
print_length_map(_Map, 1, _RF, _Enc, _Str) ->
{"#{...}", 6};
print_length_map(Map, D, RF, Enc, Str) when is_map(Map) ->
- Pairs = print_length_map_pairs(maps:to_list(Map), D, RF, Enc, Str),
+ Pairs = print_length_map_pairs(maps_to_list(Map, D), D, RF, Enc, Str),
{{map, Pairs}, list_length(Pairs, 3)}.
+maps_to_list(Map, D) when D < 0; map_size(Map) =< D ->
+ maps:to_list(Map);
+maps_to_list(Map, D) ->
+ F = fun(_K, _V, {N, L}) when N =:= D ->
+ throw(L);
+ (K, V, {N, L}) ->
+ {N+1, [{K, V} | L]}
+ end,
+ lists:reverse(catch maps:fold(F, {0, []}, Map)).
+
print_length_map_pairs([], _D, _RF, _Enc, _Str) ->
[];
print_length_map_pairs(_Pairs, 1, _RF, _Enc, _Str) ->
{dots, 3};
-print_length_map_pairs([{K,V}|Pairs], D, RF, Enc, Str) ->
- [print_length_map_pair(K,V,D-1,RF,Enc,Str) |
- print_length_map_pairs(Pairs,D-1,RF,Enc,Str)].
+print_length_map_pairs([{K, V} | Pairs], D, RF, Enc, Str) ->
+ [print_length_map_pair(K, V, D - 1, RF, Enc, Str) |
+ print_length_map_pairs(Pairs, D - 1, RF, Enc, Str)].
print_length_map_pair(K, V, D, RF, Enc, Str) ->
{KS, KL} = print_length(K, D, RF, Enc, Str),
{VS, VL} = print_length(V, D, RF, Enc, Str),
- {{map_pair, {KS,KL}, {VS,VL}}, KL + VL}.
+ KL1 = KL + 4,
+ {{map_pair, {KS, KL1}, {VS, VL}}, KL1 + VL}.
print_length_tuple(_Tuple, 1, _RF, _Enc, _Str) ->
{"{...}", 5};
@@ -612,6 +673,8 @@ cind({{tuple,true,L}, _Len}, Col, Ll, M, Ind, LD, W) ->
cind_tag_tuple(L, Col, Ll, M, Ind, LD, W + 1);
cind({{tuple,false,L}, _Len}, Col, Ll, M, Ind, LD, W) ->
cind_list(L, Col + 1, Ll, M, Ind, LD, W + 1);
+cind({{map,Pairs},_Len}, Col, Ll, M, Ind, LD, W) ->
+ cind_map(Pairs, Col + 2, Ll, M, Ind, LD, W + 2);
cind({{record,[{_Name,NLen} | L]}, _Len}, Col, Ll, M, Ind, LD, W) ->
cind_record(L, NLen, Col, Ll, M, Ind, LD, W + NLen + 1);
cind({{bin,_S}, _Len}, _Col, _Ll, _M, Ind, _LD, _W) ->
@@ -637,6 +700,48 @@ cind_tag_tuple([{_Tag,Tlen} | L], Col, Ll, M, Ind, LD, W) ->
throw(no_good)
end.
+cind_map([P | Ps], Col, Ll, M, Ind, LD, W) ->
+ PW = cind_pair(P, Col, Ll, M, Ind, last_depth(Ps, LD), W),
+ cind_pairs_tail(Ps, Col, Col + PW, Ll, M, Ind, LD, W + PW);
+cind_map(_, _Col, _Ll, _M, Ind, _LD, _W) ->
+ Ind.
+
+cind_pairs_tail([{_, Len}=P | Ps], Col0, Col, Ll, M, Ind, LD, W) ->
+ LD1 = last_depth(Ps, LD),
+ ELen = 1 + Len,
+ if
+ LD1 =:= 0, ELen + 1 < Ll - Col, W + ELen + 1 =< M, ?ATM_PAIR(P);
+ LD1 > 0, ELen < Ll - Col - LD1, W + ELen + LD1 =< M, ?ATM_PAIR(P) ->
+ cind_pairs_tail(Ps, Col0, Col + ELen, Ll, M, Ind, LD, W + ELen);
+ true ->
+ PW = cind_pair(P, Col0, Ll, M, Ind, LD1, 0),
+ cind_pairs_tail(Ps, Col0, Col0 + PW, Ll, M, Ind, LD, PW)
+ end;
+cind_pairs_tail(_, _Col0, _Col, _Ll, _M, Ind, _LD, _W) ->
+ Ind.
+
+cind_pair({{map_pair, _Key, _Value}, Len}=Pair, Col, Ll, M, _Ind, LD, W)
+ when Len < Ll - Col - LD, Len + W + LD =< M ->
+ if
+ ?ATM_PAIR(Pair) ->
+ Len;
+ true ->
+ Ll
+ end;
+cind_pair({{map_pair, K, V}, _Len}, Col0, Ll, M, Ind, LD, W0) ->
+ cind(K, Col0, Ll, M, Ind, LD, W0),
+ I = map_value_indent(Ind),
+ cind(V, Col0 + I, Ll, M, Ind, LD, 0),
+ Ll.
+
+map_value_indent(TInd) ->
+ case TInd > 0 of
+ true ->
+ TInd;
+ false ->
+ 4
+ end.
+
cind_record([F | Fs], Nlen, Col0, Ll, M, Ind, LD, W0) ->
Nind = Nlen + 1,
{Col, W} = cind_rec(Nind, Col0, Ll, M, Ind, W0),
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index c0eea652e7..98745b13f3 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -451,6 +451,8 @@ check_type(_,[{record,_,_,_}],ets) ->
ok;
check_type(_,[{cons,_,_,_}],dbg) ->
ok;
+check_type(_,[{nil,_}],dbg) ->
+ ok;
check_type(Line0,[{match,_,{var,_,_},X}],Any) ->
check_type(Line0,[X],Any);
check_type(Line0,[{match,_,X,{var,_,_}}],Any) ->
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index f3665824f2..8c4d835432 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1292,6 +1292,10 @@ abstr_term(Fun, Line) when is_function(Fun) ->
end;
abstr_term(PPR, Line) when is_pid(PPR); is_port(PPR); is_reference(PPR) ->
{special, Line, lists:flatten(io_lib:write(PPR))};
+abstr_term(Map, Line) when is_map(Map) ->
+ {map,Line,
+ [{map_field_assoc,Line,abstr_term(K, Line),abstr_term(V, Line)} ||
+ {K,V} <- maps:to_list(Map)]};
abstr_term(Simple, Line) ->
erl_parse:abstract(Simple, erl_anno:line(Line)).
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 82a3a2be4f..28f37ef8bf 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -768,6 +768,8 @@ used_records({call,_,{atom,_,record_info},[A,{atom,_,Name}]}) ->
{name, Name, A};
used_records({call,Line,{tuple,_,[M,F]},As}) ->
used_records({call,Line,{remote,Line,M,F},As});
+used_records({type,_,record,[{atom,_,Name}|Fs]}) ->
+ {name, Name, Fs};
used_records(T) when is_tuple(T) ->
{expr, tuple_to_list(T)};
used_records(E) ->
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 9877662743..3aa4ec6dab 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
+ [{<<"3\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-18.*
%% Down to - max one major revision back
- [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
+ [{<<"3\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-18.*
}.
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index c81e72689c..1cd65fbf18 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -1087,6 +1087,10 @@ wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz,
wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
TRef, EStack);
+ {'DOWN', _MRef, process, Pid, {shutdown, _}} ->
+ wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ TRef, EStack);
+
{'DOWN', _MRef, process, Pid, normal} when RType =/= permanent ->
wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
TRef, EStack);
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index f8ba6f18e9..81f927f399 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -179,19 +179,6 @@
external_attr,
local_header_offset}).
-%% Unix extra fields (not yet supported)
--define(UNIX_EXTRA_FIELD_TAG, 16#000d).
--record(unix_extra_field, {atime,
- mtime,
- uid,
- gid}).
-
-%% extended timestamps (not yet supported)
--define(EXTENDED_TIMESTAMP_TAG, 16#5455).
-%% -record(extended_timestamp, {mtime,
-%% atime,
-%% ctime}).
-
-define(END_OF_CENTRAL_DIR_MAGIC, 16#06054b50).
-define(END_OF_CENTRAL_DIR_SZ, (4+2+2+2+2+4+4+2)).
@@ -279,7 +266,8 @@ do_openzip_get(F, #openzip{files = Files, in = In0, input = Input,
case file_name_search(F, Files) of
{#zip_file{offset = Offset},_}=ZFile ->
In1 = Input({seek, bof, Offset}, In0),
- case get_z_file(In1, Z, Input, Output, [], fun silent/1, CWD, ZFile) of
+ case get_z_file(In1, Z, Input, Output, [], fun silent/1,
+ CWD, ZFile, fun all/1) of
{file, R, _In2} -> {ok, R};
_ -> throw(file_not_found)
end;
@@ -380,9 +368,12 @@ do_unzip(F, Options) ->
{Info, In1} = get_central_dir(In0, RawIterator, Input),
%% get rid of zip-comment
Z = zlib:open(),
- Files = get_z_files(Info, Z, In1, Opts, []),
- zlib:close(Z),
- Input(close, In1),
+ Files = try
+ get_z_files(Info, Z, In1, Opts, [])
+ after
+ zlib:close(Z),
+ Input(close, In1)
+ end,
{ok, Files}.
%% Iterate over all files in a zip archive
@@ -459,11 +450,20 @@ do_zip(F, Files, Options) ->
#zip_opts{output = Output, open_opts = OpO} = Opts,
Out0 = Output({open, F, OpO}, []),
Z = zlib:open(),
- {Out1, LHS, Pos} = put_z_files(Files, Z, Out0, 0, Opts, []),
- zlib:close(Z),
- Out2 = put_central_dir(LHS, Pos, Out1, Opts),
- Out3 = Output({close, F}, Out2),
- {ok, Out3}.
+ try
+ {Out1, LHS, Pos} = put_z_files(Files, Z, Out0, 0, Opts, []),
+ zlib:close(Z),
+ Out2 = put_central_dir(LHS, Pos, Out1, Opts),
+ Out3 = Output({close, F}, Out2),
+ {ok, Out3}
+ catch
+ C:R ->
+ Stk = erlang:get_stacktrace(),
+ zlib:close(Z),
+ Output({close, F}, Out0),
+ erlang:raise(C, R, Stk)
+ end.
+
%% List zip directory contents
%%
@@ -1378,12 +1378,7 @@ cd_file_header_to_file_info(FileName,
gid = 0},
add_extra_info(FI, ExtraField).
-%% add extra info to file (some day when we implement it)
-add_extra_info(FI, <<?EXTENDED_TIMESTAMP_TAG:16/little, _Rest/binary>>) ->
- FI; % not yet supported, some other day...
-add_extra_info(FI, <<?UNIX_EXTRA_FIELD_TAG:16/little, Rest/binary>>) ->
- _UnixExtra = unix_extra_field_and_var_from_bin(Rest),
- FI; % not yet supported, and not widely used
+%% Currently, we ignore all the extra fields.
add_extra_info(FI, _) ->
FI.
@@ -1403,9 +1398,10 @@ get_z_files([{#zip_file{offset = Offset},_} = ZFile | Rest], Z, In0,
true ->
In1 = Input({seek, bof, Offset}, In0),
{In2, Acc1} =
- case get_z_file(In1, Z, Input, Output, OpO, FB, CWD, ZFile) of
+ case get_z_file(In1, Z, Input, Output, OpO, FB,
+ CWD, ZFile, Filter) of
{file, GZD, Inx} -> {Inx, [GZD | Acc0]};
- {dir, Inx} -> {Inx, Acc0}
+ {_, Inx} -> {Inx, Acc0}
end,
get_z_files(Rest, Z, In2, Opts, Acc1);
_ ->
@@ -1413,7 +1409,8 @@ get_z_files([{#zip_file{offset = Offset},_} = ZFile | Rest], Z, In0,
end.
%% get a file from the archive, reading chunks
-get_z_file(In0, Z, Input, Output, OpO, FB, CWD, {ZipFile,Extra}) ->
+get_z_file(In0, Z, Input, Output, OpO, FB,
+ CWD, {ZipFile,Extra}, Filter) ->
case Input({read, ?LOCAL_FILE_HEADER_SZ}, In0) of
{eof, In1} ->
{eof, In1};
@@ -1433,29 +1430,64 @@ get_z_file(In0, Z, Input, Output, OpO, FB, CWD, {ZipFile,Extra}) ->
end,
{BFileN, In3} = Input({read, FileNameLen + ExtraLen}, In1),
{FileName, _} = get_file_name_extra(FileNameLen, ExtraLen, BFileN),
- FileName1 = add_cwd(CWD, FileName),
- case lists:last(FileName) of
- $/ ->
- %% perhaps this should always be done?
- Output({ensure_dir,FileName1},[]),
- {dir, In3};
- _ ->
- %% FileInfo = local_file_header_to_file_info(LH)
- %%{Out, In4, CRC, UncompSize} =
- {Out, In4, CRC, _UncompSize} =
- get_z_data(CompMethod, In3, FileName1,
- CompSize, Input, Output, OpO, Z),
- In5 = skip_z_data_descriptor(GPFlag, Input, In4),
- %% TODO This should be fixed some day:
- %% In5 = Input({set_file_info, FileName, FileInfo#file_info{size=UncompSize}}, In4),
- FB(FileName),
- CRC =:= CRC32 orelse throw({bad_crc, FileName}),
- {file, Out, In5}
+ ReadAndWrite =
+ case check_valid_location(CWD, FileName) of
+ {true,FileName1} ->
+ true;
+ {false,FileName1} ->
+ Filter({ZipFile#zip_file{name = FileName1},Extra})
+ end,
+ case ReadAndWrite of
+ true ->
+ case lists:last(FileName) of
+ $/ ->
+ %% perhaps this should always be done?
+ Output({ensure_dir,FileName1},[]),
+ {dir, In3};
+ _ ->
+ %% FileInfo = local_file_header_to_file_info(LH)
+ %%{Out, In4, CRC, UncompSize} =
+ {Out, In4, CRC, _UncompSize} =
+ get_z_data(CompMethod, In3, FileName1,
+ CompSize, Input, Output, OpO, Z),
+ In5 = skip_z_data_descriptor(GPFlag, Input, In4),
+ %% TODO This should be fixed some day:
+ %% In5 = Input({set_file_info, FileName,
+ %% FileInfo#file_info{size=UncompSize}}, In4),
+ FB(FileName),
+ CRC =:= CRC32 orelse throw({bad_crc, FileName}),
+ {file, Out, In5}
+ end;
+ false ->
+ {ignore, In3}
end;
_ ->
throw(bad_local_file_header)
end.
+%% make sure FileName doesn't have relative path that points over CWD
+check_valid_location(CWD, FileName) ->
+ %% check for directory traversal exploit
+ case check_dir_level(filename:split(FileName), 0) of
+ {FileOrDir,Level} when Level < 0 ->
+ CWD1 = if CWD == "" -> "./";
+ true -> CWD
+ end,
+ error_logger:format("Illegal path: ~ts, extracting in ~ts~n",
+ [add_cwd(CWD,FileName),CWD1]),
+ {false,add_cwd(CWD, FileOrDir)};
+ _ ->
+ {true,add_cwd(CWD, FileName)}
+ end.
+
+check_dir_level([FileOrDir], Level) ->
+ {FileOrDir,Level};
+check_dir_level(["." | Parts], Level) ->
+ check_dir_level(Parts, Level);
+check_dir_level([".." | Parts], Level) ->
+ check_dir_level(Parts, Level-1);
+check_dir_level([_Dir | Parts], Level) ->
+ check_dir_level(Parts, Level+1).
get_file_name_extra(FileNameLen, ExtraLen, B) ->
case B of
@@ -1534,20 +1566,6 @@ dos_date_time_from_datetime({{Year, Month, Day}, {Hour, Min, Sec}}) ->
<<DosDate:16>> = <<YearFrom1980:7, Month:4, Day:5>>,
{DosDate, DosTime}.
-unix_extra_field_and_var_from_bin(<<TSize:16/little,
- ATime:32/little,
- MTime:32/little,
- UID:16/little,
- GID:16/little,
- Var:TSize/binary>>) ->
- {#unix_extra_field{atime = ATime,
- mtime = MTime,
- uid = UID,
- gid = GID},
- Var};
-unix_extra_field_and_var_from_bin(_) ->
- throw(bad_unix_extra_field).
-
%% A pwrite-like function for iolists (used by memory-option)
pwrite_binary(B, Pos, Bin) when byte_size(B) =:= Pos ->
diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl
index 9176a3664a..d0abe5c961 100644
--- a/lib/stdlib/test/base64_SUITE.erl
+++ b/lib/stdlib/test/base64_SUITE.erl
@@ -23,9 +23,7 @@
-include_lib("common_test/include/ct.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,
- init_per_testcase/2, end_per_testcase/2]).
+-export([all/0, suite/0, groups/0, group/1]).
%% Test cases must be exported.
-export([base64_encode/1, base64_decode/1, base64_otp_5635/1,
@@ -33,41 +31,26 @@
mime_decode_to_string/1,
roundtrip_1/1, roundtrip_2/1, roundtrip_3/1, roundtrip_4/1]).
-init_per_testcase(_, Config) ->
- Config.
-
-end_per_testcase(_, _Config) ->
- ok.
-
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
+
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,4}}].
-all() ->
+all() ->
[base64_encode, base64_decode, base64_otp_5635,
base64_otp_6279, big, illegal, mime_decode, mime_decode_to_string,
{group, roundtrip}].
-groups() ->
+groups() ->
[{roundtrip, [parallel],
[roundtrip_1, roundtrip_2, roundtrip_3, roundtrip_4]}].
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
+group(roundtrip) ->
+ %% valgrind needs a lot of time
+ [{timetrap,{minutes,10}}].
%%-------------------------------------------------------------------------
%% Test base64:encode/1.
@@ -78,9 +61,9 @@ base64_encode(Config) when is_list(Config) ->
%% One pad
<<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>),
%% No pad
- "QWxhZGRpbjpvcGVuIHNlc2Ft" =
+ "QWxhZGRpbjpvcGVuIHNlc2Ft" =
base64:encode_to_string("Aladdin:open sesam"),
-
+
"MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" =
base64:encode_to_string(<<"0123456789!@#0^&*();:<>,. []{}">>),
ok.
@@ -93,7 +76,7 @@ base64_decode(Config) when is_list(Config) ->
%% One pad
<<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ=">>),
%% No pad
- <<"Aladdin:open sesam">> =
+ <<"Aladdin:open sesam">> =
base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"),
Alphabet = list_to_binary(lists:seq(0, 255)),
@@ -208,7 +191,7 @@ mime_decode_to_string(Config) when is_list(Config) ->
%% One pad to ignore, followed by more text
"Hello World!!" = base64:mime_decode_to_string(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
%% No pad
- "Aladdin:open sesam" =
+ "Aladdin:open sesam" =
base64:mime_decode_to_string("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"),
%% Encoded base 64 strings may be divided by non base 64 chars.
%% In this cases whitespaces.
@@ -314,7 +297,7 @@ interleaved_ws_roundtrip_1([], Base64List, Bin, List) ->
random_byte_list(0, Acc) ->
Acc;
-random_byte_list(N, Acc) ->
+random_byte_list(N, Acc) ->
random_byte_list(N-1, [rand:uniform(255)|Acc]).
make_big_binary(N) ->
diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl
index ccffa2e244..1f694ea549 100644
--- a/lib/stdlib/test/edlin_expand_SUITE.erl
+++ b/lib/stdlib/test/edlin_expand_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_testcase/2, end_per_testcase/2,
init_per_group/2,end_per_group/2]).
--export([normal/1, quoted_fun/1, quoted_module/1, quoted_both/1]).
+-export([normal/1, quoted_fun/1, quoted_module/1, quoted_both/1, erl_1152/1,
+ erl_352/1]).
-include_lib("common_test/include/ct.hrl").
@@ -36,7 +37,7 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [normal, quoted_fun, quoted_module, quoted_both].
+ [normal, quoted_fun, quoted_module, quoted_both, erl_1152, erl_352].
groups() ->
[].
@@ -149,5 +150,84 @@ quoted_both(Config) when is_list(Config) ->
{yes,"weird-fun-name'()",[]} = do_expand("'ExpandTestCaps1':'#"),
ok.
+erl_1152(Config) when is_list(Config) ->
+ "\n"++"foo"++" "++[1089]++_ = do_format(["foo",[1089]]),
+ ok.
+
+erl_352(Config) when is_list(Config) ->
+ erl_352_test(3, 3),
+
+ erl_352_test(3, 75),
+ erl_352_test(3, 76, [trailing]),
+ erl_352_test(4, 74),
+ erl_352_test(4, 75, [leading]),
+ erl_352_test(4, 76, [leading, trailing]),
+
+ erl_352_test(75, 3),
+ erl_352_test(76, 3, [leading]),
+ erl_352_test(74, 4),
+ erl_352_test(75, 4, [leading]),
+ erl_352_test(76, 4, [leading]),
+
+ erl_352_test(74, 74, [leading]),
+ erl_352_test(74, 75, [leading]),
+ erl_352_test(74, 76, [leading, trailing]).
+
+erl_352_test(PrefixLen, SuffixLen) ->
+ erl_352_test(PrefixLen, SuffixLen, []).
+
+erl_352_test(PrefixLen, SuffixLen, Dots) ->
+ io:format("\nPrefixLen = ~w, SuffixLen = ~w\n", [PrefixLen, SuffixLen]),
+
+ PrefixM = lists:duplicate(PrefixLen, $p),
+ SuffixM = lists:duplicate(SuffixLen, $s),
+ LM = [PrefixM ++ S ++ SuffixM || S <- ["1", "2"]],
+ StrM = do_format(LM),
+ check_leading(StrM, "", PrefixM, SuffixM, Dots),
+
+ PrefixF = lists:duplicate(PrefixLen, $p),
+ SuffixF = lists:duplicate(SuffixLen-2, $s),
+ LF = [{PrefixF ++ S ++ SuffixF, 1} || S <- ["1", "2"]],
+ StrF = do_format(LF),
+ true = check_leading(StrF, "/1", PrefixF, SuffixF, Dots),
+
+ ok.
+
+check_leading(FormStr, ArityStr, Prefix, Suffix, Dots) ->
+ List = string:tokens(FormStr, "\n "),
+ io:format("~p\n", [List]),
+ true = lists:all(fun(L) -> length(L) < 80 end, List),
+ case lists:member(leading, Dots) of
+ true ->
+ true = lists:all(fun(L) ->
+ {"...", Rest} = lists:split(3, L),
+ check_trailing(Rest, ArityStr,
+ Suffix, Dots)
+ end, List);
+ false ->
+ true = lists:all(fun(L) ->
+ {Prefix, Rest} =
+ lists:split(length(Prefix), L),
+ check_trailing(Rest, ArityStr,
+ Suffix, Dots)
+ end, List)
+ end.
+
+check_trailing([I|Str], ArityStr, Suffix, Dots) ->
+ true = lists:member(I, [$1, $2]),
+ case lists:member(trailing, Dots) of
+ true ->
+ {Rest, "..." ++ ArityStr} =
+ lists:split(length(Str) - (3 + length(ArityStr)), Str),
+ true = lists:prefix(Rest, Suffix);
+ false ->
+ {Rest, ArityStr} =
+ lists:split(length(Str) - length(ArityStr), Str),
+ Rest =:= Suffix
+ end.
+
do_expand(String) ->
edlin_expand:expand(lists:reverse(String)).
+
+do_format(StringList) ->
+ lists:flatten(edlin_expand:format_matches(StringList)).
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
index 28d69232a0..0b9106a99c 100644
--- a/lib/stdlib/test/escript_SUITE.erl
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -28,6 +28,7 @@
strange_name/1,
emulator_flags/1,
emulator_flags_no_shebang/1,
+ two_lines/1,
module_script/1,
beam_script/1,
archive_script/1,
@@ -49,7 +50,7 @@ suite() ->
all() ->
[basic, errors, strange_name, emulator_flags,
- emulator_flags_no_shebang,
+ emulator_flags_no_shebang, two_lines,
module_script, beam_script, archive_script, epp,
create_and_extract, foldl, overflow,
archive_script_file_access, unicode].
@@ -153,6 +154,18 @@ emulator_flags(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+two_lines(Config) when is_list(Config) ->
+ Data = proplists:get_value(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ run(Dir, "two_lines -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
emulator_flags_no_shebang(Config) when is_list(Config) ->
Data = proplists:get_value(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
diff --git a/lib/stdlib/test/escript_SUITE_data/two_lines b/lib/stdlib/test/escript_SUITE_data/two_lines
new file mode 100755
index 0000000000..cf4e99639c
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/two_lines
@@ -0,0 +1,2 @@
+#! /usr/bin/env escript
+main(MainArgs) -> io:format("main:~p\n", [MainArgs]), ErlArgs = init:get_arguments(), io:format("ERL_FLAGS=~p\n", [os:getenv("ERL_FLAGS")]), io:format("unknown:~p\n",[[E || E <- ErlArgs, element(1, E) =:= unknown]]).
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 8c1c625676..00e02a06cc 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -19,7 +19,7 @@
%%
-module(ets_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1,
privacy/1,privacy_owner/2]).
@@ -31,15 +31,14 @@
-export([match_delete3/1]).
-export([firstnext/1,firstnext_concurrent/1]).
-export([slot/1]).
--export([ match1/1, match2/1, match_object/1, match_object2/1]).
--export([ dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]).
--export([ tab2file/1, tab2file2/1, tabfile_ext1/1,
- tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1, badfile/1]).
--export([ heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]).
--export([ lookup_element_mult/1]).
--export([]).
+-export([match1/1, match2/1, match_object/1, match_object2/1]).
+-export([dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]).
+-export([tab2file/1, tab2file2/1, tabfile_ext1/1,
+ tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1, badfile/1]).
+-export([heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]).
+-export([lookup_element_mult/1]).
-export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]).
--export([t_delete_object/1, t_init_table/1, t_whitebox/1,
+-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
t_delete_all_objects/1, t_insert_list/1, t_test_ms/1,
t_select_delete/1,t_ets_dets/1]).
@@ -47,6 +46,7 @@
fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1,
update_element/1, update_counter/1, evil_update_counter/1, partly_bound/1, match_heavy/1]).
-export([update_counter_with_default/1]).
+-export([update_counter_table_growth/1]).
-export([member/1]).
-export([memory/1]).
-export([select_fail/1]).
@@ -60,8 +60,7 @@
-export([otp_7665/1]).
-export([meta_wb/1]).
-export([grow_shrink/1, grow_pseudo_deleted/1, shrink_pseudo_deleted/1]).
--export([
- meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1,
+-export([meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1,
meta_lookup_named_read/1, meta_lookup_named_write/1,
meta_newdel_unnamed/1, meta_newdel_named/1]).
-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1,
@@ -94,12 +93,13 @@
rename_do/1, rename_unnamed_do/1, interface_equality_do/1, ordered_match_do/1,
ordered_do/1, privacy_do/1, empty_do/1, badinsert_do/1, time_lookup_do/1,
lookup_order_do/1, lookup_element_mult_do/1, delete_tab_do/1, delete_elem_do/1,
- match_delete_do/1, match_delete3_do/1, firstnext_do/1,
+ match_delete_do/1, match_delete3_do/1, firstnext_do/1,
slot_do/1, match1_do/1, match2_do/1, match_object_do/1, match_object2_do/1,
misc1_do/1, safe_fixtable_do/1, info_do/1, dups_do/1, heavy_lookup_do/1,
heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1,
do_heavy_concurrent/1, tab2file2_do/2, exit_large_table_owner_do/2,
types_do/1, sleeper/0, memory_do/1, update_counter_with_default_do/1,
+ update_counter_table_growth_do/1,
ms_tracee_dummy/1, ms_tracee_dummy/2, ms_tracee_dummy/3, ms_tracee_dummy/4
]).
@@ -127,7 +127,7 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,5}}].
-all() ->
+all() ->
[{group, new}, {group, insert}, {group, lookup},
{group, delete}, firstnext, firstnext_concurrent, slot,
{group, match}, t_match_spec_run,
@@ -137,6 +137,7 @@ all() ->
rename, rename_unnamed, evil_rename, update_element,
update_counter, evil_update_counter,
update_counter_with_default, partly_bound,
+ update_counter_table_growth,
match_heavy, {group, fold}, member, t_delete_object,
t_init_table, t_whitebox, t_delete_all_objects,
t_insert_list, t_test_ms, t_select_delete, t_ets_dets,
@@ -158,7 +159,7 @@ all() ->
memory_check_summary]. % MUST BE LAST
-groups() ->
+groups() ->
[{new, [],
[default, setbag, badnew, verybadnew, named, keypos2,
privacy]},
@@ -246,6 +247,7 @@ t_bucket_disappears_do(Opts) ->
%% Check ets:match_spec_run/2.
t_match_spec_run(Config) when is_list(Config) ->
+ ct:timetrap({minutes,30}), %% valgrind needs a lot
init_externals(),
EtsMem = etsmem(),
@@ -706,7 +708,7 @@ adjust_xmem([_T1,_T2,_T3,_T4], {A0,B0,C0,D0} = _Mem0) ->
{A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}.
%% Misc. whitebox tests
-t_whitebox(Config) when is_list(Config) ->
+t_whitebox(Config) when is_list(Config) ->
EtsMem = etsmem(),
repeat_for_opts(whitebox_1),
repeat_for_opts(whitebox_1),
@@ -1047,6 +1049,7 @@ do_reverse_chunked({L,C},Acc) ->
%% Test the ets:select_delete/2 and ets:select_count/2 BIFs.
t_select_delete(Config) when is_list(Config) ->
+ ct:timetrap({minutes,30}), %% valgrind needs a lot
EtsMem = etsmem(),
Tables = fill_sets_int(10000) ++ fill_sets_int(10000,[{write_concurrency,true}]),
lists:foreach
@@ -1492,15 +1495,15 @@ update_element(Config) when is_list(Config) ->
verify_etsmem(EtsMem).
update_element_opts(Opts) ->
- TupleCases = [{{key,val}, 1 ,2},
- {{val,key}, 2, 1},
- {{key,val}, 1 ,[2]},
+ TupleCases = [{{key,val}, 1 ,2},
+ {{val,key}, 2, 1},
+ {{key,val}, 1 ,[2]},
{{key,val,val}, 1, [2,3]},
{{val,key,val,val}, 2, [3,4,1]},
{{val,val,key,val}, 3, [1,4,1,2]}, % update pos1 twice
{{val,val,val,key}, 4, [2,1,2,3]}],% update pos2 twice
- lists:foreach(fun({Tuple,KeyPos,UpdPos}) -> update_element_opts(Tuple,KeyPos,UpdPos,Opts) end,
+ lists:foreach(fun({Tuple,KeyPos,UpdPos}) -> update_element_opts(Tuple,KeyPos,UpdPos,Opts) end,
TupleCases),
update_element_neg(Opts).
@@ -1516,9 +1519,9 @@ update_element_opts(Tuple,KeyPos,UpdPos,Opts) ->
true = ets:delete(OrdSet),
ok.
-update_element(T,Tuple,KeyPos,UpdPos) ->
+update_element(T,Tuple,KeyPos,UpdPos) ->
KeyList = [17,"seventeen",<<"seventeen">>,{17},list_to_binary(lists:seq(1,100)),make_ref(), self()],
- lists:foreach(fun(Key) ->
+ lists:foreach(fun(Key) ->
TupleWithKey = setelement(KeyPos,Tuple,Key),
update_element_do(T,TupleWithKey,Key,UpdPos)
end,
@@ -1553,29 +1556,29 @@ update_element_do(Tab,Tuple,Key,UpdPos) ->
{Pos, element(ToIx+1,Values)} % single {pos,value} arg
end,
- UpdateF = fun(ToIx,Rand) ->
- PosValArg = PosValArgF(ToIx,[],UpdPos,Rand,PosValArgF),
- %%io:format("update_element(~p)~n",[PosValArg]),
- ArgHash = erlang:phash2({Tab,Key,PosValArg}),
- true = ets:update_element(Tab, Key, PosValArg),
- ArgHash = erlang:phash2({Tab,Key,PosValArg}),
- NewTuple = update_tuple(PosValArg,Tuple),
- [NewTuple] = ets:lookup(Tab,Key)
+ UpdateF = fun(ToIx,Rand) ->
+ PosValArg = PosValArgF(ToIx,[],UpdPos,Rand,PosValArgF),
+ %%io:format("update_element(~p)~n",[PosValArg]),
+ ArgHash = erlang:phash2({Tab,Key,PosValArg}),
+ true = ets:update_element(Tab, Key, PosValArg),
+ ArgHash = erlang:phash2({Tab,Key,PosValArg}),
+ NewTuple = update_tuple(PosValArg,Tuple),
+ [NewTuple] = ets:lookup(Tab,Key)
end,
- LoopF = fun(_FromIx, Incr, _Times, Checksum, _MeF) when Incr >= Length ->
+ LoopF = fun(_FromIx, Incr, _Times, Checksum, _MeF) when Incr >= Length ->
Checksum; % done
- (FromIx, Incr, 0, Checksum, MeF) ->
+ (FromIx, Incr, 0, Checksum, MeF) ->
MeF(FromIx, Incr+1, Length, Checksum, MeF);
- (FromIx, Incr, Times, Checksum, MeF) ->
+ (FromIx, Incr, Times, Checksum, MeF) ->
ToIx = (FromIx + Incr) rem Length,
UpdateF(ToIx,Checksum),
- if
+ if
Incr =:= 0 -> UpdateF(ToIx,Checksum); % extra update to same value
true -> true
- end,
+ end,
MeF(ToIx, Incr, Times-1, Checksum+ToIx+1, MeF)
end,
@@ -1619,7 +1622,7 @@ update_element_neg_do(T) ->
Object = {key, 0, "Hej"},
true = ets:insert(T,Object),
- UpdateF = fun(Arg3) ->
+ UpdateF = fun(Arg3) ->
ArgHash = erlang:phash2({T,key,Arg3}),
{'EXIT',{badarg,_}} = (catch ets:update_element(T,key,Arg3)),
ArgHash = erlang:phash2({T,key,Arg3}),
@@ -1694,7 +1697,7 @@ update_counter_for(T) ->
true = ets:lookup(T, b) =:= [setelement(1, NewObj, b)],
ets:delete(T, b),
Myself(NewObj,Times-1,Arg3,Myself)
- end,
+ end,
LoopF = fun(Obj, Times, Arg3) ->
%%io:format("Loop start:\nObj = ~p\nArg3=~p\n",[Obj,Arg3]),
@@ -1803,7 +1806,7 @@ uc_mimic(Obj, [Pits|Tail], Acc) ->
uc_adder(Init, {_Pos, Add}) ->
Init + Add;
-uc_adder(Init, {_Pos, Add, Thres, Warp}) ->
+uc_adder(Init, {_Pos, Add, Thres, Warp}) ->
case Init + Add of
X when X > Thres, Add > 0 ->
Warp;
@@ -1835,7 +1838,7 @@ update_counter_neg_for(T) ->
Object = {key,0,false,1},
true = ets:insert(T,Object),
- UpdateF = fun(Arg3) ->
+ UpdateF = fun(Arg3) ->
ArgHash = erlang:phash2({T,key,Arg3}),
{'EXIT',{badarg,_}} = (catch ets:update_counter(T,key,Arg3)),
ArgHash = erlang:phash2({T,key,Arg3}),
@@ -1955,6 +1958,16 @@ update_counter_with_default_do(Opts) ->
ok.
+update_counter_table_growth(_Config) ->
+ repeat_for_opts(update_counter_table_growth_do).
+
+update_counter_table_growth_do(Opts) ->
+ Set = ets_new(b, [set | Opts]),
+ [ets:update_counter(Set, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)],
+ OrderedSet = ets_new(b, [ordered_set | Opts]),
+ [ets:update_counter(OrderedSet, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)],
+ ok.
+
%% Check that a first-next sequence always works on a fixed table.
fixtable_next(Config) when is_list(Config) ->
repeat_for_opts(fixtable_next_do, [write_concurrency,all_types]).
@@ -1965,15 +1978,16 @@ fixtable_next_do(Opts) ->
verify_etsmem(EtsMem).
do_fixtable_next(Tab) ->
- F = fun(X,T,FF) -> case X of
- 0 -> true;
- _ ->
- ets:insert(T, {X,
- integer_to_list(X),
- X rem 10}),
- FF(X-1,T,FF)
- end
- end,
+ F = fun(X,T,FF) ->
+ case X of
+ 0 -> true;
+ _ ->
+ ets:insert(T, {X,
+ integer_to_list(X),
+ X rem 10}),
+ FF(X-1,T,FF)
+ end
+ end,
F(100,Tab,F),
ets:safe_fixtable(Tab,true),
First = ets:first(Tab),
@@ -1988,7 +2002,7 @@ do_fixtable_next(Tab) ->
%% Check inserts of deleted keys in fixed bags.
fixtable_insert(Config) when is_list(Config) ->
- Combos = [[Type,{write_concurrency,WC}] || Type<- [bag,duplicate_bag],
+ Combos = [[Type,{write_concurrency,WC}] || Type<- [bag,duplicate_bag],
WC <- [false,true]],
lists:foreach(fun(Opts) -> fixtable_insert_do(Opts) end,
Combos),
@@ -2104,7 +2118,7 @@ heir_do(Opts) ->
%% Different types of heir data and link/monitor relations
TestFun = fun(Arg) -> {EtsMem,Arg} end,
- Combos = [{Data,Mode} || Data<-[foo_data, <<"binary">>,
+ Combos = [{Data,Mode} || Data<-[foo_data, <<"binary">>,
lists:seq(1,10), {17,TestFun,self()},
"The busy heir"],
Mode<-[none,link,monitor]],
@@ -2144,7 +2158,7 @@ heir_do(Opts) ->
Founder4 ! {go, Heir4},
{'DOWN', MrefH4, process, Heir4, normal} = receive_any(),
erts_debug:set_internal_state(next_pid, NextPidIx),
- DoppelGanger = spawn_monitor_with_pid(Heir4,
+ DoppelGanger = spawn_monitor_with_pid(Heir4,
fun()-> die_please = receive_any() end),
Founder4 ! die_please,
{'DOWN', MrefF4, process, Founder4, normal} = receive_any(),
@@ -2157,12 +2171,12 @@ heir_do(Opts) ->
failed ->
io:format("Failed to spawn process with pid ~p\n", [Heir4]),
true % try again
- end
+ end
end),
verify_etsmem(EtsMem).
-heir_founder(Master, HeirData, Opts) ->
+heir_founder(Master, HeirData, Opts) ->
{go,Heir} = receive_any(),
HeirTpl = case Heir of
none -> {heir,none};
@@ -2235,7 +2249,7 @@ heir_1(HeirData,Mode,Opts) ->
{'DOWN', Mref, process, Heir, normal} = receive_any().
%% Test ets:give_way/3.
-give_away(Config) when is_list(Config) ->
+give_away(Config) when is_list(Config) ->
repeat_for_opts(give_away_do).
give_away_do(Opts) ->
@@ -2374,7 +2388,7 @@ bad_table(Config) when is_list(Config) ->
ok.
bad_table_do(Opts, DummyFile) ->
- Parent = self(),
+ Parent = self(),
{Pid,Mref} = my_spawn_opt(fun()-> ets_new(priv,[private,named_table | Opts]),
Priv = ets_new(priv,[private | Opts]),
ets_new(prot,[protected,named_table | Opts]),
@@ -2429,7 +2443,7 @@ bad_table_do(Opts, DummyFile) ->
],
Info = {Opts, Priv, Prot},
lists:foreach(fun(Op) -> bad_table_op(Info, Op) end,
- OpList),
+ OpList),
Pid ! die_please,
{'DOWN', Mref, process, Pid, normal} = receive_any(),
ok.
@@ -2564,14 +2578,14 @@ interface_equality_do(Opts) ->
Set = ets_new(set,[set | Opts]),
OrderedSet = ets_new(ordered_set,[ordered_set | Opts]),
F = fun(X,T,FF) -> case X of
- 0 -> true;
- _ ->
- ets:insert(T, {X,
- integer_to_list(X),
- X rem 10}),
- FF(X-1,T,FF)
- end
- end,
+ 0 -> true;
+ _ ->
+ ets:insert(T, {X,
+ integer_to_list(X),
+ X rem 10}),
+ FF(X-1,T,FF)
+ end
+ end,
F(100,Set,F),
F(100,OrderedSet,F),
equal_results(ets, insert, Set, OrderedSet, [{a,"a"}]),
@@ -2640,20 +2654,20 @@ ordered_match_do(Opts) ->
F(3000,T1,F),
[[3,3],[3,3],[3,3]] = ets:match(T1, {'_','_','$1','$2',3}),
F2 = fun(X,Rem,Res,FF) -> case X of
- 0 -> [];
- _ ->
+ 0 -> [];
+ _ ->
case X rem Rem of
Res ->
FF(X-1,Rem,Res,FF) ++
[{X,
- integer_to_list(X),
+ integer_to_list(X),
X rem 10,
X rem 100,
X rem 1000}];
_ ->
FF(X-1,Rem,Res,FF)
end
- end
+ end
end,
OL1 = F2(3000,100,2,F2),
OL1 = ets:match_object(T1, {'_','_','_',2,'_'}),
@@ -2731,7 +2745,7 @@ pick_all_backwards(T) ->
%% Small test case for both set and bag type ets tables.
-setbag(Config) when is_list(Config) ->
+setbag(Config) when is_list(Config) ->
EtsMem = etsmem(),
Set = ets_new(set,[set]),
Bag = ets_new(bag,[bag]),
@@ -2808,7 +2822,7 @@ privacy_do(Opts) ->
privacy_check(pub,prot,priv),
- Owner ! {shift,1,{pub,prot,priv}},
+ Owner ! {shift,1,{pub,prot,priv}},
receive
{Pub1,Prot1,Priv1} ->
ok = privacy_check(Pub1,Prot1,Priv1),
@@ -2947,7 +2961,7 @@ badlookup(Config) when is_list(Config) ->
verify_etsmem(EtsMem).
%% Test that lookup returns objects in order of insertion for bag and dbag.
-lookup_order(Config) when is_list(Config) ->
+lookup_order(Config) when is_list(Config) ->
EtsMem = etsmem(),
repeat_for_opts(lookup_order_do, [write_concurrency,[bag,duplicate_bag]]),
verify_etsmem(EtsMem),
@@ -2969,7 +2983,7 @@ lookup_order_2(Opts, Fixed) ->
case Fixed of
true -> ets:safe_fixtable(T,true);
false -> ok
- end,
+ end,
S10 = {T,[],key},
S20 = check_insert(S10,A),
S30 = check_insert(S20,B),
@@ -2981,7 +2995,7 @@ lookup_order_2(Opts, Fixed) ->
S80 = check_delete(S70,D2b),
S90 = check_insert(S80,D2a),
SA0 = check_delete(S90,D3a),
- SB0 = check_delete(SA0,D3b),
+ SB0 = check_delete(SA0,D3b),
check_insert_new(SB0,D3b),
true = ets:delete(T)
@@ -2994,7 +3008,7 @@ check_insert({T,List0,Key},Val) ->
ets:insert(T,{Key,Val}),
List1 = case (ets:info(T,type) =:= bag andalso
lists:member({Key,Val},List0)) of
- true -> List0;
+ true -> List0;
false -> [{Key,Val} | List0]
end,
check_check({T,List1,Key}).
@@ -3027,8 +3041,6 @@ check_check(S={T,List,Key}) ->
Items = length(List),
S.
-
-
fill_tab(Tab,Val) ->
ets:insert(Tab,{key,Val}),
ets:insert(Tab,{{a,144},Val}),
@@ -3056,13 +3068,11 @@ lookup_element_mult_do(Opts) ->
verify_etsmem(EtsMem).
lem_data() ->
- [
- {service,'eddie2@boromir',{150,236,14,103},httpd88,self()},
+ [{service,'eddie2@boromir',{150,236,14,103},httpd88,self()},
{service,'eddie2@boromir',{150,236,14,103},httpd80,self()},
{service,'eddie3@boromir',{150,236,14,107},httpd88,self()},
{service,'eddie3@boromir',{150,236,14,107},httpd80,self()},
- {service,'eddie4@boromir',{150,236,14,108},httpd88,self()}
- ].
+ {service,'eddie4@boromir',{150,236,14,108},httpd88,self()}].
lem_crash(T) ->
L = ets:lookup_element(T, 'eddie2@boromir', 3),
@@ -3113,6 +3123,7 @@ delete_tab_do(Opts) ->
%% Check that ets:delete/1 works and that other processes can run.
delete_large_tab(Config) when is_list(Config) ->
+ ct:timetrap({minutes,30}), %% valgrind needs a lot
Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)],
EtsMem = etsmem(),
repeat_for_opts(fun(Opts) -> delete_large_tab_do(Opts,Data) end),
@@ -3135,7 +3146,7 @@ delete_large_tab_1(Name, Flags, Data, Fix) ->
lists:foreach(fun({K,_}) -> ets:delete(Tab, K) end, Data)
end,
- {priority, Prio} = process_info(self(), priority),
+ {priority, Prio} = process_info(self(), priority),
Deleter = self(),
[SchedTracer]
= start_loopers(1,
@@ -3182,7 +3193,7 @@ delete_large_tab_1(Name, Flags, Data, Fix) ->
%% Delete a large name table and try to create a new table with
%% the same name in another process.
-delete_large_named_table(Config) when is_list(Config) ->
+delete_large_named_table(Config) when is_list(Config) ->
Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)],
EtsMem = etsmem(),
repeat_for_opts(fun(Opts) -> delete_large_named_table_do(Opts,Data) end),
@@ -3553,7 +3564,7 @@ dyn_lookup(T) -> dyn_lookup(T, ets:first(T)).
dyn_lookup(_T, '$end_of_table') -> [];
dyn_lookup(T, K) ->
- NextKey=ets:next(T,K),
+ NextKey = ets:next(T,K),
case ets:next(T,K) of
NextKey ->
dyn_lookup(T, NextKey);
@@ -4072,9 +4083,9 @@ tabfile_ext2_do(Opts,Config) ->
Name = make_ref(),
[ets:insert(T,{X,integer_to_list(X)}) || X <- L],
ok = ets:tab2file(T,FName,[{extended_info,[md5sum]}]),
- true = lists:sort(ets:tab2list(T)) =:=
+ true = lists:sort(ets:tab2list(T)) =:=
lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
- true = lists:sort(ets:tab2list(T)) =:=
+ true = lists:sort(ets:tab2list(T)) =:=
lists:sort(ets:tab2list(
element(2,ets:file2tab(FName,[{verify,true}])))),
{ok, Name} = disk_log:open([{name,Name},{file,FName}]),
@@ -4089,9 +4100,9 @@ tabfile_ext2_do(Opts,Config) ->
ets:tab2list(
element(2,ets:file2tab(FName2)))),
{error,checksum_error} = ets:file2tab(FName2,[{verify,true}]),
- {value,{extended_info,[md5sum]}} =
+ {value,{extended_info,[md5sum]}} =
lists:keysearch(extended_info,1,element(2,ets:tabfile_info(FName2))),
- {value,{extended_info,[md5sum]}} =
+ {value,{extended_info,[md5sum]}} =
lists:keysearch(extended_info,1,element(2,ets:tabfile_info(FName))),
file:delete(FName),
file:delete(FName2),
@@ -4136,15 +4147,14 @@ tabfile_ext4(Config) when is_list(Config) ->
Name2 = make_ref(),
[ets:insert(TL,{X,integer_to_list(X)}) || X <- LL],
ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
- {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
+ {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
{mode, read_only}]),
{C,[_|_]} = disk_log:chunk(Name2,start),
{_,[_|_]} = disk_log:chunk(Name2,C),
disk_log:close(Name2),
- true = lists:sort(ets:tab2list(TL)) =:=
+ true = lists:sort(ets:tab2list(TL)) =:=
lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
- Res = [
- begin
+ Res = [begin
{ok,FD} = file:open(FName,[binary,read,write]),
{ok, Bin} = file:pread(FD,0,1000),
<<B1:N/binary,Ch:8,B2/binary>> = Bin,
@@ -4154,7 +4164,7 @@ tabfile_ext4(Config) when is_list(Config) ->
ok = file:close(FD),
X = case ets:file2tab(FName) of
{ok,TL2} ->
- true = lists:sort(ets:tab2list(TL)) =/=
+ true = lists:sort(ets:tab2list(TL)) =/=
lists:sort(ets:tab2list(TL2));
_ ->
totally_broken
@@ -4162,7 +4172,7 @@ tabfile_ext4(Config) when is_list(Config) ->
{error,Y} = ets:file2tab(FName,[{verify,true}]),
ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
{X,Y}
- end || N <- lists:seq(500,600) ],
+ end || N <- lists:seq(500,600)],
io:format("~p~n",[Res]),
file:delete(FName),
ok.
@@ -4391,16 +4401,14 @@ member_do(Opts) ->
build_table(L1,L2,Num) ->
- T = ets_new(xxx, [ordered_set]
- ),
+ T = ets_new(xxx, [ordered_set]),
lists:foreach(
fun(X1) ->
lists:foreach(
fun(X2) ->
F = fun(FF,N) ->
- ets:insert(T,{{X1,X2,N},
- X1, X2, N}),
- case N of
+ ets:insert(T,{{X1,X2,N}, X1, X2, N}),
+ case N of
0 ->
ok;
_ ->
@@ -4413,16 +4421,14 @@ build_table(L1,L2,Num) ->
T.
build_table2(L1,L2,Num) ->
- T = ets_new(xxx, [ordered_set]
- ),
+ T = ets_new(xxx, [ordered_set]),
lists:foreach(
fun(X1) ->
lists:foreach(
fun(X2) ->
F = fun(FF,N) ->
- ets:insert(T,{{N,X1,X2},
- N, X1, X2}),
- case N of
+ ets:insert(T,{{N,X1,X2}, N, X1, X2}),
+ case N of
0 ->
ok;
_ ->
@@ -4713,7 +4719,7 @@ del_one_by_one_dbag_3(T,From,To) ->
N = (ets:info(T,size) + 1),
Obj2 = {From, integer_to_list(From)},
ets:delete_object(T,Obj2),
- N = (ets:info(T,size) + 2)
+ N = (ets:info(T,size) + 2)
end,
Next = if
From < To ->
@@ -4760,14 +4766,14 @@ gen_dets_filename(Config,N) ->
filename:join(proplists:get_value(priv_dir,Config),
"testdets_" ++ integer_to_list(N) ++ ".dets").
-otp_6842_select_1000(Config) when is_list(Config) ->
+otp_6842_select_1000(Config) when is_list(Config) ->
Tab = ets_new(xxx,[ordered_set]),
[ets:insert(Tab,{X,X}) || X <- lists:seq(1,10000)],
AllTrue = lists:duplicate(10,true),
AllTrue =
[ length(
element(1,
- ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
+ ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
X*1000 || X <- lists:seq(1,10) ],
Sequences = [[1000,1000,1000,1000,1000,1000,1000,1000,1000,1000],
[2000,2000,2000,2000,2000],
@@ -4793,7 +4799,13 @@ check_seq(A,B,C) ->
false.
otp_6338(Config) when is_list(Config) ->
- L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,118,106>>),
+ L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,
+ 98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,
+ 0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,
+ 105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,
+ 0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,
+ 101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,
+ 118,106>>),
T = ets_new(xxx,[ordered_set]),
lists:foreach(fun(X) -> ets:insert(T,X) end,L),
[[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
@@ -4812,7 +4824,7 @@ otp_5340_do(Opts) ->
ets:delete(T).
w(_,0, _) -> ok;
-w(T,N, Id) ->
+w(T,N, Id) ->
ets:insert(T, {N, Id}),
w(T,N-1,Id).
@@ -4902,7 +4914,7 @@ meta_wb_new(Name, _, Tabs, Opts) ->
case (catch ets_new(Name,[named_table|Opts])) of
Name ->
false = lists:member(Name, Tabs),
- [Name | Tabs];
+ [Name | Tabs];
{'EXIT',{badarg,_}} ->
true = lists:member(Name, Tabs),
Tabs
@@ -5077,7 +5089,7 @@ meta_lookup_unnamed_read(Config) when is_list(Config) ->
Tab
end,
ExecF = fun(Tab) -> [{key,data}] = ets:lookup(Tab,key),
- Tab
+ Tab
end,
FiniF = fun(Tab) -> true = ets:delete(Tab)
end,
@@ -5101,7 +5113,7 @@ meta_lookup_named_read(Config) when is_list(Config) ->
Tab
end,
ExecF = fun(Tab) -> [{key,data}] = ets:lookup(Tab,key),
- Tab
+ Tab
end,
FiniF = fun(Tab) -> true = ets:delete(Tab)
end,
@@ -5160,9 +5172,9 @@ smp_fixed_delete_do() ->
ets:safe_fixtable(T,true),
Buckets = num_of_buckets(T),
InitF = fun([ProcN,NumOfProcs|_]) -> {ProcN,NumOfProcs} end,
- ExecF = fun({Key,_}) when Key > NumOfObjs ->
+ ExecF = fun({Key,_}) when Key > NumOfObjs ->
[end_of_work];
- ({Key,Increment}) ->
+ ({Key,Increment}) ->
true = ets:delete(T,Key),
{Key+Increment,Increment}
end,
@@ -5191,7 +5203,7 @@ smp_unfix_fix_do() ->
T = ets_new(foo,[public,{write_concurrency,true}]),
%%Mem = ets:info(T,memory),
NumOfObjs = 100000,
- Deleted = 50000,
+ Deleted = 50000,
filltabint(T,NumOfObjs),
ets:safe_fixtable(T,true),
Buckets = num_of_buckets(T),
@@ -5204,7 +5216,7 @@ smp_unfix_fix_do() ->
true = ets:info(T,fixed),
Deleted = get_kept_objects(T),
- {Child, Mref} =
+ {Child, Mref} =
my_spawn_opt(
fun()->
true = ets:info(T,fixed),
@@ -5263,22 +5275,19 @@ otp_8166_do(WC) ->
NumOfObjs = 3000, %% Need more than 1000 live objects for match_object to trap one time
Deleted = NumOfObjs div 2,
filltabint(T,NumOfObjs),
- {ReaderPid, ReaderMref} =
- my_spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end,
- [link, monitor, {scheduler,2}]),
- {ZombieCrPid, ZombieCrMref} =
- my_spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end,
- [link, monitor, {scheduler,3}]),
+ {ReaderPid, ReaderMref} = my_spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end,
+ [link, monitor, {scheduler,2}]),
+ {ZombieCrPid, ZombieCrMref} = my_spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end,
+ [link, monitor, {scheduler,3}]),
repeat(fun() -> ZombieCrPid ! {loop, self()},
zombies_created = receive_any(),
otp_8166_trapper(T, 10, ZombieCrPid)
- end,
- 100),
+ end, 100),
ReaderPid ! quit,
{'DOWN', ReaderMref, process, ReaderPid, normal} = receive_any(),
- ZombieCrPid ! quit,
+ ZombieCrPid ! quit,
{'DOWN', ZombieCrMref, process, ZombieCrPid, normal} = receive_any(),
false = ets:info(T,fixed),
0 = get_kept_objects(T),
@@ -5288,7 +5297,7 @@ otp_8166_do(WC) ->
%% Keep reading the table
otp_8166_reader(T, NumOfObjs) ->
- repeat_while(fun(0) ->
+ repeat_while(fun(0) ->
receive quit -> {false,done}
after 0 -> {true,NumOfObjs}
end;
@@ -5302,14 +5311,14 @@ otp_8166_reader(T, NumOfObjs) ->
otp_8166_trapper(T, Try, ZombieCrPid) ->
[] = ets:match_object(T,{'_',"Pink Unicorn"}),
case {ets:info(T,fixed),Try} of
- {true,1} ->
+ {true,1} ->
io:format("failed to provoke unsafe unfix, give up...\n",[]),
ZombieCrPid ! unfix;
- {true,_} ->
+ {true,_} ->
io:format("trapper too fast, trying again...\n",[]),
otp_8166_trapper(T, Try-1, ZombieCrPid);
{false,_} -> done
- end.
+ end.
%% Fixate table and create some pseudo-deleted objects (zombies)
@@ -5329,7 +5338,7 @@ otp_8166_zombie_creator(T,Deleted) ->
repeat_while(fun() -> case ets:info(T,safe_fixed_monotonic_time) of
{_,[_P1,_P2]} ->
false;
- _ ->
+ _ ->
receive unfix -> false
after 0 -> true
end
@@ -5386,7 +5395,7 @@ smp_select_delete(Config) when is_list(Config) ->
Mod = 17,
Zeros = erlang:make_tuple(Mod,0),
InitF = fun(_) -> Zeros end,
- ExecF = fun(Diffs0) ->
+ ExecF = fun(Diffs0) ->
case rand:uniform(20) of
1 ->
Mod = 17,
@@ -5408,7 +5417,7 @@ smp_select_delete(Config) when is_list(Config) ->
Diffs1;
false -> Diffs0
end
- end
+ end
end,
FiniF = fun(Result) -> Result end,
Results = run_workers_do(InitF,ExecF,FiniF,20000),
@@ -5419,7 +5428,7 @@ smp_select_delete(Config) when is_list(Config) ->
0, TotCnts),
io:format("LeftInTab = ~p\n",[LeftInTab]),
LeftInTab = ets:info(T,size),
- lists:foldl(fun(Cnt,Eq) ->
+ lists:foldl(fun(Cnt,Eq) ->
WasCnt = ets:select_count(T,
[{{'_', '$1'},
[{'=:=', {'rem', '$1', Mod}, Eq}],
@@ -5427,7 +5436,7 @@ smp_select_delete(Config) when is_list(Config) ->
io:format("~p: ~p =?= ~p\n",[Eq,Cnt,WasCnt]),
Cnt = WasCnt,
Eq+1
- end,
+ end,
0, TotCnts),
verify_table_load(T),
LeftInTab = ets:select_delete(T, [{{'$1','$1'}, [], [true]}]),
@@ -5465,8 +5474,8 @@ types_do(Opts) ->
%% OTP-9932: Memory overwrite when inserting large integers in compressed bag.
%% Will crash with segv on 64-bit opt if not fixed.
otp_9932(Config) when is_list(Config) ->
- T = ets:new(xxx, [bag, compressed]),
- Fun = fun(N) ->
+ T = ets:new(xxx, [bag, compressed]),
+ Fun = fun(N) ->
Key = {1316110174588445 bsl N,1316110174588583 bsl N},
S = {Key, Key},
true = ets:insert(T, S),
@@ -5482,9 +5491,9 @@ otp_9932(Config) when is_list(Config) ->
%% write_concurrency table.
otp_9423(Config) when is_list(Config) ->
InitF = fun(_) -> {0,0} end,
- ExecF = fun({S,F}) ->
- receive
- stop ->
+ ExecF = fun({S,F}) ->
+ receive
+ stop ->
io:format("~p got stop\n", [self()]),
[end_of_work | {"Succeded=",S,"Failed=",F}]
after 0 ->
@@ -5580,12 +5589,12 @@ take(Config) when is_list(Config) ->
%% Utility functions:
%%
-add_lists(L1,L2) ->
+add_lists(L1,L2) ->
add_lists(L1,L2,[]).
add_lists([],[],Acc) ->
lists:reverse(Acc);
add_lists([E1|T1], [E2|T2], Acc) ->
- add_lists(T1, T2, [E1+E2 | Acc]).
+ add_lists(T1, T2, [E1+E2 | Acc]).
run_workers(InitF,ExecF,FiniF,Laps) ->
run_workers(InitF,ExecF,FiniF,Laps, 0).
@@ -5631,9 +5640,9 @@ worker_loop(infinite, ExecF, State) ->
worker_loop(N, ExecF, State) ->
worker_loop(N-1,ExecF,ExecF(State)).
-wait_pids(Pids) ->
+wait_pids(Pids) ->
wait_pids(Pids,[]).
-wait_pids([],Acc) ->
+wait_pids([],Acc) ->
Acc;
wait_pids(Pids, Acc) ->
receive
@@ -5670,7 +5679,7 @@ etsmem() ->
wait_for_memory_deallocations(),
AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size),
- ets:info(T,memory),ets:info(T,type)}
+ ets:info(T,memory),ets:info(T,type)}
end, ets:all()),
EtsAllocInfo = erlang:system_info({allocator,ets_alloc}),
@@ -5882,7 +5891,7 @@ receive_any() ->
receive_any_spinning() ->
receive_any_spinning(1000000).
receive_any_spinning(Loops) ->
- receive_any_spinning(Loops,Loops,1).
+ receive_any_spinning(Loops,Loops,1).
receive_any_spinning(Loops,0,Tries) ->
receive M ->
io:format("Spinning process ~p got msg ~p after ~p tries\n", [self(),M,Tries]),
diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl
index b7c4d3a6e5..d48b75fde8 100644
--- a/lib/stdlib/test/filename_SUITE.erl
+++ b/lib/stdlib/test/filename_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
dirname_bin/1, extension_bin/1, join_bin/1, t_nativename_bin/1]).
-export([pathtype_bin/1,rootname_bin/1,split_bin/1]).
-export([t_basedir_api/1, t_basedir_xdg/1, t_basedir_windows/1]).
+-export([safe_relative_path/1]).
-include_lib("common_test/include/ct.hrl").
@@ -41,7 +42,8 @@ all() ->
find_src,
absname_bin, absname_bin_2,
{group,p},
- t_basedir_xdg, t_basedir_windows].
+ t_basedir_xdg, t_basedir_windows,
+ safe_relative_path].
groups() ->
[{p, [parallel],
@@ -768,6 +770,71 @@ t_nativename_bin(Config) when is_list(Config) ->
filename:nativename(<<"/usr/tmp//arne/">>)
end.
+safe_relative_path(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Root = filename:join(PrivDir, ?FUNCTION_NAME),
+ ok = file:make_dir(Root),
+ ok = file:set_cwd(Root),
+
+ ok = file:make_dir("a"),
+ ok = file:set_cwd("a"),
+ ok = file:make_dir("b"),
+ ok = file:set_cwd("b"),
+ ok = file:make_dir("c"),
+
+ ok = file:set_cwd(Root),
+
+ "a" = test_srp("a"),
+ "a/b" = test_srp("a/b"),
+ "a/b" = test_srp("a/./b"),
+ "a/b" = test_srp("a/./b/."),
+
+ "" = test_srp("a/.."),
+ "" = test_srp("a/./.."),
+ "" = test_srp("a/../."),
+ "a" = test_srp("a/b/.."),
+ "a" = test_srp("a/../a"),
+ "a" = test_srp("a/../a/../a"),
+ "a/b/c" = test_srp("a/../a/b/c"),
+
+ unsafe = test_srp("a/../.."),
+ unsafe = test_srp("a/../../.."),
+ unsafe = test_srp("a/./../.."),
+ unsafe = test_srp("a/././../../.."),
+ unsafe = test_srp("a/b/././../../.."),
+
+ unsafe = test_srp(PrivDir), %Absolute path.
+
+ ok.
+
+test_srp(RelPath) ->
+ Res = do_test_srp(RelPath),
+ Res = case do_test_srp(list_to_binary(RelPath)) of
+ Bin when is_binary(Bin) ->
+ binary_to_list(Bin);
+ Other ->
+ Other
+ end.
+
+do_test_srp(RelPath) ->
+ {ok,Root} = file:get_cwd(),
+ ok = file:set_cwd(RelPath),
+ {ok,Cwd} = file:get_cwd(),
+ ok = file:set_cwd(Root),
+ case filename:safe_relative_path(RelPath) of
+ unsafe ->
+ true = length(Cwd) < length(Root),
+ unsafe;
+ "" ->
+ "";
+ SafeRelPath ->
+ ok = file:set_cwd(SafeRelPath),
+ {ok,Cwd} = file:get_cwd(),
+ true = length(Cwd) >= length(Root),
+ ok = file:set_cwd(Root),
+ SafeRelPath
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% basedirs
t_basedir_api(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index 364314f91b..99ac0c3951 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,33 +37,33 @@ all() ->
{group, stop_handle_event},
{group, abnormal},
{group, abnormal_handle_event},
- shutdown, stop_and_reply, event_order,
+ shutdown, stop_and_reply, state_enter, event_order,
+ state_timeout, event_types, code_change,
{group, sys},
hibernate, enter_loop].
groups() ->
- [{start, [],
- [start1, start2, start3, start4, start5, start6, start7,
- start8, start9, start10, start11, start12, next_events]},
- {start_handle_event, [],
- [start1, start2, start3, start4, start5, start6, start7,
- start8, start9, start10, start11, start12, next_events]},
- {stop, [],
- [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]},
- {stop_handle_event, [],
- [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]},
- {abnormal, [], [abnormal1, abnormal2]},
- {abnormal_handle_event, [], [abnormal1, abnormal2]},
- {sys, [],
- [sys1, code_change,
- call_format_status,
- error_format_status, terminate_crash_format,
- get_state, replace_state]},
- {sys_handle_event, [],
- [sys1,
- call_format_status,
- error_format_status, terminate_crash_format,
- get_state, replace_state]}].
+ [{start, [], tcs(start)},
+ {start_handle_event, [], tcs(start)},
+ {stop, [], tcs(stop)},
+ {stop_handle_event, [], tcs(stop)},
+ {abnormal, [], tcs(abnormal)},
+ {abnormal_handle_event, [], tcs(abnormal)},
+ {sys, [], tcs(sys)},
+ {sys_handle_event, [], tcs(sys)}].
+
+tcs(start) ->
+ [start1, start2, start3, start4, start5, start6, start7,
+ start8, start9, start10, start11, start12, next_events];
+tcs(stop) ->
+ [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10];
+tcs(abnormal) ->
+ [abnormal1, abnormal1clean, abnormal1dirty, abnormal2];
+tcs(sys) ->
+ [sys1, call_format_status,
+ error_format_status, terminate_crash_format,
+ get_state, replace_state].
+
init_per_suite(Config) ->
Config.
@@ -452,8 +452,52 @@ abnormal1(Config) ->
gen_statem:call(Name, {delayed_answer,1000}, 10),
Reason),
ok = gen_statem:stop(Name),
+ ?t:sleep(1100),
+ ok = verify_empty_msgq().
+
+%% Check that time outs in calls work
+abnormal1clean(Config) ->
+ Name = abnormal1clean,
+ LocalSTM = {local,Name},
+
+ {ok, _Pid} =
+ gen_statem:start(LocalSTM, ?MODULE, start_arg(Config, []), []),
+
+ %% timeout call.
+ delayed =
+ gen_statem:call(Name, {delayed_answer,1}, {clean_timeout,100}),
+ {timeout,_} =
+ ?EXPECT_FAILURE(
+ gen_statem:call(
+ Name, {delayed_answer,1000}, {clean_timeout,10}),
+ Reason),
+ ok = gen_statem:stop(Name),
+ ?t:sleep(1100),
ok = verify_empty_msgq().
+%% Check that time outs in calls work
+abnormal1dirty(Config) ->
+ Name = abnormal1dirty,
+ LocalSTM = {local,Name},
+
+ {ok, _Pid} =
+ gen_statem:start(LocalSTM, ?MODULE, start_arg(Config, []), []),
+
+ %% timeout call.
+ delayed =
+ gen_statem:call(Name, {delayed_answer,1}, {dirty_timeout,100}),
+ {timeout,_} =
+ ?EXPECT_FAILURE(
+ gen_statem:call(
+ Name, {delayed_answer,1000}, {dirty_timeout,10}),
+ Reason),
+ ok = gen_statem:stop(Name),
+ ?t:sleep(1100),
+ case flush() of
+ [{Ref,delayed}] when is_reference(Ref) ->
+ ok
+ end.
+
%% Check that bad return values makes the stm crash. Note that we must
%% trap exit since we must link to get the real bad_return_ error
abnormal2(Config) ->
@@ -461,10 +505,10 @@ abnormal2(Config) ->
{ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []),
%% bad return value in the gen_statem loop
- {{bad_return_value,badreturn},_} =
+ {{bad_return_from_state_function,badreturn},_} =
?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason),
receive
- {'EXIT',Pid,{bad_return_value,badreturn}} -> ok
+ {'EXIT',Pid,{bad_return_from_state_function,badreturn}} -> ok
after 5000 ->
ct:fail(gen_statem_did_not_die)
end,
@@ -513,7 +557,8 @@ stop_and_reply(_Config) ->
{stop_and_reply,Reason,
[R1,{reply,From2,Reply2}]}
end},
- {ok,STM} = gen_statem:start_link(?MODULE, {map_statem,Machine}, []),
+ {ok,STM} =
+ gen_statem:start_link(?MODULE, {map_statem,Machine,[]}, []),
Self = self(),
Tag1 = make_ref(),
@@ -538,6 +583,76 @@ stop_and_reply(_Config) ->
+state_enter(_Config) ->
+ process_flag(trap_exit, true),
+ Self = self(),
+
+ Machine =
+ %% Abusing the internal format of From...
+ #{init =>
+ fun () ->
+ {ok,start,1}
+ end,
+ start =>
+ fun (enter, Prev, N) ->
+ Self ! {enter,start,Prev,N},
+ {keep_state,N + 1};
+ (internal, Prev, N) ->
+ Self ! {internal,start,Prev,N},
+ {keep_state,N + 1};
+ ({call,From}, repeat, N) ->
+ {repeat_state,N + 1,
+ [{reply,From,{repeat,start,N}}]};
+ ({call,From}, echo, N) ->
+ {next_state,wait,N + 1,
+ {reply,From,{echo,start,N}}};
+ ({call,From}, {stop,Reason}, N) ->
+ {stop_and_reply,Reason,
+ [{reply,From,{stop,N}}],N + 1}
+ end,
+ wait =>
+ fun (enter, Prev, N) when N < 5 ->
+ {repeat_state,N + 1,
+ {reply,{Self,N},{enter,Prev}}};
+ (enter, Prev, N) ->
+ Self ! {enter,wait,Prev,N},
+ {keep_state,N + 1};
+ ({call,From}, repeat, N) ->
+ {repeat_state_and_data,
+ [{reply,From,{repeat,wait,N}}]};
+ ({call,From}, echo, N) ->
+ {next_state,start,N + 1,
+ [{next_event,internal,wait},
+ {reply,From,{echo,wait,N}}]}
+ end},
+ {ok,STM} =
+ gen_statem:start_link(
+ ?MODULE, {map_statem,Machine,[state_enter]}, []),
+
+ [{enter,start,start,1}] = flush(),
+ {echo,start,2} = gen_statem:call(STM, echo),
+ [{3,{enter,start}},{4,{enter,start}},{enter,wait,start,5}] = flush(),
+ {wait,[6|_]} = sys:get_state(STM),
+ {repeat,wait,6} = gen_statem:call(STM, repeat),
+ [{enter,wait,wait,6}] = flush(),
+ {echo,wait,7} = gen_statem:call(STM, echo),
+ [{enter,start,wait,8},{internal,start,wait,9}] = flush(),
+ {repeat,start,10} = gen_statem:call(STM, repeat),
+ [{enter,start,start,11}] = flush(),
+ {stop,12} = gen_statem:call(STM, {stop,bye}),
+ [{'EXIT',STM,bye}] = flush(),
+
+ {noproc,_} =
+ ?EXPECT_FAILURE(gen_statem:call(STM, hej), Reason),
+ case flush() of
+ [] ->
+ ok;
+ Other2 ->
+ ct:fail({unexpected,Other2})
+ end.
+
+
+
event_order(_Config) ->
process_flag(trap_exit, true),
@@ -580,7 +695,7 @@ event_order(_Config) ->
Result
end},
- {ok,STM} = gen_statem:start_link(?MODULE, {map_statem,Machine}, []),
+ {ok,STM} = gen_statem:start_link(?MODULE, {map_statem,Machine,[]}, []),
Self = self(),
Tag1 = make_ref(),
gen_statem:cast(STM, {reply,{Self,Tag1},ok1}),
@@ -610,6 +725,165 @@ event_order(_Config) ->
+state_timeout(_Config) ->
+ process_flag(trap_exit, true),
+
+ Machine =
+ #{init =>
+ fun () ->
+ {ok,start,0}
+ end,
+ start =>
+ fun
+ ({call,From}, {go,Time}, 0) ->
+ self() ! message_to_self,
+ {next_state, state1, {Time,From},
+ %% Verify that internal events goes before external
+ [{state_timeout,Time,1},
+ {next_event,internal,1}]}
+ end,
+ state1 =>
+ fun
+ (internal, 1, Data) ->
+ %% Verify that a state change cancels timeout 1
+ {next_state, state2, Data,
+ [{timeout,0,2},
+ {state_timeout,0,2},
+ {next_event,internal,2}]}
+ end,
+ state2 =>
+ fun
+ (internal, 2, Data) ->
+ %% Verify that {state_timeout,0,_}
+ %% comes after next_event and that
+ %% {timeout,0,_} is cancelled by
+ %% pending {state_timeout,0,_}
+ {keep_state, {ok,2,Data},
+ [{timeout,0,3}]};
+ (state_timeout, 2, {ok,2,Data}) ->
+ %% Verify that timeout 0's are processed
+ %% in order
+ {keep_state, {ok,3,Data},
+ [{timeout,0,4},{state_timeout,0,5}]};
+ (timeout, 4, {ok,3,Data}) ->
+ %% Verify that timeout 0 is cancelled by
+ %% enqueued state_timeout 0 and that
+ %% multiple state_timeout 0 can be enqueued
+ {keep_state, {ok,4,Data},
+ [{state_timeout,0,6},{timeout,0,7}]};
+ (state_timeout, 5, {ok,4,Data}) ->
+ {keep_state, {ok,5,Data}};
+ (state_timeout, 6, {ok,5,{Time,From}}) ->
+ {next_state, state3, 6,
+ [{reply,From,ok},
+ {state_timeout,Time,8}]}
+ end,
+ state3 =>
+ fun
+ (info, message_to_self, 6) ->
+ {keep_state, 7};
+ ({call,From}, check, 7) ->
+ {keep_state, From};
+ (state_timeout, 8, From) ->
+ {stop_and_reply, normal,
+ {reply,From,ok}}
+ end},
+
+ {ok,STM} = gen_statem:start_link(?MODULE, {map_statem,Machine,[]}, []),
+ sys:trace(STM, true),
+ TRef = erlang:start_timer(1000, self(), kull),
+ ok = gen_statem:call(STM, {go,500}),
+ ok = gen_statem:call(STM, check),
+ receive
+ {timeout,TRef,kull} ->
+ ct:fail(late_timeout)
+ after 0 ->
+ receive
+ {timeout,TRef,kull} ->
+ ok
+ after 1000 ->
+ ct:fail(no_check_timeout)
+ end
+ end,
+ receive
+ {'EXIT',STM,normal} ->
+ ok
+ after 500 ->
+ ct:fail(did_not_stop)
+ end,
+
+ verify_empty_msgq().
+
+
+
+%% Test that all event types can be sent with {next_event,EventType,_}
+event_types(_Config) ->
+ process_flag(trap_exit, true),
+
+ Machine =
+ %% Abusing the internal format of From...
+ #{init =>
+ fun () ->
+ {ok, start, undefined}
+ end,
+ start =>
+ fun ({call,_} = Call, Req, undefined) ->
+ {next_state, state1, undefined,
+ [{next_event,internal,1},
+ {next_event,state_timeout,2},
+ {next_event,timeout,3},
+ {next_event,info,4},
+ {next_event,cast,5},
+ {next_event,Call,Req}]}
+ end,
+ state1 =>
+ fun (internal, 1, undefined) ->
+ {next_state, state2, undefined}
+ end,
+ state2 =>
+ fun (state_timeout, 2, undefined) ->
+ {next_state, state3, undefined}
+ end,
+ state3 =>
+ fun (timeout, 3, undefined) ->
+ {next_state, state4, undefined}
+ end,
+ state4 =>
+ fun (info, 4, undefined) ->
+ {next_state, state5, undefined}
+ end,
+ state5 =>
+ fun (cast, 5, undefined) ->
+ {next_state, state6, undefined}
+ end,
+ state6 =>
+ fun ({call,From}, stop, undefined) ->
+ {stop_and_reply, shutdown,
+ [{reply,From,stopped}]}
+ end},
+ {ok,STM} =
+ gen_statem:start_link(
+ ?MODULE, {map_statem,Machine,[]}, [{debug,[trace]}]),
+
+ stopped = gen_statem:call(STM, stop),
+ receive
+ {'EXIT',STM,shutdown} ->
+ ok
+ after 500 ->
+ ct:fail(did_not_stop)
+ end,
+
+ {noproc,_} =
+ ?EXPECT_FAILURE(gen_statem:call(STM, hej), Reason),
+ case flush() of
+ [] ->
+ ok;
+ Other2 ->
+ ct:fail({unexpected,Other2})
+ end.
+
+
+
sys1(Config) ->
{ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []),
{status, Pid, {module,gen_statem}, _} = sys:get_status(Pid),
@@ -633,11 +907,13 @@ sys1(Config) ->
sys:resume(Pid),
stop_it(Pid).
-code_change(Config) ->
- Mode = handle_event_function,
- {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []),
+code_change(_Config) ->
+ {ok,Pid} =
+ gen_statem:start(
+ ?MODULE, {callback_mode,state_functions,[]}, []),
{idle,data} = sys:get_state(Pid),
sys:suspend(Pid),
+ Mode = handle_event_function,
sys:change_code(Pid, ?MODULE, old_vsn, Mode),
sys:resume(Pid),
{idle,{old_vsn,data,Mode}} = sys:get_state(Pid),
@@ -708,7 +984,7 @@ error_format_status(Config) ->
gen_statem:start(
?MODULE, start_arg(Config, {data,Data}), []),
%% bad return value in the gen_statem loop
- {{bad_return_value,badreturn},_} =
+ {{bad_return_from_state_function,badreturn},_} =
?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason),
receive
{error,_,
@@ -716,7 +992,7 @@ error_format_status(Config) ->
"** State machine"++_,
[Pid,{{call,_},badreturn},
{formatted,idle,Data},
- error,{bad_return_value,badreturn}|_]}} ->
+ error,{bad_return_from_state_function,badreturn}|_]}} ->
ok;
Other when is_tuple(Other), element(1, Other) =:= error ->
error_logger_forwarder:unregister(),
@@ -1029,11 +1305,7 @@ enter_loop(_Config) ->
end,
%% Process not started using proc_lib
- CallbackMode = state_functions,
- Pid4 =
- spawn_link(
- gen_statem, enter_loop,
- [?MODULE,[],CallbackMode,state0,[]]),
+ Pid4 = spawn_link(gen_statem, enter_loop, [?MODULE,[],state0,[]]),
receive
{'EXIT',Pid4,process_was_not_started_by_proc_lib} ->
ok
@@ -1107,21 +1379,18 @@ enter_loop(Reg1, Reg2) ->
anon -> ignore
end,
proc_lib:init_ack({ok, self()}),
- CallbackMode = state_functions,
case Reg2 of
local ->
gen_statem:enter_loop(
- ?MODULE, [], CallbackMode, state0, [], {local,armitage});
+ ?MODULE, [], state0, [], {local,armitage});
global ->
gen_statem:enter_loop(
- ?MODULE, [], CallbackMode, state0, [], {global,armitage});
+ ?MODULE, [], state0, [], {global,armitage});
via ->
gen_statem:enter_loop(
- ?MODULE, [], CallbackMode, state0, [],
- {via, dummy_via, armitage});
+ ?MODULE, [], state0, [], {via, dummy_via, armitage});
anon ->
- gen_statem:enter_loop(
- ?MODULE, [], CallbackMode, state0, [])
+ gen_statem:enter_loop(?MODULE, [], state0, [])
end.
@@ -1266,33 +1535,39 @@ init(stop_shutdown) ->
{stop,shutdown};
init(sleep) ->
?t:sleep(1000),
- {state_functions,idle,data};
+ {ok,idle,data};
init(hiber) ->
- {state_functions,hiber_idle,[]};
+ {ok,hiber_idle,[]};
init(hiber_now) ->
- {state_functions,hiber_idle,[],[hibernate]};
+ {ok,hiber_idle,[],[hibernate]};
init({data, Data}) ->
- {state_functions,idle,Data};
+ {ok,idle,Data};
init({callback_mode,CallbackMode,Arg}) ->
- case init(Arg) of
- {_,State,Data,Ops} ->
- {CallbackMode,State,Data,Ops};
- {_,State,Data} ->
- {CallbackMode,State,Data};
- Other ->
- Other
- end;
-init({map_statem,#{init := Init}=Machine}) ->
+ ets:new(?MODULE, [named_table,private]),
+ ets:insert(?MODULE, {callback_mode,CallbackMode}),
+ init(Arg);
+init({map_statem,#{init := Init}=Machine,Modes}) ->
+ ets:new(?MODULE, [named_table,private]),
+ ets:insert(?MODULE, {callback_mode,[handle_event_function|Modes]}),
case Init() of
{ok,State,Data,Ops} ->
- {handle_event_function,State,[Data|Machine],Ops};
+ {ok,State,[Data|Machine],Ops};
{ok,State,Data} ->
- {handle_event_function,State,[Data|Machine]};
+ {ok,State,[Data|Machine]};
Other ->
Other
end;
init([]) ->
- {state_functions,idle,data}.
+ {ok,idle,data}.
+
+callback_mode() ->
+ try ets:lookup(?MODULE, callback_mode) of
+ [{callback_mode,CallbackMode}] ->
+ CallbackMode
+ catch
+ error:badarg ->
+ state_functions
+ end.
terminate(_, _State, crash_terminate) ->
exit({crash,terminate});
@@ -1530,6 +1805,10 @@ handle_event(
{keep_state,[NewData|Machine]};
{keep_state,NewData,Ops} ->
{keep_state,[NewData|Machine],Ops};
+ {repeat_state,NewData} ->
+ {repeat_state,[NewData|Machine]};
+ {repeat_state,NewData,Ops} ->
+ {repeat_state,[NewData|Machine],Ops};
Other ->
Other
end;
@@ -1568,7 +1847,12 @@ wrap_result(Result) ->
code_change(OldVsn, State, Data, CallbackMode) ->
- {CallbackMode,State,{OldVsn,Data,CallbackMode}}.
+ io:format(
+ "code_change(~p, ~p, ~p, ~p)~n", [OldVsn,State,Data,CallbackMode]),
+ ets:insert(?MODULE, {callback_mode,CallbackMode}),
+ io:format(
+ "code_change(~p, ~p, ~p, ~p)~n", [OldVsn,State,Data,CallbackMode]),
+ {ok,State,{OldVsn,Data,CallbackMode}}.
format_status(terminate, [_Pdict,State,Data]) ->
{formatted,State,Data};
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 7d48cbc97c..6e99619324 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1,
otp_10836/1, io_lib_width_too_small/1,
io_with_huge_message_queue/1, format_string/1,
- maps/1, coverage/1]).
+ maps/1, coverage/1, otp_14175/1]).
-export([pretty/2]).
@@ -61,7 +61,7 @@ all() ->
printable_range, bad_printable_range,
io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836,
io_lib_width_too_small, io_with_huge_message_queue,
- format_string, maps, coverage].
+ format_string, maps, coverage, otp_14175].
%% Error cases for output.
error_1(Config) when is_list(Config) ->
@@ -415,13 +415,13 @@ otp_6354(Config) when is_list(Config) ->
bt(<<"#rrrrr{\n"
" f1 = 1,\n"
" f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n"
- " f3 = \n"
+ " f3 =\n"
" #rrrrr{\n"
" f1 = h,f2 = i,\n"
- " f3 = \n"
+ " f3 =\n"
" #rrrrr{\n"
" f1 = aa,\n"
- " f2 = \n"
+ " f2 =\n"
" #rrrrr{\n"
" f1 = #rrrrr{f1 = a,f2 = b,f3 = c},\n"
" f2 = 2,f3 = 3},\n"
@@ -431,17 +431,17 @@ otp_6354(Config) when is_list(Config) ->
2,3},bb}}},
-1)),
bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
- " bbbbbbbbbbbbbbbbbbbb = \n"
+ " bbbbbbbbbbbbbbbbbbbb =\n"
" #d{aaaaaaaaaaaaaaaaaaaa = a,bbbbbbbbbbbbbbbbbbbb = b,\n"
" cccccccccccccccccccc = c,dddddddddddddddddddd = d,\n"
" eeeeeeeeeeeeeeeeeeee = e},\n"
" cccccccccccccccccccc = 3,\n"
- " dddddddddddddddddddd = \n"
+ " dddddddddddddddddddd =\n"
" #d{aaaaaaaaaaaaaaaaaaaa = h,bbbbbbbbbbbbbbbbbbbb = i,\n"
- " cccccccccccccccccccc = \n"
+ " cccccccccccccccccccc =\n"
" #d{aaaaaaaaaaaaaaaaaaaa = aa,"
"bbbbbbbbbbbbbbbbbbbb = bb,\n"
- " cccccccccccccccccccc = \n"
+ " cccccccccccccccccccc =\n"
" #d{aaaaaaaaaaaaaaaaaaaa = 1,"
"bbbbbbbbbbbbbbbbbbbb = 2,\n"
" cccccccccccccccccccc = 3,"
@@ -534,21 +534,21 @@ otp_6354(Config) when is_list(Config) ->
p({A,{A,{A,{A,{A,{A,{A,
{g,{h,{i,{j,{k,{l,{m,{n,{o,{a}}}}}}}}}}}}}}}}}, 100)),
bt(<<"#c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
- " f1 = \n"
+ " f1 =\n"
" #c{\n"
" f1 = #c{f1 = #c{f1 = #c{f1 = a,"
"f2 = b},f2 = b},f2 = b},\n"
@@ -564,13 +564,13 @@ otp_6354(Config) when is_list(Config) ->
p({c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,a,b},b},b},b},b},b},
b},b},b},b},b},b}, -1)),
bt(<<"#rrrrr{\n"
- " f1 = \n"
+ " f1 =\n"
" #rrrrr{\n"
- " f1 = \n"
+ " f1 =\n"
" #rrrrr{\n"
- " f1 = \n"
+ " f1 =\n"
" #rrrrr{\n"
- " f1 = \n"
+ " f1 =\n"
" {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a,"
"f3 = b}},b},\n"
" f2 = {rrrrr,c,d},\n"
@@ -2106,3 +2106,200 @@ coverage(_Config) ->
io:format("~s\n", [S2]),
ok.
+
+otp_14175(_Config) ->
+ "..." = p(#{}, 0),
+ "#{}" = p(#{}, 1),
+ "#{...}" = p(#{a => 1}, 1),
+ "#{#{} => a}" = p(#{#{} => a}, 2),
+ "#{a => 1,...}" = p(#{a => 1, b => 2}, 2),
+ "#{a => 1,b => 2}" = p(#{a => 1, b => 2}, -1),
+
+ M = #{kaaaaaaaaaaaaaaaaaaa => v1,kbbbbbbbbbbbbbbbbbbb => v2,
+ kccccccccccccccccccc => v3,kddddddddddddddddddd => v4,
+ keeeeeeeeeeeeeeeeeee => v5},
+ "#{...}" = p(M, 1),
+ mt("#{kaaaaaaaaaaaaaaaaaaaa => v1,...}", p(M, 2)),
+ mt("#{kaaaaaaaaaaaaaaaaaaaa => 1,kbbbbbbbbbbbbbbbbbbbb => 2,...}",
+ p(M, 3)),
+
+ mt("#{kaaaaaaaaaaaaaaaaaaa => v1,kbbbbbbbbbbbbbbbbbbb => v2,\n"
+ " kccccccccccccccccccc => v3,...}", p(M, 4)),
+
+ mt("#{kaaaaaaaaaaaaaaaaaaa => v1,kbbbbbbbbbbbbbbbbbbb => v2,\n"
+ " kccccccccccccccccccc => v3,kddddddddddddddddddd => v4,...}",
+ p(M, 5)),
+
+ mt("#{kaaaaaaaaaaaaaaaaaaa => v1,kbbbbbbbbbbbbbbbbbbb => v2,\n"
+ " kccccccccccccccccccc => v3,kddddddddddddddddddd => v4,\n"
+ " keeeeeeeeeeeeeeeeeee => v5}", p(M, 6)),
+
+ weak("#{aaaaaaaaaaaaaaaaaaa => 1,bbbbbbbbbbbbbbbbbbbb => 2,\n"
+ " cccccccccccccccccccc => {3},\n"
+ " dddddddddddddddddddd => 4,eeeeeeeeeeeeeeeeeeee => 5}",
+ p(#{aaaaaaaaaaaaaaaaaaa => 1,bbbbbbbbbbbbbbbbbbbb => 2,
+ cccccccccccccccccccc => {3},
+ dddddddddddddddddddd => 4,eeeeeeeeeeeeeeeeeeee => 5}, -1)),
+
+ M2 = #{dddddddddddddddddddd => {1}, {aaaaaaaaaaaaaaaaaaaa} => 2,
+ {bbbbbbbbbbbbbbbbbbbb} => 3,{cccccccccccccccccccc} => 4,
+ {eeeeeeeeeeeeeeeeeeee} => 5},
+ "#{...}" = p(M2, 1),
+ weak("#{dddddddddddddddddddd => {...},...}", p(M2, 2)),
+ weak("#{dddddddddddddddddddd => {1},{...} => 2,...}", p(M2, 3)),
+
+ weak("#{dddddddddddddddddddd => {1},\n"
+ " {aaaaaaaaaaaaaaaaaaaa} => 2,\n"
+ " {...} => 3,...}", p(M2, 4)),
+
+ weak("#{dddddddddddddddddddd => {1},\n"
+ " {aaaaaaaaaaaaaaaaaaaa} => 2,\n"
+ " {bbbbbbbbbbbbbbbbbbbb} => 3,\n"
+ " {...} => 4,...}", p(M2, 5)),
+
+ weak("#{dddddddddddddddddddd => {1},\n"
+ " {aaaaaaaaaaaaaaaaaaaa} => 2,\n"
+ " {bbbbbbbbbbbbbbbbbbbb} => 3,\n"
+ " {cccccccccccccccccccc} => 4,\n"
+ " {...} => 5}", p(M2, 6)),
+
+ weak("#{dddddddddddddddddddd => {1},\n"
+ " {aaaaaaaaaaaaaaaaaaaa} => 2,\n"
+ " {bbbbbbbbbbbbbbbbbbbb} => 3,\n"
+ " {cccccccccccccccccccc} => 4,\n"
+ " {eeeeeeeeeeeeeeeeeeee} => 5}", p(M2, 7)),
+
+ M3 = #{kaaaaaaaaaaaaaaaaaaa => vuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,
+ kbbbbbbbbbbbbbbbbbbb => vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv,
+ kccccccccccccccccccc => vxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
+ kddddddddddddddddddd => vyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,
+ keeeeeeeeeeeeeeeeeee => vzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz},
+
+ mt("#{aaaaaaaaaaaaaaaaaaaa =>\n"
+ " uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,\n"
+ " bbbbbbbbbbbbbbbbbbbb =>\n"
+ " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv,\n"
+ " cccccccccccccccccccc =>\n"
+ " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,\n"
+ " dddddddddddddddddddd =>\n"
+ " yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,\n"
+ " eeeeeeeeeeeeeeeeeeee =>\n"
+ " zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz}", p(M3, -1)),
+
+ R4 = {c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,a,b},b},b},b},b},b},
+ b},b},b},b},b},b},
+ M4 = #{aaaaaaaaaaaaaaaaaaaa => R4,
+ bbbbbbbbbbbbbbbbbbbb => R4,
+ cccccccccccccccccccc => R4,
+ dddddddddddddddddddd => R4,
+ eeeeeeeeeeeeeeeeeeee => R4},
+
+ weak("#{aaaaaaaaaaaaaaaaaaaa =>\n"
+ " #c{f1 = #c{f1 = #c{...},f2 = b},f2 = b},\n"
+ " bbbbbbbbbbbbbbbbbbbb => #c{f1 = #c{f1 = {...},...},f2 = b},\n"
+ " cccccccccccccccccccc => #c{f1 = #c{...},f2 = b},\n"
+ " dddddddddddddddddddd => #c{f1 = {...},...},\n"
+ " eeeeeeeeeeeeeeeeeeee => #c{...}}", p(M4, 7)),
+
+ M5 = #{aaaaaaaaaaaaaaaaaaaa => R4},
+ mt("#{aaaaaaaaaaaaaaaaaaaa =>\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 =\n"
+ " #c{\n"
+ " f1 = #c{f1 = #c{f1 = #c{f1 = a,f2 = b},f2 = b},"
+ "f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b}}", p(M5, -1)),
+ ok.
+
+%% Just check number of newlines and dots ('...').
+-define(WEAK, true).
+
+-ifdef(WEAK).
+
+weak(S, R) ->
+ (nl(S) =:= nl(R) andalso
+ dots(S) =:= dots(S)).
+
+nl(S) ->
+ [C || C <- S, C =:= $\n].
+
+dots(S) ->
+ [C || C <- S, C =:= $\.].
+
+-else. % WEAK
+
+weak(S, R) ->
+ mt(S, R).
+
+-endif. % WEAK
+
+%% If EXACT is defined: mt() matches strings exactly.
+%%
+%% if EXACT is not defined: do not match the strings exactly, but
+%% compare them assuming that all map keys and all map values are
+%% equal (by assuming all map keys and all map values have the same
+%% length and begin with $k and $v respectively).
+
+%-define(EXACT, true).
+
+-ifdef(EXACT).
+
+mt(S, R) ->
+ S =:= R.
+
+-else. % EXACT
+
+mt(S, R) ->
+ anon(S) =:= anon(R).
+
+anon(S) ->
+ {ok, Ts0, _} = erl_scan:string(S, 1, [text]),
+ Ts = anon1(Ts0),
+ text(Ts).
+
+anon1([]) -> [];
+anon1([{atom,Anno,Atom}=T|Ts]) ->
+ case erl_anno:text(Anno) of
+ "k" ++ _ ->
+ NewAnno = erl_anno:set_text("key", Anno),
+ [{atom,NewAnno,Atom}|anon1(Ts)];
+ "v" ++ _ ->
+ NewAnno = erl_anno:set_text("val", Anno),
+ [{atom,NewAnno,Atom}|anon1(Ts)];
+ _ ->
+ [T|anon1(Ts)]
+ end;
+anon1([T|Ts]) ->
+ [T|anon1(Ts)].
+
+text(Ts) ->
+ lists:append(text1(Ts)).
+
+text1([]) -> [];
+text1([T|Ts]) ->
+ Anno = element(2, T),
+ [erl_anno:text(Anno) | text1(Ts)].
+
+-endif. % EXACT
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index 1c5faa960b..f35013b1b2 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -296,6 +296,8 @@ basic_dbg(Config) when is_list(Config) ->
compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> bindings() end)">>),
[{['$1','$2'],[],['$_']}] =
compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> object() end)">>),
+ [{[],[],[{return_trace}]}] =
+ compile_and_run(<<"dbg:fun2ms(fun([]) -> return_trace() end)">>),
ok.
%% Test calling of ets/dbg:fun2ms from the shell.
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 2bd940020c..846c2c56f4 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -869,11 +869,12 @@ eval_unique(Config) when is_list(Config) ->
[a] = qlc:e(Q2, {unique_all, true})
">>,
- <<"Q = qlc:q([SQV || SQV <- qlc:q([X || X <- [1,2,1]],unique)],
+ <<"Q = qlc:q([SQV || SQV <- qlc:q([X || X <- [1,2,1,#{a => 1}]],
+ unique)],
unique),
{call,_,_,[{lc,_,{var,_,'X'},[{generate,_,{var,_,'X'},_}]},_]} =
qlc:info(Q, [{format,abstract_code},unique_all]),
- [1,2] = qlc:e(Q)">>,
+ [1,2,#{a := 1}] = qlc:e(Q)">>,
<<"Q = qlc:q([X || X <- [1,2,1]]),
{call,_,_,[{lc,_,{var,_,'X'},[{generate,_,{var,_,'X'},_}]},_]} =
@@ -2620,7 +2621,16 @@ info(Config) when is_list(Config) ->
{cons, _, _, _}]},
{nil,_}}]}]} = i(QH, {format, abstract_code}),
[{5},{6}] = qlc:e(QH),
- [{4},{5},{6}] = qlc:e(F(3))">>
+ [{4},{5},{6}] = qlc:e(F(3))">>,
+
+ <<"Fun = fun ?MODULE:i/2,
+ L = [{#{k => #{v => Fun}}, Fun}],
+ H = qlc:q([Q || Q <- L, Q =:= {#{k => #{v => Fun}}, Fun}]),
+ L = qlc:e(H),
+ {call,_,_,[{lc,_,{var,_,'Q'},
+ [{generate,_,_,_},
+ {op,_,_,_,_}]}]} =
+ qlc:info(H, [{format,abstract_code}])">>
],
run(Config, Ts),
diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl
index cb778c96d4..47e7c4f03d 100644
--- a/lib/stdlib/test/rand_SUITE.erl
+++ b/lib/stdlib/test/rand_SUITE.erl
@@ -18,7 +18,11 @@
%% %CopyrightEnd%
-module(rand_SUITE).
--export([all/0, suite/0,groups/0]).
+-compile({nowarn_deprecated_function,[{random,seed,1},
+ {random,uniform_s,1},
+ {random,uniform_s,2}]}).
+
+-export([all/0, suite/0, groups/0, group/1]).
-export([interval_int/1, interval_float/1, seed/1,
api_eq/1, reference/1,
@@ -47,18 +51,22 @@ groups() ->
[{basic_stats, [parallel],
[basic_stats_uniform_1, basic_stats_uniform_2, basic_stats_normal]}].
+group(basic_stats) ->
+ %% valgrind needs a lot of time
+ [{timetrap,{minutes,10}}].
+
%% A simple helper to test without test_server during dev
test() ->
Tests = all(),
lists:foreach(fun(Test) ->
- try
- ok = ?MODULE:Test([]),
- io:format("~p: ok~n", [Test])
- catch _:Reason ->
- io:format("Failed: ~p: ~p ~p~n",
- [Test, Reason, erlang:get_stacktrace()])
- end
- end, Tests).
+ try
+ ok = ?MODULE:Test([]),
+ io:format("~p: ok~n", [Test])
+ catch _:Reason ->
+ io:format("Failed: ~p: ~p ~p~n",
+ [Test, Reason, erlang:get_stacktrace()])
+ end
+ end, Tests).
algs() ->
[exs64, exsplus, exs1024].
@@ -267,13 +275,13 @@ gen(_, _, Acc) -> lists:reverse(Acc).
%% Check that the algorithms generate sound values.
basic_stats_uniform_1(Config) when is_list(Config) ->
- ct:timetrap({minutes,6}), %% valgrind needs a lot of time
+ ct:timetrap({minutes,15}), %% valgrind needs a lot of time
[basic_uniform_1(?LOOP, rand:seed_s(Alg), 0.0, array:new([{default, 0}]))
|| Alg <- algs()],
ok.
basic_stats_uniform_2(Config) when is_list(Config) ->
- ct:timetrap({minutes,6}), %% valgrind needs a lot of time
+ ct:timetrap({minutes,15}), %% valgrind needs a lot of time
[basic_uniform_2(?LOOP, rand:seed_s(Alg), 0, array:new([{default, 0}]))
|| Alg <- algs()],
ok.
@@ -380,7 +388,7 @@ crypto_uniform_n(N, State0) ->
%% Not a test but measures the time characteristics of the different algorithms
measure(Suite) when is_atom(Suite) -> [];
measure(_Config) ->
- ct:timetrap({minutes,6}), %% valgrind needs a lot of time
+ ct:timetrap({minutes,15}), %% valgrind needs a lot of time
Algos = [crypto64|algs()],
io:format("RNG uniform integer performance~n",[]),
_ = measure_1(random, fun(State) -> {int, random:uniform_s(10000, State)} end),
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index dc82e92876..80585ca359 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -30,7 +30,7 @@
progex_bit_syntax/1, progex_records/1,
progex_lc/1, progex_funs/1,
otp_5990/1, otp_6166/1, otp_6554/1,
- otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1]).
+ otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1, otp_13719/1]).
-export([ start_restricted_from_shell/1,
start_restricted_on_command_line/1,restricted_local/1]).
@@ -91,7 +91,7 @@ groups() ->
progex_funs]},
{tickets, [],
[otp_5990, otp_6166, otp_6554, otp_7184,
- otp_7232, otp_8393, otp_10302]}].
+ otp_7232, otp_8393, otp_10302, otp_13719]}].
init_per_suite(Config) ->
Config.
@@ -2325,7 +2325,7 @@ otp_6554(Config) when is_list(Config) ->
"[unproper | list]).">>),
%% Cheating:
"exception error: no function clause matching "
- "erl_eval:do_apply(4)" ++ _ =
+ "shell:apply_fun(4)" ++ _ =
comm_err(<<"erlang:error(function_clause, [4]).">>),
"exception error: no function clause matching "
"lists:reverse(" ++ _ =
@@ -2810,6 +2810,19 @@ otp_10302(Config) when is_list(Config) ->
test_server:stop_node(Node),
ok.
+otp_13719(Config) when is_list(Config) ->
+ Test = <<"-module(otp_13719).
+ -record(bar, {}).
+ -record(foo, {bar :: #bar{}}).">>,
+ File = filename("otp_13719.erl", Config),
+ Beam = filename("otp_13719.beam", Config),
+ ok = compile_file(Config, File, Test, []),
+ RR = "rr(\"" ++ Beam ++ "\"). #foo{}.",
+ "[bar,foo]\n#foo{bar = undefined}.\n" = t(RR),
+ file:delete(filename("test.beam", Config)),
+ file:delete(File),
+ ok.
+
scan(B) ->
F = fun(Ts) ->
case erl_parse:parse_term(Ts) of
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 64dd41e75a..6f3979bb77 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -720,20 +720,25 @@ memory(Config) when is_list(Config) ->
%% Test filenames with characters outside the US ASCII range.
unicode(Config) when is_list(Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- do_unicode(PrivDir),
+ run_unicode_node(Config, "+fnu"),
case has_transparent_naming() of
true ->
- Pa = filename:dirname(code:which(?MODULE)),
- Node = start_node(unicode, "+fnl -pa "++Pa),
- ok = rpc:call(Node, erlang, apply,
- [fun() -> do_unicode(PrivDir) end,[]]),
- true = test_server:stop_node(Node),
- ok;
+ run_unicode_node(Config, "+fnl");
false ->
ok
end.
+run_unicode_node(Config, Option) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Pa = filename:dirname(code:which(?MODULE)),
+ Args = Option ++ " -pa "++Pa,
+ io:format("~s\n", [Args]),
+ Node = start_node(unicode, Args),
+ ok = rpc:call(Node, erlang, apply,
+ [fun() -> do_unicode(PrivDir) end,[]]),
+ true = test_server:stop_node(Node),
+ ok.
+
has_transparent_naming() ->
case os:type() of
{unix,darwin} -> false;
@@ -745,10 +750,11 @@ do_unicode(PrivDir) ->
ok = file:set_cwd(PrivDir),
ok = file:make_dir("unicöde"),
- Names = unicode_create_files(),
+ Names = lists:sort(unicode_create_files()),
Tar = "unicöde.tar",
ok = erl_tar:create(Tar, ["unicöde"], []),
- {ok,Names} = erl_tar:table(Tar, []),
+ {ok,Names0} = erl_tar:table(Tar, []),
+ Names = lists:sort(Names0),
_ = [ok = file:delete(Name) || Name <- Names],
ok = erl_tar:extract(Tar),
_ = [{ok,_} = file:read_file(Name) || Name <- Names],
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index 2add5a39a2..1dfcda4ed0 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,8 +25,9 @@
zip_to_binary/1,
unzip_options/1, zip_options/1, list_dir_options/1, aliases/1,
openzip_api/1, zip_api/1, open_leak/1, unzip_jar/1,
+ unzip_traversal_exploit/1,
compress_control/1,
- foldl/1]).
+ foldl/1,fd_leak/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
@@ -38,7 +39,8 @@ all() ->
[borderline, atomic, bad_zip, unzip_from_binary,
unzip_to_binary, zip_to_binary, unzip_options,
zip_options, list_dir_options, aliases, openzip_api,
- zip_api, open_leak, unzip_jar, compress_control, foldl].
+ zip_api, open_leak, unzip_jar, compress_control, foldl,
+ unzip_traversal_exploit,fd_leak].
groups() ->
[].
@@ -377,6 +379,52 @@ unzip_options(Config) when is_list(Config) ->
0 = delete_files([Subdir]),
ok.
+%% Test that unzip handles directory traversal exploit (OTP-13633)
+unzip_traversal_exploit(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ZipName = filename:join(DataDir, "exploit.zip"),
+
+ %% $ zipinfo -1 test/zip_SUITE_data/exploit.zip
+ %% clash.txt
+ %% ../clash.txt
+ %% ../above.txt
+ %% subdir/../in_root_dir.txt
+
+ %% create a temp directory
+ SubDir = filename:join(PrivDir, "exploit_test"),
+ ok = file:make_dir(SubDir),
+
+ ClashFile = filename:join(SubDir,"clash.txt"),
+ AboveFile = filename:join(SubDir,"above.txt"),
+ RelativePathFile = filename:join(SubDir,"subdir/../in_root_dir.txt"),
+
+ %% unzip in SubDir
+ {ok, [ClashFile, ClashFile, AboveFile, RelativePathFile]} =
+ zip:unzip(ZipName, [{cwd,SubDir}]),
+
+ {ok,<<"This file will overwrite other file.\n">>} =
+ file:read_file(ClashFile),
+ {ok,_} = file:read_file(AboveFile),
+ {ok,_} = file:read_file(RelativePathFile),
+
+ %% clean up
+ delete_files([SubDir]),
+
+ %% create the temp directory again
+ ok = file:make_dir(SubDir),
+
+ %% unzip in SubDir
+ {ok, [ClashFile, AboveFile, RelativePathFile]} =
+ zip:unzip(ZipName, [{cwd,SubDir},keep_old_files]),
+
+ {ok,<<"This is the original file.\n">>} =
+ file:read_file(ClashFile),
+
+ %% clean up
+ delete_files([SubDir]),
+ ok.
+
%% Test unzip a jar file (OTP-7382).
unzip_jar(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
@@ -834,3 +882,35 @@ foldl(Config) ->
{error, enoent} = zip:foldl(ZipFun, [], File),
ok.
+
+fd_leak(Config) ->
+ ok = file:set_cwd(proplists:get_value(priv_dir, Config)),
+ DataDir = proplists:get_value(data_dir, Config),
+ Name = filename:join(DataDir, "bad_file_header.zip"),
+ BadExtract = fun() ->
+ {error,bad_file_header} = zip:extract(Name),
+ ok
+ end,
+ do_fd_leak(BadExtract, 1),
+
+ BadCreate = fun() ->
+ {error,enoent} = zip:zip("failed.zip",
+ ["none"]),
+ ok
+ end,
+ do_fd_leak(BadCreate, 1),
+
+ ok.
+
+do_fd_leak(_Bad, 10000) ->
+ ok;
+do_fd_leak(Bad, N) ->
+ try Bad() of
+ ok ->
+ do_fd_leak(Bad, N + 1)
+ catch
+ C:R ->
+ Stk = erlang:get_stacktrace(),
+ io:format("Bad error after ~p attempts\n", [N]),
+ erlang:raise(C, R, Stk)
+ end.
diff --git a/lib/stdlib/test/zip_SUITE_data/exploit.zip b/lib/stdlib/test/zip_SUITE_data/exploit.zip
new file mode 100644
index 0000000000..afb8dbd192
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/exploit.zip
Binary files differ
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 46e3ceac03..f7bd21472c 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.0
+STDLIB_VSN = 3.3
diff --git a/lib/syntax_tools/doc/specs/.gitignore b/lib/syntax_tools/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/syntax_tools/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/syntax_tools/doc/src/Makefile b/lib/syntax_tools/doc/src/Makefile
index ff4f3f78ff..e55222e59c 100644
--- a/lib/syntax_tools/doc/src/Makefile
+++ b/lib/syntax_tools/doc/src/Makefile
@@ -81,10 +81,15 @@ 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 +=
+SPECS_FLAGS = -I../../include
DVIPS_FLAGS +=
# ----------------------------------------------------
@@ -93,7 +98,7 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-docs: pdf html man
+docs: man pdf html
$(TOP_PDF_FILE): $(XML_FILES)
@@ -120,6 +125,7 @@ clean clean_docs:
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECDIR)/*
rm -f errs core *~
# ----------------------------------------------------
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index ef207f7c3d..acc465a322 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -32,6 +32,70 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 2.1.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug regarding reverting map types. </p>
+ <p>
+ Own Id: OTP-15098 Aux Id: ERIERL-177 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Syntax_Tools 2.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The address to the FSF in the license header has been
+ updated.</p>
+ <p>
+ Own Id: OTP-14084</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Syntax_Tools 2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug where <c>erl_tidy</c> crashed on the tilde
+ character when printing to standard output. </p>
+ <p>
+ Own Id: OTP-13725 Aux Id: ERL-151, PR-1071 </p>
+ </item>
+ <item>
+ <p><c>merl_transform</c> could get into an infinite loop
+ when syntactically incorrect text was passed to a
+ <c>merl:qquote/2,3</c> call.</p>
+ <p>
+ Own Id: OTP-13755</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Improve types and specs in OTP documentation generated
+ from Erlang source files. </p>
+ <p>
+ Own Id: OTP-13720 Aux Id: ERL-120 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 2.0</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/syntax_tools/doc/src/specs.xml b/lib/syntax_tools/doc/src/specs.xml
new file mode 100644
index 0000000000..04c3a494e7
--- /dev/null
+++ b/lib/syntax_tools/doc/src/specs.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_epp_dodger.xml"/>
+ <xi:include href="../specs/specs_erl_comment_scan.xml"/>
+ <xi:include href="../specs/specs_erl_prettypr.xml"/>
+ <xi:include href="../specs/specs_erl_recomment.xml"/>
+ <xi:include href="../specs/specs_erl_syntax.xml"/>
+ <xi:include href="../specs/specs_erl_syntax_lib.xml"/>
+ <xi:include href="../specs/specs_erl_tidy.xml"/>
+ <xi:include href="../specs/specs_igor.xml"/>
+ <xi:include href="../specs/specs_merl.xml"/>
+ <xi:include href="../specs/specs_merl_transform.xml"/>
+ <xi:include href="../specs/specs_prettypr.xml"/>
+</specs>
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index 39c522fd11..43e42d8195 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2006 Richard Carlsson
diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl
index 03429d4d42..8d0e2a10a3 100644
--- a/lib/syntax_tools/src/erl_comment_scan.erl
+++ b/lib/syntax_tools/src/erl_comment_scan.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% =====================================================================
@@ -30,8 +30,14 @@
%% =====================================================================
--type comment() :: {integer(), integer(), integer(), [string()]}.
--type commentLine() :: {integer(), integer(), integer(), string()}.
+-type comment() :: {Line:: integer(),
+ Column:: integer(),
+ Indentation :: integer(),
+ Text :: [string()]}.
+-type commentLine() :: {Line :: integer(),
+ Column :: integer(),
+ Indent :: integer(),
+ Text :: string()}.
%% =====================================================================
%% @spec file(FileName::file:filename()) -> [Comment]
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index f1615b2610..6c812aaa6c 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
@@ -195,10 +195,16 @@ format(Node) ->
%% =====================================================================
%% @spec format(Tree::syntaxTree(), Options::[term()]) -> string()
-%% syntaxTree() = erl_syntax:syntaxTree()
%%
-%% @type hook() = (syntaxTree(), context(), Continuation) -> document()
-%% Continuation = (syntaxTree(), context()) -> document().
+%% @type syntaxTree() = erl_syntax:syntaxTree().
+%%
+%% An abstract syntax tree. See the {@link erl_syntax} module for
+%% details.
+%%
+%% @type hook() = (syntaxTree(), context(), Continuation) ->
+%% prettypr:document()
+%% Continuation = (syntaxTree(), context()) ->
+%% prettypr:document().
%%
%% A call-back function for user-controlled formatting. See {@link
%% format/2}.
@@ -277,7 +283,7 @@ format(Node, Options) ->
%% =====================================================================
-%% @spec best(Tree::syntaxTree()) -> empty | document()
+%% @spec best(Tree::syntaxTree()) -> empty | prettypr:document()
%% @equiv best(Tree, [])
-spec best(erl_syntax:syntaxTree()) -> 'empty' | prettypr:document().
@@ -288,7 +294,7 @@ best(Node) ->
%% =====================================================================
%% @spec best(Tree::syntaxTree(), Options::[term()]) ->
-%% empty | document()
+%% empty | prettypr:document()
%%
%% @doc Creates a fixed "best" abstract layout for a syntax tree. This
%% is similar to the `layout/2' function, except that here, the final
@@ -310,7 +316,7 @@ best(Node, Options) ->
%% =====================================================================
-%% @spec layout(Tree::syntaxTree()) -> document()
+%% @spec layout(Tree::syntaxTree()) -> prettypr:document()
%% @equiv layout(Tree, [])
-spec layout(erl_syntax:syntaxTree()) -> prettypr:document().
@@ -320,8 +326,7 @@ layout(Node) ->
%% =====================================================================
-%% @spec layout(Tree::syntaxTree(), Options::[term()]) -> document()
-%% document() = prettypr:document()
+%% @spec layout(Tree::syntaxTree(), Options::[term()]) -> prettypr:document()
%%
%% @doc Creates an abstract document layout for a syntax tree. The
%% result represents a set of possible layouts (cf. module `prettypr').
diff --git a/lib/syntax_tools/src/erl_recomment.erl b/lib/syntax_tools/src/erl_recomment.erl
index c1141b2bc6..a774b898e8 100644
--- a/lib/syntax_tools/src/erl_recomment.erl
+++ b/lib/syntax_tools/src/erl_recomment.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
@@ -30,6 +30,9 @@
-export([recomment_forms/2, quick_recomment_forms/2, recomment_tree/2]).
+%% @type syntaxTree() = erl_syntax:syntaxTree(). An abstract syntax
+%% tree. See the {@link erl_syntax} module for details.
+
%% =====================================================================
%% @spec quick_recomment_forms(Forms, Comments::[Comment]) ->
%% syntaxTree()
@@ -55,7 +58,6 @@ quick_recomment_forms(Tree, Cs) ->
%% =====================================================================
%% @spec recomment_forms(Forms, Comments::[Comment]) -> syntaxTree()
%%
-%% syntaxTree() = erl_syntax:syntaxTree()
%% Forms = syntaxTree() | [syntaxTree()]
%% Comment = {Line, Column, Indentation, Text}
%% Line = integer()
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index ee42e56172..91da3ad571 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
@@ -5300,7 +5300,7 @@ revert_map_type_assoc(Node) ->
Pos = get_pos(Node),
Name = map_type_assoc_name(Node),
Value = map_type_assoc_value(Node),
- {type, Pos, map_type_assoc, [Name, Value]}.
+ {type, Pos, map_field_assoc, [Name, Value]}.
%% =====================================================================
@@ -5358,7 +5358,7 @@ revert_map_type_exact(Node) ->
Pos = get_pos(Node),
Name = map_type_exact_name(Node),
Value = map_type_exact_value(Node),
- {type, Pos, map_type_exact, [Name, Value]}.
+ {type, Pos, map_field_exact, [Name, Value]}.
%% =====================================================================
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index 9815559779..aae6755639 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
@@ -280,7 +280,7 @@ mapfoldl(_, S, []) ->
%% =====================================================================
%% @spec variables(syntaxTree()) -> set(atom())
%%
-%% set(T) = //stdlib/sets:set(T)
+%% @type set(T) = //stdlib/sets:set(T)
%%
%% @doc Returns the names of variables occurring in a syntax tree, The
%% result is a set of variable names represented by atoms. Macro names
@@ -1955,7 +1955,7 @@ analyze_application(Node) ->
%% =====================================================================
-%% @spec analyze_type_application(Node::syntaxTree()) -> typeName()
+%% @spec analyze_type_application(Node::syntaxTree()) -> TypeName
%%
%% TypeName = {atom(), integer()}
%% | {ModuleName, {atom(), integer()}}
diff --git a/lib/syntax_tools/src/erl_tidy.erl b/lib/syntax_tools/src/erl_tidy.erl
index f2de12b410..2e0ee209f8 100644
--- a/lib/syntax_tools/src/erl_tidy.erl
+++ b/lib/syntax_tools/src/erl_tidy.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1999-2014 Richard Carlsson
@@ -36,6 +36,11 @@
%% been reasonably well tested, but the possibility of errors remains.
%% Keep backups of your original code safely stored, until you feel
%% confident that the new, modified code can be trusted.
+%%
+%% @type syntaxTree() = erl_syntax:syntaxTree(). An abstract syntax
+%% tree. See the {@link erl_syntax} module for details.
+%%
+%% @type filename() = file:filename().
-module(erl_tidy).
@@ -79,7 +84,6 @@ dir(Dir) ->
%% =====================================================================
%% @spec dir(Directory::filename(), Options::[term()]) -> ok
-%% filename() = file:filename()
%%
%% @doc Tidies Erlang source files in a directory and its
%% subdirectories.
@@ -206,7 +210,7 @@ file__defaults() ->
{verbose, false}].
default_printer() ->
- fun (Tree, Options) -> erl_prettypr:format(Tree, Options) end.
+ fun erl_prettypr:format/2.
%% =====================================================================
%% @spec file(Name) -> ok
@@ -253,7 +257,7 @@ file(Name) ->
%%
%% <dt>{printer, Function}</dt>
%% <dd><ul>
-%% <li>`Function = (syntaxTree()) -> string()'</li>
+%% <li>`Function = (syntaxTree(), [term()]) -> string()'</li>
%% </ul>
%%
%% Specifies a function for prettyprinting Erlang syntax trees.
@@ -414,7 +418,7 @@ write_module(Tree, Name, Opts) ->
print_module(Tree, Opts) ->
Printer = proplists:get_value(printer, Opts),
- io:format(Printer(Tree, Opts)).
+ io:put_chars(Printer(Tree, Opts)).
output(FD, Printer, Tree, Opts) ->
io:put_chars(FD, Printer(Tree, Opts)),
@@ -513,7 +517,6 @@ module(Forms) ->
%% @spec module(Forms, Options::[term()]) -> syntaxTree()
%%
%% Forms = syntaxTree() | [syntaxTree()]
-%% syntaxTree() = erl_syntax:syntaxTree()
%%
%% @doc Tidies a syntax tree representation of a module
%% definition. The given `Forms' may be either a single
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 1d14bd7c3a..4d18f7abcf 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1998-2014 Richard Carlsson
@@ -151,7 +151,8 @@ default_printer(Tree, Options) ->
%% @spec parse_transform(Forms::[syntaxTree()], Options::[term()]) ->
%% [syntaxTree()]
%%
-%% syntaxTree() = erl_syntax:syntaxTree()
+%% @type syntaxTree() = erl_syntax:syntaxTree(). An abstract syntax
+%% tree. See the {@link erl_syntax} module for details.
%%
%% @doc Allows Igor to work as a component of the Erlang compiler.
%% Including the term `{parse_transform, igor}' in the
@@ -212,7 +213,7 @@ merge(Name, Files) ->
%% @spec merge(Name::atom(), Files::[filename()], Options::[term()]) ->
%% [filename()]
%%
-%% filename() = file:filename()
+%% @type filename() = file:filename()
%%
%% @doc Merges source code files to a single file. `Name'
%% specifies the name of the resulting module - not the name of the
@@ -367,6 +368,7 @@ merge_files(Name, Files, Options) ->
%% @spec merge_files(Name::atom(), Sources::[Forms],
%% Files::[filename()], Options::[term()]) ->
%% {syntaxTree(), [stubDescriptor()]}
+%%
%% Forms = syntaxTree() | [syntaxTree()]
%%
%% @doc Merges source code files and syntax trees to a single syntax
diff --git a/lib/syntax_tools/src/merl_tests.erl b/lib/syntax_tools/src/merl_tests.erl
index c1aae3100e..27db594050 100644
--- a/lib/syntax_tools/src/merl_tests.erl
+++ b/lib/syntax_tools/src/merl_tests.erl
@@ -48,6 +48,21 @@ parse_error_test_() ->
f(merl:quote("{")))
].
+transform_parse_error_test_() ->
+ [?_assertEqual("merl:quote(\"{\")",
+ f(merl_transform:parse_transform(
+ [?Q("merl:quote(\"{\")")], []))),
+ ?_assertEqual("merl:quote(2, \"{\")",
+ f(merl_transform:parse_transform(
+ [?Q("merl:quote(2, \"{\")")], []))),
+ ?_assertEqual("merl:qquote(\"{\", [{var, V}])",
+ f(merl_transform:parse_transform(
+ [?Q("merl:qquote(\"{\", [{var, V}])")], []))),
+ ?_assertEqual("merl:qquote(2, \"{\", [{var, V}])",
+ f(merl_transform:parse_transform(
+ [?Q("merl:qquote(2, \"{\", [{var, V}])")], [])))
+ ].
+
term_test_() ->
[?_assertEqual(tuple, erl_syntax:type(merl:term({}))),
?_assertEqual("{foo, 42}", f(merl:term({foo, 42})))
diff --git a/lib/syntax_tools/src/merl_transform.erl b/lib/syntax_tools/src/merl_transform.erl
index fe58b6a122..497baddd0a 100644
--- a/lib/syntax_tools/src/merl_transform.erl
+++ b/lib/syntax_tools/src/merl_transform.erl
@@ -104,10 +104,15 @@ expand_qquote([Text, Env], T, Line) ->
case erl_syntax:is_literal(Text) of
true ->
As = [Line, erl_syntax:concrete(Text)],
- %% expand further if possible
- expand(merl:qquote(Line, "merl:subst(_@tree, _@env)",
- [{tree, eval_call(Line, quote, As, T)},
- {env, Env}]));
+ case eval_call(Line, quote, As, failed) of
+ failed ->
+ T;
+ T1 ->
+ %% expand further if possible
+ expand(merl:qquote(Line, "merl:subst(_@tree, _@env)",
+ [{tree, T1},
+ {env, Env}]))
+ end;
false ->
T
end;
diff --git a/lib/syntax_tools/src/prettypr.erl b/lib/syntax_tools/src/prettypr.erl
index 1b5ba6b05a..5156af667b 100644
--- a/lib/syntax_tools/src/prettypr.erl
+++ b/lib/syntax_tools/src/prettypr.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2000-2006 Richard Carlsson
diff --git a/lib/syntax_tools/test/merl_SUITE.erl b/lib/syntax_tools/test/merl_SUITE.erl
index 945972d405..52bbd9b3b8 100644
--- a/lib/syntax_tools/test/merl_SUITE.erl
+++ b/lib/syntax_tools/test/merl_SUITE.erl
@@ -29,12 +29,14 @@
init_per_group/2,end_per_group/2]).
%% Test cases
--export([merl_smoke_test/1]).
+-export([merl_smoke_test/1,
+ transform_parse_error_test/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [merl_smoke_test].
+ [merl_smoke_test,
+ transform_parse_error_test].
groups() ->
[].
@@ -84,6 +86,21 @@ merl_smoke_test(Config) when is_list(Config) ->
end)),
ok.
+transform_parse_error_test(_Config) ->
+ ?assertEqual("merl:quote(\"{\")",
+ f(merl_transform:parse_transform(
+ [?Q("merl:quote(\"{\")")], []))),
+ ?assertEqual("merl:quote(2, \"{\")",
+ f(merl_transform:parse_transform(
+ [?Q("merl:quote(2, \"{\")")], []))),
+ ?assertEqual("merl:qquote(\"{\", [{var, V}])",
+ f(merl_transform:parse_transform(
+ [?Q("merl:qquote(\"{\", [{var, V}])")], []))),
+ ?assertEqual("merl:qquote(2, \"{\", [{var, V}])",
+ f(merl_transform:parse_transform(
+ [?Q("merl:qquote(2, \"{\", [{var, V}])")], []))),
+ ok.
+
%% utilities
f(Ts) when is_list(Ts) ->
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index b935d42bb7..b03d249a60 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -26,15 +26,16 @@
%% Test cases
-export([app_test/1,appup_test/1,smoke_test/1,revert/1,revert_map/1,
+ revert_map_type/1,
t_abstract_type/1,t_erl_parse_type/1,t_epp_dodger/1,
- t_comment_scan/1,t_igor/1]).
+ t_comment_scan/1,t_igor/1,t_erl_tidy/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test,appup_test,smoke_test,revert,revert_map,
+ [app_test,appup_test,smoke_test,revert,revert_map,revert_map_type,
t_abstract_type,t_erl_parse_type,t_epp_dodger,
- t_comment_scan,t_igor].
+ t_comment_scan,t_igor,t_erl_tidy].
groups() ->
[].
@@ -123,7 +124,26 @@ revert_map(Config) when is_list(Config) ->
{map_field_assoc,{atom,17,name},{var,18,'Value'}}}]),
?t:timetrap_cancel(Dog).
-
+%% Testing bug fix for reverting map_field_assoc in types
+revert_map_type(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(1)),
+ Form1 = {attribute,4,record,
+ {state,
+ [{typed_record_field,
+ {record_field,5,{atom,5,x}},
+ {type,5,map,
+ [{type,5,map_field_exact,[{atom,5,y},{atom,5,z}]}]}}]}},
+ Mapped1 = erl_syntax_lib:map(fun(X) -> X end, Form1),
+ Form1 = erl_syntax:revert(Mapped1),
+ Form2 = {attribute,4,record,
+ {state,
+ [{typed_record_field,
+ {record_field,5,{atom,5,x}},
+ {type,5,map,
+ [{type,5,map_field_assoc,[{atom,5,y},{atom,5,z}]}]}}]}},
+ Mapped2 = erl_syntax_lib:map(fun(X) -> X end, Form2),
+ Form2 = erl_syntax:revert(Mapped2),
+ ?t:timetrap_cancel(Dog).
%% api tests
@@ -237,6 +257,12 @@ t_igor(Config) when is_list(Config) ->
ok.
+t_erl_tidy(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ File = filename:join(DataDir,"erl_tidy_tilde.erl"),
+ ok = erl_tidy:file(File, [{stdout, true}]),
+ ok.
+
test_comment_scan([],_) -> ok;
test_comment_scan([File|Files],DataDir) ->
Filename = filename:join(DataDir,File),
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/erl_tidy_tilde.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/erl_tidy_tilde.erl
new file mode 100644
index 0000000000..888264bad6
--- /dev/null
+++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/erl_tidy_tilde.erl
@@ -0,0 +1,13 @@
+%%
+%% File: erl_tidy_tilde.erl
+%% Author: Mark Bucciarelli
+%% Created: 2016-06-05
+%%
+
+-module(erl_tidy_tilde).
+
+-export([start/0]).
+
+start() ->
+ io:put_chars("tilde characters ('~')in source were "
+ "breaking erl_tidy\n").
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index f09c2a01d0..6cd62c7814 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 2.0
+SYNTAX_TOOLS_VSN = 2.1.1.1
diff --git a/lib/tools/doc/src/erlang_mode.xml b/lib/tools/doc/src/erlang_mode.xml
index 00cf5196b4..7fef74813b 100644
--- a/lib/tools/doc/src/erlang_mode.xml
+++ b/lib/tools/doc/src/erlang_mode.xml
@@ -252,7 +252,14 @@
behavior</item>
<item>gen_event - skeleton for the OTP gen_event behavior</item>
<item>gen_fsm - skeleton for the OTP gen_fsm behavior</item>
- <item>gen_statem - skeleton for the OTP gen_statem behavior</item>
+ <item>
+ gen_statem (StateName/3) - skeleton for the OTP gen_statem behavior
+ using state name functions
+ </item>
+ <item>
+ gen_statem (handle_event/4) - skeleton for the OTP gen_statem behavior
+ using one state function
+ </item>
<item>Library module - skeleton for a module that does not
implement a process.</item>
<item>Corba callback - skeleton for a Corba callback module.</item>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 0b8a2be715..af20200d49 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -31,6 +31,104 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 2.9.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved edoc support in emacs mode.</p>
+ <p>
+ Own Id: OTP-14217 Aux Id: PR-1282 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 2.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix unhandled trace event send_to_non_existing_process in
+ fprof.</p>
+ <p>
+ Own Id: OTP-13998</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved edoc support in emacs erlang-mode.</p>
+ <p>
+ Own Id: OTP-13945 Aux Id: PR-1157 </p>
+ </item>
+ <item>
+ <p>
+ Added erldoc to emacs mode which opens html documentation
+ in browser from emacs. For example <c>M-x erldoc-browse
+ RET lists:foreach/2</c>.</p>
+ <p>
+ Own Id: OTP-14018 Aux Id: PR-1197 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 2.8.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Errors in type specification and Emacs template
+ generation for <c>gen_statem:code_change/4</c> has been
+ fixed from bugs.erlang.org's Jira cases ERL-172 and
+ ERL-187.</p>
+ <p>
+ Own Id: OTP-13746 Aux Id: ERL-172, ERL-187 </p>
+ </item>
+ <item>
+ <p>
+ Fix gc_start/gc_end in fprof tags when parsing old trace
+ logs.</p>
+ <p>
+ Own Id: OTP-13778 Aux Id: PR-1136 </p>
+ </item>
+ <item>
+ <p><c>make</c> (tools) and <c>ct_make</c> (common_test)
+ would crash if an Erlang source file contained a
+ <c>-warning()</c> directive.</p>
+ <p>
+ Own Id: OTP-13855</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 2.8.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Correct a bug when adding multiple modules to an Xref
+ server. The bug was introduced in OTP-19.0. </p>
+ <p>
+ Own Id: OTP-13708 Aux Id: ERL-173 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.8.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/doc/src/xref_chapter.xml b/lib/tools/doc/src/xref_chapter.xml
index 8b14e03064..872793bdcb 100644
--- a/lib/tools/doc/src/xref_chapter.xml
+++ b/lib/tools/doc/src/xref_chapter.xml
@@ -234,7 +234,7 @@
operand of the intersection operator <c>*</c> is implicitly
converted to the more special type of the second operand.</item>
<tag><c>xref:q(s, "(Mod) tools").</c></tag>
- <item>All modules of the <c>tools</c> application.</item>
+ <item>All modules of the Tools application.</item>
<tag><c>xref:q(s, '"xref_.*" : Mod').</c></tag>
<item>All modules with a name beginning with <c>xref_</c>.</item>
<tag><c>xref:q(s, "# E&nbsp;|&nbsp;X&nbsp;").</c></tag>
@@ -252,9 +252,9 @@
<tag><c>xref:q(s, "XC * (ME - strict ME)").</c></tag>
<item>External calls within some module.</item>
<tag><c>xref:q(s, "E&nbsp;|||&nbsp;kernel").</c></tag>
- <item>All calls within the <c>kernel</c> application. </item>
+ <item>All calls within the Kernel application. </item>
<tag><c>xref:q(s, "closure&nbsp;E&nbsp;|&nbsp;kernel&nbsp;||&nbsp;kernel").</c></tag>
- <item>All direct and indirect calls within the <c>kernel</c>
+ <item>All direct and indirect calls within the Kernel
application. Both the calling and the used functions of
indirect calls are defined in modules of the kernel
application, but it is possible that some functions outside
diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile
index 585425e5f1..35c93ba4ed 100644
--- a/lib/tools/emacs/Makefile
+++ b/lib/tools/emacs/Makefile
@@ -38,11 +38,13 @@ MAN_FILES= \
tags.3
EMACS_FILES= \
+ erldoc \
erlang-skels \
erlang-skels-old \
erlang_appwiz \
erlang-start \
erlang-eunit \
+ erlang-edoc \
erlang-flymake \
erlang
diff --git a/lib/tools/emacs/erlang-edoc.el b/lib/tools/emacs/erlang-edoc.el
new file mode 100644
index 0000000000..241590b850
--- /dev/null
+++ b/lib/tools/emacs/erlang-edoc.el
@@ -0,0 +1,172 @@
+;;; erlang-edoc.el --- EDoc support for Erlang mode -*- lexical-binding: t; -*-
+
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 1996-2016. All Rights Reserved.
+;;
+;; Licensed under the Apache License, Version 2.0 (the "License");
+;; you may not use this file except in compliance with the License.
+;; You may obtain a copy of the License at
+;;
+;; http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
+;;
+;; %CopyrightEnd%
+
+;;; Commentary:
+
+;; Ref: http://www.erlang.org/doc/apps/edoc/users_guide.html
+;;
+;; To use: (add-hook 'erlang-mode-hook 'erlang-edoc-mode)
+
+;;; Code:
+
+(defcustom erlang-edoc-indent-level 2
+ "Indentation level of xhtml in Erlang edoc."
+ :safe 'integerp
+ :group 'erlang)
+
+(defvar erlang-edoc-generic-tags
+ '("clear" "docfile" "end" "headerfile" "todo" "TODO" "type")
+ "Tags that can be used anywhere within a module.")
+
+(defvar erlang-edoc-overview-tags
+ '("author" "copyright" "doc" "reference" "see" "since" "title" "version")
+ "Tags that can be used in an overview file.")
+
+(defvar erlang-edoc-module-tags
+ '("author" "copyright" "deprecated" "doc" "hidden" "private" "reference"
+ "see" "since" "version")
+ "Tags that can be used before a module declaration.")
+
+(defvar erlang-edoc-function-tags
+ '("deprecated" "doc" "equiv" "hidden" "param" "private" "returns"
+ "see" "since" "spec" "throws" "type")
+ "Tags that can be used before a function definition.")
+
+(defvar erlang-edoc-predefined-macros
+ '("date" "docRoot" "link" "module" "package" "section" "time"
+ "type" "version"))
+
+(defface erlang-edoc-tag '((t (:inherit font-lock-constant-face)))
+ "Face used to highlight edoc tags."
+ :group 'erlang)
+
+(defface erlang-edoc-macro '((t (:inherit font-lock-preprocessor-face)))
+ "Face used to highlight edoc macros."
+ :group 'erlang)
+
+(defface erlang-edoc-verbatim
+ '((t (:family "Monospace" :inherit font-lock-keyword-face)))
+ "Face used to highlight verbatim text."
+ :group 'erlang)
+
+(defface erlang-edoc-todo '((t (:inherit font-lock-warning-face)))
+ "Face used to highlight edoc macros."
+ :group 'erlang)
+
+(defface erlang-edoc-heading '((t (:inherit bold)))
+ "Face used to highlight edoc headings."
+ :group 'erlang)
+
+(defvar erlang-edoc-font-lock-keywords
+ '(("^%+\\s-*\\(@\\w+\\)\\_>" 1 'erlang-edoc-tag prepend)
+ ("^%+\\s-*" ("{\\(@\\w+\\)\\_>" nil nil (1 'erlang-edoc-macro prepend)))
+ ("^%+\\s-*" ("\\(?:@@\\)*\\(@[@{}]\\)" nil nil (1 'escape-glyph prepend)))
+ ("^%+\\s-*\\(@deprecated\\)\\_>" 1 font-lock-warning-face prepend)
+ ;; http://www.erlang.org/doc/apps/edoc/chapter.html#Wiki_notation
+ ("^%+\\s-*" ("[^`]`\\([^`]?\\|[^`].*?[^']\\)'"
+ (forward-char -1) nil (1 'erlang-edoc-verbatim prepend)))
+ ("^%+\\s-*" ("\\[\\(\\(?:https?\\|file\\|ftp\\)://[^][]+\\)\\]"
+ nil nil (1 'link prepend)))
+ ("^%+\\s-*\\(?:\\(?1:@todo\\|@TODO\\)\\_>\\|\\(?1:TODO\\):\\)"
+ 1 'erlang-edoc-todo prepend)
+ ("^%+\\s-*\\(\\(=\\{2,4\\}\\)[^=\n].*[^=\n]\\2\\)\\s-*$"
+ 1 'erlang-edoc-heading prepend)))
+
+(defun erlang-edoc-xml-context ()
+ "Parse edoc x(ht)ml context at comment start of current line."
+ (eval-and-compile (require 'xmltok))
+ (save-excursion
+ (beginning-of-line)
+ (when (looking-at "^%+\\s-*")
+ (let ((pt (match-end 0)) context)
+ (forward-comment (- (point)))
+ (while (< (point) pt)
+ (xmltok-forward)
+ (cond ((eq xmltok-type 'start-tag)
+ (push (cons xmltok-type xmltok-start) context))
+ ((eq xmltok-type 'end-tag)
+ (pop context))))
+ (goto-char pt)
+ (xmltok-forward)
+ (push (car (memq xmltok-type '(start-tag end-tag))) context)
+ context))))
+
+(defun erlang-edoc-indent-line ()
+ (let ((context (erlang-edoc-xml-context)))
+ (when context
+ (save-excursion
+ (beginning-of-line)
+ (re-search-forward "^%+\\s-*" (line-end-position))
+ (when (or (car context) (cadr context))
+ (let ((pad (when (cadr context)
+ (save-excursion
+ (goto-char (cdr (cadr context)))
+ (- (current-column)
+ (progn
+ (beginning-of-line)
+ (skip-chars-forward "%")
+ (current-column)))))))
+ (just-one-space (cond ((not pad) 1)
+ ((eq (car context) 'end-tag) pad)
+ (t (+ erlang-edoc-indent-level pad)))))))
+ (when (looking-back "^%*\\s-*" (line-beginning-position))
+ (re-search-forward "\\=%*\\s-*")))))
+
+(defun erlang-edoc-before-module-declaration-p ()
+ (save-excursion
+ (beginning-of-line)
+ (forward-comment (point-max))
+ (or (eobp) (re-search-forward "^-module\\s-*(" nil t))))
+
+(defun erlang-edoc-completion-at-point ()
+ (when (eq (syntax-ppss-context (syntax-ppss)) 'comment)
+ (save-excursion
+ (skip-syntax-backward "w_")
+ (when (= (preceding-char) ?@)
+ (let* ((is-tag (looking-back "^%+\\s-*@" (line-beginning-position)))
+ (beg (point))
+ (end (progn (skip-syntax-forward "w_") (point)))
+ (table (cond
+ ((not is-tag)
+ erlang-edoc-predefined-macros)
+ ((erlang-edoc-before-module-declaration-p)
+ (append erlang-edoc-module-tags
+ erlang-edoc-generic-tags))
+ (t (append erlang-edoc-function-tags
+ erlang-edoc-generic-tags)))))
+ (list beg end table))))))
+
+;;;###autoload
+(define-minor-mode erlang-edoc-mode nil
+ :lighter " EDoc"
+ (cond (erlang-edoc-mode
+ (add-hook 'erlang-indent-line-hook #'erlang-edoc-indent-line nil t)
+ (font-lock-add-keywords nil erlang-edoc-font-lock-keywords t)
+ (add-hook 'completion-at-point-functions
+ #'erlang-edoc-completion-at-point nil t))
+ (t
+ (remove-hook 'erlang-indent-line-hook #'erlang-edoc-indent-line t)
+ (font-lock-remove-keywords nil erlang-edoc-font-lock-keywords)
+ (remove-hook 'completion-at-point-functions
+ #'erlang-edoc-completion-at-point t)))
+ (jit-lock-refontify))
+
+(provide 'erlang-edoc)
+;;; erlang-edoc.el ends here
diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el
index ce26c83295..bdb3d9ad4a 100644
--- a/lib/tools/emacs/erlang-skels.el
+++ b/lib/tools/emacs/erlang-skels.el
@@ -1,7 +1,7 @@
;;
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 2010-2016. All Rights Reserved.
+;; Copyright Ericsson AB 2010-2017. All Rights Reserved.
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
@@ -56,8 +56,10 @@
erlang-skel-gen-event erlang-skel-header)
("gen_fsm" "gen-fsm"
erlang-skel-gen-fsm erlang-skel-header)
- ("gen_statem" "gen-statem"
- erlang-skel-gen-statem erlang-skel-header)
+ ("gen_statem (StateName/3)" "gen-statem-StateName"
+ erlang-skel-gen-statem-StateName erlang-skel-header)
+ ("gen_statem (handle_event/4)" "gen-statem-handle-event"
+ erlang-skel-gen-statem-handle-event erlang-skel-header)
("wx_object" "wx-object"
erlang-skel-wx-object erlang-skel-header)
("Library module" "gen-lib"
@@ -497,6 +499,7 @@ Please see the function `tempo-define-template'.")
"%% {stop, Reason}" n
(erlang-skel-separator-end 2)
"init([]) ->" n>
+ "process_flag(trap_exit, true)," n>
"{ok, #state{}}." n
n
(erlang-skel-separator-start 2)
@@ -740,6 +743,7 @@ Please see the function `tempo-define-template'.")
"%% {stop, StopReason}" n
(erlang-skel-separator-end 2)
"init([]) ->" n>
+ "process_flag(trap_exit, true)," n>
"{ok, state_name, #state{}}." n
n
(erlang-skel-separator-start 2)
@@ -860,7 +864,7 @@ Please see the function `tempo-define-template'.")
"*The template of a gen_fsm.
Please see the function `tempo-define-template'.")
-(defvar erlang-skel-gen-statem
+(defvar erlang-skel-gen-statem-StateName
'((erlang-skel-include erlang-skel-large-header)
"-behaviour(gen_statem)." n n
@@ -868,9 +872,8 @@ Please see the function `tempo-define-template'.")
"-export([start_link/0])." n
n
"%% gen_statem callbacks" n
- "-export([init/1, terminate/3, code_change/4])." n
+ "-export([callback_mode/0, init/1, terminate/3, code_change/4])." n
"-export([state_name/3])." n
- "-export([handle_event/4])." n
n
"-define(SERVER, ?MODULE)." n
n
@@ -899,48 +902,149 @@ Please see the function `tempo-define-template'.")
(erlang-skel-separator-start 2)
"%% @private" n
"%% @doc" n
+ "%% Define the callback_mode() for this callback module." n
+ (erlang-skel-separator-end 2)
+ "-spec callback_mode() -> gen_statem:callback_mode_result()." n
+ "callback_mode() -> state_functions." n
+ n
+ (erlang-skel-separator-start 2)
+ "%% @private" n
+ "%% @doc" n
"%% Whenever a gen_statem is started using gen_statem:start/[3,4] or" n
"%% gen_statem:start_link/[3,4], this function is called by the new" n
"%% process to initialize." n
(erlang-skel-separator-end 2)
- "-spec init(Args :: term()) -> " n>
- "{gen_statem:callback_mode()," n>
- "State :: term(), Data :: term()} |" n>
- "{gen_statem:callback_mode()," n>
- "State :: term(), Data :: term()," n>
- "[gen_statem:action()] | gen_statem:action()} |" n>
- "ignore |" n>
- "{stop, Reason :: term()}." n
+ "-spec init(Args :: term()) ->" n>
+ "gen_statem:init_result(atom())." n
"init([]) ->" n>
- "{state_functions, state_name, #data{}}." n
+ "process_flag(trap_exit, true)," n>
+ "{ok, state_name, #data{}}." n
n
(erlang-skel-separator-start 2)
"%% @private" n
"%% @doc" n
- "%% If the gen_statem runs with CallbackMode =:= state_functions" n
- "%% there should be one instance of this function for each possible" n
- "%% state name. Whenever a gen_statem receives an event," n
- "%% the instance of this function with the same name" n
- "%% as the current state name StateName is called to" n
- "%% handle the event." n
+ "%% There should be one function like this for each state name." n
+ "%% Whenever a gen_statem receives an event, the function " n
+ "%% with the name of the current state (StateName) " n
+ "%% is called to handle the event." n
(erlang-skel-separator-end 2)
- "-spec state_name(" n>
- "gen_statem:event_type(), Msg :: term()," n>
+ "-spec state_name('enter'," n>
+ "OldState :: atom()," n>
+ "Data :: term()) ->" n>
+ "gen_statem:state_enter_result('state_name');" n>
+ "(gen_statem:event_type()," n>
+ "Msg :: term()," n>
"Data :: term()) ->" n>
- "gen_statem:state_function_result(). " n
+ "gen_statem:event_handler_result(atom())." n
+ ;;
"state_name({call,Caller}, _Msg, Data) ->" n>
"{next_state, state_name, Data, [{reply,Caller,ok}]}." n
n
(erlang-skel-separator-start 2)
"%% @private" n
"%% @doc" n
- "%% If the gen_statem runs with CallbackMode =:= handle_event_function" n
- "%% this function is called for every event a gen_statem receives." n
+ "%% This function is called by a gen_statem when it is about to" n
+ "%% terminate. It should be the opposite of Module:init/1 and do any" n
+ "%% necessary cleaning up. When it returns, the gen_statem terminates with" n
+ "%% Reason. The return value is ignored." n
+ (erlang-skel-separator-end 2)
+ "-spec terminate(Reason :: term(), State :: term(), Data :: term()) ->" n>
+ "any()." n
+ "terminate(_Reason, _State, _Data) ->" n>
+ "void." n
+ n
+ (erlang-skel-separator-start 2)
+ "%% @private" n
+ "%% @doc" n
+ "%% Convert process state when code is changed" n
+ (erlang-skel-separator-end 2)
+ "-spec code_change(" n>
+ "OldVsn :: term() | {down,term()}," n>
+ "State :: term(), Data :: term(), Extra :: term()) ->" n>
+ "{ok, NewState :: term(), NewData :: term()} |" n>
+ "(Reason :: term())." n
+ "code_change(_OldVsn, State, Data, _Extra) ->" n>
+ "{ok, State, Data}." n
+ n
+ (erlang-skel-double-separator-start 3)
+ "%%% Internal functions" n
+ (erlang-skel-double-separator-end 3)
+ )
+ "*The template of a gen_statem (StateName/3).
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-gen-statem-handle-event
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(gen_statem)." n n
+
+ "%% API" n
+ "-export([start_link/0])." n
+ n
+ "%% gen_statem callbacks" n
+ "-export([callback_mode/0, init/1, terminate/3, code_change/4])." n
+ "-export([handle_event/4])." n
+ n
+ "-define(SERVER, ?MODULE)." n
+ n
+ "-record(data, {})." n
+ n
+ (erlang-skel-double-separator-start 3)
+ "%%% API" n
+ (erlang-skel-double-separator-end 3) n
+ (erlang-skel-separator-start 2)
+ "%% @doc" n
+ "%% Creates a gen_statem process which calls Module:init/1 to" n
+ "%% initialize. To ensure a synchronized start-up procedure, this" n
+ "%% function does not return until Module:init/1 has returned." n
+ "%%" n
+ (erlang-skel-separator-end 2)
+ "-spec start_link() ->" n>
+ "{ok, Pid :: pid()} |" n>
+ "ignore |" n>
+ "{error, Error :: term()}." n
+ "start_link() ->" n>
+ "gen_statem:start_link({local, ?SERVER}, ?MODULE, [], [])." n
+ n
+ (erlang-skel-double-separator-start 3)
+ "%%% gen_statem callbacks" n
+ (erlang-skel-double-separator-end 3) n
+ (erlang-skel-separator-start 2)
+ "%% @private" n
+ "%% @doc" n
+ "%% Define the callback_mode() for this callback module." n
+ (erlang-skel-separator-end 2)
+ "-spec callback_mode() -> gen_statem:callback_mode_result()." n
+ "callback_mode() -> handle_event_function." n
+ n
+ (erlang-skel-separator-start 2)
+ "%% @private" n
+ "%% @doc" n
+ "%% Whenever a gen_statem is started using gen_statem:start/[3,4] or" n
+ "%% gen_statem:start_link/[3,4], this function is called by the new" n
+ "%% process to initialize." n
(erlang-skel-separator-end 2)
- "-spec handle_event(" n>
- "gen_statem:event_type(), Msg :: term()," n>
- "State :: term(), Data :: term()) ->" n>
- "gen_statem:handle_event_result(). " n
+ "-spec init(Args :: term()) ->" n>
+ "gen_statem:init_result(term())." n
+ "init([]) ->" n>
+ "process_flag(trap_exit, true)," n>
+ "{ok, state_name, #data{}}." n
+ n
+ (erlang-skel-separator-start 2)
+ "%% @private" n
+ "%% @doc" n
+ "%% This function is called for every event a gen_statem receives." n
+ (erlang-skel-separator-end 2)
+ "-spec handle_event('enter'," n>
+ "OldState :: term()," n>
+ "State :: term()," n>
+ "Data :: term()) ->" n>
+ "gen_statem:state_enter_result(term());" n>
+ "(gen_statem:event_type()," n>
+ "Msg :: term()," n>
+ "State :: term()," n>
+ "Data :: term()) ->" n>
+ "gen_statem:event_handler_result(term())." n
+ ;;
"handle_event({call,From}, _Msg, State, Data) ->" n>
"{next_state, State, Data, [{reply,From,ok}]}." n
n
@@ -965,7 +1069,8 @@ Please see the function `tempo-define-template'.")
"-spec code_change(" n>
"OldVsn :: term() | {down,term()}," n>
"State :: term(), Data :: term(), Extra :: term()) ->" n>
- "{ok, NewState :: term(), NewData :: term()}." n
+ "{ok, NewState :: term(), NewData :: term()} |" n>
+ "(Reason :: term())." n
"code_change(_OldVsn, State, Data, _Extra) ->" n>
"{ok, State, Data}." n
n
@@ -973,7 +1078,7 @@ Please see the function `tempo-define-template'.")
"%%% Internal functions" n
(erlang-skel-double-separator-end 3)
)
- "*The template of a gen_statem.
+ "*The template of a gen_statem (handle_event/4).
Please see the function `tempo-define-template'.")
(defvar erlang-skel-wx-object
diff --git a/lib/tools/emacs/erlang-start.el b/lib/tools/emacs/erlang-start.el
index 76e0575e68..160057e179 100644
--- a/lib/tools/emacs/erlang-start.el
+++ b/lib/tools/emacs/erlang-start.el
@@ -78,6 +78,21 @@
(autoload 'erlang-find-tag-other-window "erlang"
"Like `find-tag-other-window'. Capable of retreiving Erlang modules.")
+;;
+;; Declare functions in "erlang-edoc.el".
+;;
+
+(autoload 'erlang-edoc-mode "erlang-edoc" "Toggle Erlang-Edoc mode on or off." t)
+
+;;
+;; Declare functions in "erldoc.el".
+;;
+
+(autoload 'erldoc-browse "erldoc" "\n\n(fn MFA)" t nil)
+(autoload 'erldoc-browse-topic "erldoc" "\n\n(fn TOPIC)" t nil)
+(autoload 'erldoc-apropos "erldoc" "\n\n(fn PATTERN)" t nil)
+(autoload 'erldoc-eldoc-function "erldoc" "\
+A function suitable for `eldoc-documentation-function'.\n\n(fn)" nil nil)
;;
;; Associate files extensions ".erl" and ".hrl" with Erlang mode.
diff --git a/lib/tools/emacs/erlang-test.el b/lib/tools/emacs/erlang-test.el
index 9a146632c5..ba6190d194 100644
--- a/lib/tools/emacs/erlang-test.el
+++ b/lib/tools/emacs/erlang-test.el
@@ -52,28 +52,42 @@ concatenated to form an erlang file to test on.")
(ert-deftest erlang-test-tags ()
(let* ((dir (make-temp-file "erlang-test" t))
- (erlang-file (expand-file-name "erlang_test.erl" dir))
- (tags-file (expand-file-name "TAGS" dir))
- tags-file-name tags-table-list erlang-buffer)
- (unwind-protect
- (progn
- (erlang-test-create-erlang-file erlang-file)
- (erlang-test-compile-tags erlang-file tags-file)
- (setq erlang-buffer (find-file-noselect erlang-file))
- (with-current-buffer erlang-buffer
- (setq-local tags-file-name tags-file))
- ;; Setting global tags-file-name is a workaround for
- ;; GNU Emacs bug#23164.
- (setq tags-file-name tags-file)
- (erlang-test-completion-table)
- (erlang-test-xref-find-definitions erlang-file erlang-buffer))
- (when (buffer-live-p erlang-buffer)
- (kill-buffer erlang-buffer))
- (let ((tags-buffer (find-buffer-visiting tags-file)))
- (when (buffer-live-p tags-buffer)
- (kill-buffer tags-buffer)))
- (when (file-exists-p dir)
- (delete-directory dir t)))))
+ (erlang-file (expand-file-name "erlang_test.erl" dir))
+ (tags-file (expand-file-name "TAGS" dir))
+ (old-tags-file-name (default-value 'tags-file-name))
+ (old-tags-table-list (default-value 'tags-table-list))
+ tags-file-name
+ tags-table-list
+ tags-table-set-list
+ erlang-buffer
+ erlang-mode-hook
+ prog-mode-hook
+ erlang-shell-mode-hook
+ tags-add-tables)
+ (unwind-protect
+ (progn
+ (setq-default tags-file-name nil)
+ (setq-default tags-table-list nil)
+ (erlang-test-create-erlang-file erlang-file)
+ (erlang-test-compile-tags erlang-file tags-file)
+ (setq erlang-buffer (find-file-noselect erlang-file))
+ (with-current-buffer erlang-buffer
+ (setq-local tags-file-name tags-file))
+ ;; Setting global tags-file-name is a workaround for
+ ;; GNU Emacs bug#23164.
+ (setq tags-file-name tags-file)
+ (erlang-test-complete-at-point tags-file)
+ (erlang-test-completion-table)
+ (erlang-test-xref-find-definitions erlang-file erlang-buffer))
+ (when (buffer-live-p erlang-buffer)
+ (kill-buffer erlang-buffer))
+ (let ((tags-buffer (find-buffer-visiting tags-file)))
+ (when (buffer-live-p tags-buffer)
+ (kill-buffer tags-buffer)))
+ (when (file-exists-p dir)
+ (delete-directory dir t))
+ (setq-default tags-file-name old-tags-file-name)
+ (setq-default tags-table-list old-tags-table-list))))
(defun erlang-test-create-erlang-file (erlang-file)
(with-temp-file erlang-file
@@ -116,6 +130,54 @@ concatenated to form an erlang file to test on.")
(should (eq expected-line (line-number-at-pos)))
(should (= (point-at-bol) (point))))
+(defun erlang-test-complete-at-point (tags-file)
+ (with-temp-buffer
+ (erlang-mode)
+ (setq-local tags-file-name tags-file)
+ (insert "\nerlang_test:fun")
+ (erlang-complete-tag)
+ (should (looking-back "erlang_test:function"))
+ (insert "\nfun")
+ (erlang-complete-tag)
+ (should (looking-back "function"))
+ (insert "\nerlang_")
+ (erlang-complete-tag)
+ (should (looking-back "erlang_test:"))))
+
+
+(ert-deftest erlang-test-compile-options ()
+ (erlang-test-format-opt t
+ "t")
+ (erlang-test-format-opt nil
+ "nil")
+ (erlang-test-format-opt (cons 1 2)
+ "{1, 2}")
+ (erlang-test-format-opt (list 1)
+ "[1]")
+ (erlang-test-format-opt (list 1 2)
+ "[1, 2]")
+ (erlang-test-format-opt (list 1 2 3)
+ "[1, 2, 3]")
+ (erlang-test-format-opt 'symbol
+ "symbol")
+ (erlang-test-format-opt "string"
+ "\"string\"")
+ (erlang-test-format-opt []
+ "{}")
+ (erlang-test-format-opt [1]
+ "{1}")
+ (erlang-test-format-opt [1 2]
+ "{1, 2}")
+ (erlang-test-format-opt [1 2 (3 [4 5 6] 7)]
+ "{1, 2, [3, {4, 5, 6}, 7]}"))
+
+(defun erlang-test-format-opt (elisp &optional expected-erlang)
+ (let ((erlang (inferior-erlang-format-opt elisp)))
+ (message "%s -> %s" elisp erlang)
+ (when expected-erlang
+ (should (equal erlang expected-erlang)))
+ erlang))
+
(provide 'erlang-test)
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index a2062180f3..39c6065ce4 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -59,7 +59,7 @@
;; Please state as exactly as possible:
;; - Version number of Erlang Mode (see the menu), Emacs, Erlang,
-;; and of any other relevant software.
+;; and of any other relevant software.
;; - What the expected result was.
;; - What you did, preferably in a repeatable step-by-step form.
;; - A description of the unexpected result.
@@ -78,6 +78,10 @@
;; Variables:
+(defgroup erlang nil
+ "The Erlang programming language."
+ :group 'languages)
+
(defconst erlang-version "2.7"
"The version number of Erlang mode.")
@@ -91,20 +95,20 @@ Erlang mode menu.")
(eval-and-compile
(defconst erlang-emacs-major-version
(if (boundp 'emacs-major-version)
- emacs-major-version
+ emacs-major-version
(string-match "\\([0-9]+\\)\\.\\([0-9]+\\)" emacs-version)
(erlang-string-to-int (substring emacs-version
- (match-beginning 1) (match-end 1))))
+ (match-beginning 1) (match-end 1))))
"Major version number of Emacs."))
(eval-and-compile
(defconst erlang-emacs-minor-version
- (if (boundp 'emacs-minor-version)
- emacs-minor-version
- (string-match "\\([0-9]+\\)\\.\\([0-9]+\\)" emacs-version)
- (erlang-string-to-int (substring emacs-version
- (match-beginning 2) (match-end 2))))
- "Minor version number of Emacs."))
+ (if (boundp 'emacs-minor-version)
+ emacs-minor-version
+ (string-match "\\([0-9]+\\)\\.\\([0-9]+\\)" emacs-version)
+ (erlang-string-to-int (substring emacs-version
+ (match-beginning 2) (match-end 2))))
+ "Minor version number of Emacs."))
(defconst erlang-xemacs-p (string-match "Lucid\\|XEmacs" emacs-version)
"Non-nil when running under XEmacs or Lucid Emacs.")
@@ -119,12 +123,12 @@ buffers in Erlang mode, just like under GNU Emacs.
Never EVER set this variable!")
(defvar erlang-menu-items '(erlang-menu-base-items
- erlang-menu-skel-items
- erlang-menu-shell-items
- erlang-menu-compile-items
- erlang-menu-man-items
- erlang-menu-personal-items
- erlang-menu-version-items)
+ erlang-menu-skel-items
+ erlang-menu-shell-items
+ erlang-menu-compile-items
+ erlang-menu-man-items
+ erlang-menu-personal-items
+ erlang-menu-version-items)
"*List of menu item list to combine to create Erlang mode menu.
External programs which temporarily add menu items to the Erlang mode
@@ -170,7 +174,7 @@ variable.")
("TAGS"
(("Find Tag" find-tag)
("Find Next Tag" erlang-find-next-tag)
- ;("Find Regexp" find-tag-regexp)
+ ;("Find Regexp" find-tag-regexp)
("Complete Word" erlang-complete-tag)
("Tags Apropos" tags-apropos)
("Search Files" tags-search))))
@@ -475,6 +479,11 @@ To activate the workaround, place the following in your `~/.emacs' file:
"*Indentation of Erlang calls/clauses within blocks.")
(put 'erlang-indent-level 'safe-local-variable 'integerp)
+(defvar erlang-icr-indent nil
+ "*Indentation of Erlang if/case/receive/ patterns. `nil' means
+ keeping default behavior. When non-nil, indent to th column of
+ if/case/receive.")
+
(defvar erlang-indent-guard 2
"*Indentation of Erlang guards.")
(put 'erlang-indent-guard 'safe-local-variable 'integerp)
@@ -558,35 +567,35 @@ This is an elisp list of options. Each option can be either:
Supporting \_< and \_> This is determined by checking the version of Emacs used."))
(eval-and-compile
- (defconst erlang-atom-quoted-regexp
+ (defconst erlang-atom-quoted-regexp
"'\\(?:[^\\']\\|\\(?:\\\\.\\)\\)*'"
"Regexp describing a single-quoted atom"))
(eval-and-compile
(defconst erlang-atom-regular-regexp
(if erlang-regexp-modern-p
- "\\_<[[:lower:]]\\(?:\\sw\\|\\s_\\)*\\_>"
+ "\\_<[[:lower:]]\\(?:\\sw\\|\\s_\\)*\\_>"
"\\<[[:lower:]]\\(?:\\sw\\|\\s_\\)*\\>")
"Regexp describing a regular (non-quoted) atom"))
(eval-and-compile
- (defconst erlang-atom-regexp
- (concat "\\(" erlang-atom-quoted-regexp "\\|"
- erlang-atom-regular-regexp "\\)")
+ (defconst erlang-atom-regexp
+ (concat "\\(" erlang-atom-quoted-regexp "\\|"
+ erlang-atom-regular-regexp "\\)")
"Regexp describing an Erlang atom."))
(eval-and-compile
(defconst erlang-atom-regexp-matches 1
"Number of regexp parenthesis pairs in `erlang-atom-regexp'.
-
+
This is used to determine parenthesis matches in complex regexps which
contains `erlang-atom-regexp'."))
(eval-and-compile
- (defconst erlang-variable-regexp
- (if erlang-regexp-modern-p
- "\\_<\\([[:upper:]_]\\(?:\\sw\\|\\s_\\)*\\)\\_>"
+ (defconst erlang-variable-regexp
+ (if erlang-regexp-modern-p
+ "\\_<\\([[:upper:]_]\\(?:\\sw\\|\\s_\\)*\\)\\_>"
"\\<\\([[:upper:]_]\\(?:\\sw\\|\\s_\\)*\\)\\>")
"Regexp which should match an Erlang variable.
@@ -605,13 +614,13 @@ This is used to determine matches in complex regexps which contains
"Like `regexp-opt', except if PAREN is `symbols', then the
resulting regexp is surrounded by \\_< and \\_>."
(if (eq paren 'symbols)
- (if erlang-regexp-modern-p
- (concat "\\_<" (regexp-opt strings t) "\\_>")
- (concat "\\<" (regexp-opt strings t) "\\>"))
+ (if erlang-regexp-modern-p
+ (concat "\\_<" (regexp-opt strings t) "\\_>")
+ (concat "\\<" (regexp-opt strings t) "\\>"))
(regexp-opt strings paren))))
-(eval-and-compile
+(eval-and-compile
(defvar erlang-keywords
'("after"
"begin"
@@ -630,7 +639,7 @@ resulting regexp is surrounded by \\_< and \\_>."
(eval-and-compile
(defconst erlang-keywords-regexp (erlang-regexp-opt erlang-keywords 'symbols)))
-
+
(eval-and-compile
(defvar erlang-operators
'("and"
@@ -653,7 +662,7 @@ resulting regexp is surrounded by \\_< and \\_>."
(eval-and-compile
(defconst erlang-operators-regexp (erlang-regexp-opt erlang-operators 'symbols)))
-
+
(eval-and-compile
(defvar erlang-guards
@@ -676,7 +685,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"binary"
"bitstring"
"boolean"
- ;;"float" ; Not included to avoid clashes with the bif float/1
+ ;;"float" ; Not included to avoid clashes with the bif float/1
"function"
"integer"
"list"
@@ -722,7 +731,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"Erlang type specs types"))
(eval-and-compile
- (defconst erlang-predefined-types-regexp
+ (defconst erlang-predefined-types-regexp
(erlang-regexp-opt erlang-predefined-types 'symbols)))
@@ -842,7 +851,7 @@ resulting regexp is surrounded by \\_< and \\_>."
(eval-and-compile
(defconst erlang-int-bif-regexp (erlang-regexp-opt erlang-int-bifs 'symbols)))
-
+
(eval-and-compile
(defvar erlang-ext-bifs
@@ -997,8 +1006,8 @@ behaviour.")
(let ((map (make-sparse-keymap)))
(unless (boundp 'indent-line-function)
(define-key map "\t" 'erlang-indent-command))
- (define-key map ";" 'erlang-electric-semicolon)
- (define-key map "," 'erlang-electric-comma)
+ (define-key map ";" 'erlang-electric-semicolon)
+ (define-key map "," 'erlang-electric-comma)
(define-key map "<" 'erlang-electric-lt)
(define-key map ">" 'erlang-electric-gt)
(define-key map "\C-m" 'erlang-electric-newline)
@@ -1010,7 +1019,7 @@ behaviour.")
(unless (boundp 'beginning-of-defun-function)
(define-key map "\M-\C-a" 'erlang-beginning-of-function)
(define-key map "\M-\C-e" 'erlang-end-of-function)
- (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs
+ (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs
(define-key map "\M-\t" 'erlang-complete-tag)
(define-key map "\C-c\M-\t" 'tempo-complete-tag)
(define-key map "\M-+" 'erlang-find-next-tag)
@@ -1064,7 +1073,7 @@ behaviour.")
(defvar erlang-font-lock-keywords-function-header
(list
(list (concat "^" erlang-atom-regexp "\\s-*(")
- 1 'font-lock-function-name-face t))
+ 1 'font-lock-function-name-face t))
"Font lock keyword highlighting a function header.")
(defface erlang-font-lock-exported-function-name-face
@@ -1086,7 +1095,7 @@ behaviour.")
(defvar erlang-font-lock-keywords-exported-function-header
(list
(list #'erlang-match-next-exported-function
- 1 'erlang-font-lock-exported-function-name-face t))
+ 1 'erlang-font-lock-exported-function-name-face t))
"Font lock keyword highlighting an exported function header.")
(defvar erlang-font-lock-keywords-int-bifs
@@ -1098,8 +1107,8 @@ behaviour.")
(defvar erlang-font-lock-keywords-ext-bifs
(list
(list (concat "\\<\\(erlang\\)\\s-*:\\s-*" erlang-ext-bif-regexp "\\s-*(")
- '(1 'font-lock-builtin-face)
- '(2 'font-lock-builtin-face)))
+ '(1 'font-lock-builtin-face)
+ '(2 'font-lock-builtin-face)))
"Font lock keyword highlighting built in functions.")
(defvar erlang-font-lock-keywords-int-function-calls
@@ -1113,7 +1122,7 @@ behaviour.")
(list (concat erlang-atom-regexp "\\s-*:\\s-*"
erlang-atom-regexp "\\s-*(")
'(1 'font-lock-type-face)
- '(2 'font-lock-type-face)))
+ '(2 'font-lock-type-face)))
"Font lock keyword highlighting an external function call.")
(defvar erlang-font-lock-keywords-fun-n
@@ -1131,7 +1140,7 @@ behaviour.")
(defvar erlang-font-lock-keywords-dollar
(list
(list "\\(\\$\\([^\\]\\|\\\\\\([^0-7^\n]\\|[0-7]+\\|\\^[a-zA-Z]\\)\\)\\)"
- 1 'font-lock-constant-face))
+ 1 'font-lock-constant-face))
"Font lock keyword highlighting numbers in ASCII form (e.g. $A).")
(defvar erlang-font-lock-keywords-arrow
@@ -1151,18 +1160,18 @@ behaviour.")
(defvar erlang-font-lock-keywords-attr
(list
- (list (concat "^\\(-" erlang-atom-regexp "\\)\\(\\s-\\|\\.\\|(\\)")
- 1 (if (boundp 'font-lock-preprocessor-face)
- 'font-lock-preprocessor-face
- 'font-lock-constant-face)))
+ (list (concat "^\\(-" erlang-atom-regexp "\\)\\(\\s-\\|\\.\\|(\\)")
+ 1 (if (boundp 'font-lock-preprocessor-face)
+ 'font-lock-preprocessor-face
+ 'font-lock-constant-face)))
"Font lock keyword highlighting attributes.")
(defvar erlang-font-lock-keywords-quotes
(list
(list "`\\([-+a-zA-Z0-9_:*][-+a-zA-Z0-9_:*]+\\)'"
- 1
- 'font-lock-keyword-face
- t))
+ 1
+ 'font-lock-keyword-face
+ t))
"Font lock keyword highlighting words in single quotes in comments.
This is not the highlighting of Erlang strings and atoms, which
@@ -1171,27 +1180,27 @@ are highlighted by syntactic analysis.")
(defvar erlang-font-lock-keywords-guards
(list
(list (concat "[^:]" erlang-guards-regexp "\\s-*(")
- 1 'font-lock-builtin-face))
+ 1 'font-lock-builtin-face))
"Font lock keyword highlighting guards.")
(defvar erlang-font-lock-keywords-predefined-types
(list
(list (concat "[^:]" erlang-predefined-types-regexp "\\s-*(")
- 1 'font-lock-builtin-face))
+ 1 'font-lock-builtin-face))
"Font lock keyword highlighting predefined types.")
(defvar erlang-font-lock-keywords-macros
(list
(list (concat "?\\s-*\\(" erlang-atom-regexp
- "\\|" erlang-variable-regexp "\\)")
- 1 'font-lock-constant-face)
+ "\\|" erlang-variable-regexp "\\)")
+ 1 'font-lock-constant-face)
(list (concat "^\\(-\\(?:define\\|ifn?def\\)\\)\\s-*(\\s-*\\(" erlang-atom-regexp
- "\\|" erlang-variable-regexp "\\)")
- (if (boundp 'font-lock-preprocessor-face)
- (list 1 'font-lock-preprocessor-face t)
- (list 1 'font-lock-constant-face t))
- (list 3 'font-lock-type-face t t))
+ "\\|" erlang-variable-regexp "\\)")
+ (if (boundp 'font-lock-preprocessor-face)
+ (list 1 'font-lock-preprocessor-face t)
+ (list 1 'font-lock-constant-face t))
+ (list 3 'font-lock-type-face t t))
(list "^-e\\(lse\\|ndif\\)\\>" 0 'font-lock-preprocessor-face t))
"Font lock keyword highlighting macros.
This must be placed in front of `erlang-font-lock-keywords-vars'.")
@@ -1202,8 +1211,8 @@ This must be placed in front of `erlang-font-lock-keywords-vars'.")
1 'font-lock-type-face)
;; Don't highlight numerical constants.
(list (if erlang-regexp-modern-p
- "\\_<[0-9]+#\\([0-9a-zA-Z]+\\)"
- "\\<[0-9]+#\\([0-9a-zA-Z]+\\)")
+ "\\_<[0-9]+#\\([0-9a-zA-Z]+\\)"
+ "\\<[0-9]+#\\([0-9a-zA-Z]+\\)")
1 nil t)
(list (concat "^-record\\s-*(\\s-*" erlang-atom-regexp)
1 'font-lock-type-face))
@@ -1212,8 +1221,8 @@ This must be placed in front of `erlang-font-lock-keywords-vars'.")
(defvar erlang-font-lock-keywords-vars
(list
- (list (concat "[^#]" erlang-variable-regexp) ; no numerical constants
- 1 'font-lock-variable-name-face))
+ (list (concat "[^#]" erlang-variable-regexp) ; no numerical constants
+ 1 'font-lock-variable-name-face))
"Font lock keyword highlighting Erlang variables.
Must be preceded by `erlang-font-lock-keywords-macros' to work properly.")
@@ -1236,32 +1245,32 @@ Example:
(defvar erlang-font-lock-keywords-1
(append erlang-font-lock-keywords-function-header
- erlang-font-lock-keywords-dollar
- erlang-font-lock-keywords-arrow
- erlang-font-lock-keywords-keywords
- )
+ erlang-font-lock-keywords-dollar
+ erlang-font-lock-keywords-arrow
+ erlang-font-lock-keywords-keywords
+ )
;; DocStringOrig: erlang-font-lock-keywords
erlang-font-lock-descr-string)
(defvar erlang-font-lock-keywords-2
(append erlang-font-lock-keywords-1
- erlang-font-lock-keywords-int-bifs
- erlang-font-lock-keywords-ext-bifs
- erlang-font-lock-keywords-attr
- erlang-font-lock-keywords-quotes
- erlang-font-lock-keywords-guards
- )
+ erlang-font-lock-keywords-int-bifs
+ erlang-font-lock-keywords-ext-bifs
+ erlang-font-lock-keywords-attr
+ erlang-font-lock-keywords-quotes
+ erlang-font-lock-keywords-guards
+ )
;; DocStringCopy: erlang-font-lock-keywords
erlang-font-lock-descr-string)
(defvar erlang-font-lock-keywords-3
(append erlang-font-lock-keywords-2
- erlang-font-lock-keywords-operators
- erlang-font-lock-keywords-macros
- erlang-font-lock-keywords-records
- erlang-font-lock-keywords-vars
- erlang-font-lock-keywords-predefined-types
- )
+ erlang-font-lock-keywords-operators
+ erlang-font-lock-keywords-macros
+ erlang-font-lock-keywords-records
+ erlang-font-lock-keywords-vars
+ erlang-font-lock-keywords-predefined-types
+ )
;; DocStringCopy: erlang-font-lock-keywords
erlang-font-lock-descr-string)
@@ -1269,10 +1278,10 @@ Example:
(append erlang-font-lock-keywords-3
erlang-font-lock-keywords-exported-function-header
erlang-font-lock-keywords-int-function-calls
- erlang-font-lock-keywords-ext-function-calls
- erlang-font-lock-keywords-fun-n
+ erlang-font-lock-keywords-ext-function-calls
+ erlang-font-lock-keywords-fun-n
erlang-font-lock-keywords-lc
- )
+ )
;; DocStringCopy: erlang-font-lock-keywords
erlang-font-lock-descr-string)
@@ -1333,17 +1342,17 @@ replaced by `erlang-etags-tags-completion-table'.")
(eval-when-compile
(if (or (featurep 'bytecomp)
- (featurep 'byte-compile))
+ (featurep 'byte-compile))
(progn
- (cond ((string-match "Lucid\\|XEmacs" emacs-version)
- (put 'comment-indent-hook 'byte-obsolete-variable nil)
- ;; Do not warn for unused variables
- ;; when compiling under XEmacs.
- (setq byte-compile-warnings
- '(free-vars unresolved callargs redefine))))
- (require 'comint)
- (require 'tempo)
- (require 'compile))))
+ (cond ((string-match "Lucid\\|XEmacs" emacs-version)
+ (put 'comment-indent-hook 'byte-obsolete-variable nil)
+ ;; Do not warn for unused variables
+ ;; when compiling under XEmacs.
+ (setq byte-compile-warnings
+ '(free-vars unresolved callargs redefine))))
+ (require 'comint)
+ (require 'tempo)
+ (require 'compile))))
(defun erlang-version ()
@@ -1351,7 +1360,7 @@ replaced by `erlang-etags-tags-completion-table'.")
(interactive)
(if (erlang-interactive-p)
(message "Erlang mode version %s, written by Anders Lindgren"
- erlang-version))
+ erlang-version))
erlang-version)
(defun erlang-interactive-p ()
@@ -1389,7 +1398,7 @@ useful commands:
C-c C-q - Indent current function.
M-; - Create a comment at the end of the line.
M-q - Fill a comment, i.e. wrap lines so that they (hopefully)
- will look better.
+ will look better.
M-a - Goto the beginning of an Erlang clause.
M-C-a - Ditto for function.
M-e - Goto the end of an Erlang clause.
@@ -1436,8 +1445,11 @@ Other commands:
(erlang-skel-init)
(when (fboundp 'tempo-use-tag-list)
(tempo-use-tag-list 'erlang-tempo-tags))
- (when (boundp 'xref-backend-functions)
- (add-hook 'xref-backend-functions #'erlang-etags--xref-backend nil t))
+ (when (and (fboundp 'add-function) (fboundp 'erldoc-eldoc-function))
+ (or eldoc-documentation-function
+ (setq-local eldoc-documentation-function #'ignore))
+ (add-function :before-until (local 'eldoc-documentation-function)
+ #'erldoc-eldoc-function))
(run-hooks 'erlang-mode-hook)
(if (zerop (buffer-size))
(run-hooks 'erlang-new-file-hook)))
@@ -1450,35 +1462,35 @@ Other commands:
(defun erlang-syntax-table-init ()
(if (null erlang-mode-syntax-table)
(let ((table (make-syntax-table)))
- (modify-syntax-entry ?\n ">" table)
- (modify-syntax-entry ?\" "\"" table)
- (modify-syntax-entry ?# "." table)
-;; (modify-syntax-entry ?$ "\\" table) ;; Creates problems with indention afterwards
-;; (modify-syntax-entry ?$ "'" table) ;; Creates syntax highlighting and indention problems
- (modify-syntax-entry ?$ "/" table) ;; Misses the corner case "string that ends with $"
- ;; we have to live with that for now..it is the best alternative
- ;; that can be worked around with "string hat ends with \$"
- (modify-syntax-entry ?% "<" table)
- (modify-syntax-entry ?& "." table)
- (modify-syntax-entry ?\' "\"" table)
- (modify-syntax-entry ?* "." table)
- (modify-syntax-entry ?+ "." table)
- (modify-syntax-entry ?- "." table)
- (modify-syntax-entry ?/ "." table)
- (modify-syntax-entry ?: "." table)
- (modify-syntax-entry ?< "." table)
- (modify-syntax-entry ?= "." table)
- (modify-syntax-entry ?> "." table)
- (modify-syntax-entry ?\\ "\\" table)
- (modify-syntax-entry ?_ "_" table)
- (modify-syntax-entry ?| "." table)
- (modify-syntax-entry ?^ "'" table)
-
- ;; Pseudo bit-syntax: Latin1 double angle quotes as parens.
- ;;(modify-syntax-entry ?\253 "(?\273" table)
- ;;(modify-syntax-entry ?\273 ")?\253" table)
-
- (setq erlang-mode-syntax-table table)))
+ (modify-syntax-entry ?\n ">" table)
+ (modify-syntax-entry ?\" "\"" table)
+ (modify-syntax-entry ?# "." table)
+ ;; (modify-syntax-entry ?$ "\\" table) ;; Creates problems with indention afterwards
+ ;; (modify-syntax-entry ?$ "'" table) ;; Creates syntax highlighting and indention problems
+ (modify-syntax-entry ?$ "/" table) ;; Misses the corner case "string that ends with $"
+ ;; we have to live with that for now..it is the best alternative
+ ;; that can be worked around with "string hat ends with \$"
+ (modify-syntax-entry ?% "<" table)
+ (modify-syntax-entry ?& "." table)
+ (modify-syntax-entry ?\' "\"" table)
+ (modify-syntax-entry ?* "." table)
+ (modify-syntax-entry ?+ "." table)
+ (modify-syntax-entry ?- "." table)
+ (modify-syntax-entry ?/ "." table)
+ (modify-syntax-entry ?: "." table)
+ (modify-syntax-entry ?< "." table)
+ (modify-syntax-entry ?= "." table)
+ (modify-syntax-entry ?> "." table)
+ (modify-syntax-entry ?\\ "\\" table)
+ (modify-syntax-entry ?_ "_" table)
+ (modify-syntax-entry ?| "." table)
+ (modify-syntax-entry ?^ "'" table)
+
+ ;; Pseudo bit-syntax: Latin1 double angle quotes as parens.
+ ;;(modify-syntax-entry ?\253 "(?\273" table)
+ ;;(modify-syntax-entry ?\273 ")?\253" table)
+
+ (setq erlang-mode-syntax-table table)))
(set-syntax-table erlang-mode-syntax-table))
@@ -1488,12 +1500,12 @@ Other commands:
;; delsel/pending-del mode. Also, set up text properties for bit
;; syntax handling.
(mapc #'(lambda (cmd)
- (put cmd 'delete-selection t) ;for delsel (Emacs)
- (put cmd 'pending-delete t)) ;for pending-del (XEmacs)
- '(erlang-electric-semicolon
- erlang-electric-comma
- erlang-electric-gt))
-
+ (put cmd 'delete-selection t) ;for delsel (Emacs)
+ (put cmd 'pending-delete t)) ;for pending-del (XEmacs)
+ '(erlang-electric-semicolon
+ erlang-electric-comma
+ erlang-electric-gt))
+
(put 'bitsyntax-open-outer 'syntax-table '(4 . ?>))
(put 'bitsyntax-open-outer 'rear-nonsticky '(category))
(put 'bitsyntax-open-inner 'rear-nonsticky '(category))
@@ -1514,8 +1526,6 @@ Other commands:
(setq paragraph-separate paragraph-start)
(make-local-variable 'paragraph-ignore-fill-prefix)
(setq paragraph-ignore-fill-prefix t)
- (make-local-variable 'require-final-newline)
- (setq require-final-newline t)
(make-local-variable 'defun-prompt-regexp)
(setq defun-prompt-regexp erlang-defun-prompt-regexp)
(make-local-variable 'comment-start)
@@ -1548,17 +1558,15 @@ Other commands:
(set (make-local-variable 'outline-regexp) "[[:lower:]0-9_]+ *(.*) *-> *$")
(set (make-local-variable 'outline-level) (lambda () 1))
(set (make-local-variable 'add-log-current-defun-function)
- 'erlang-current-defun)
- (set (make-local-variable 'find-tag-default-function)
- 'erlang-find-tag-for-completion))
+ 'erlang-current-defun))
(defun erlang-font-lock-init ()
"Initialize Font Lock for Erlang mode."
(or erlang-font-lock-syntax-table
(setq erlang-font-lock-syntax-table
- (let ((table (copy-syntax-table erlang-mode-syntax-table)))
- (modify-syntax-entry ?_ "w" table)
- table)))
+ (let ((table (copy-syntax-table erlang-mode-syntax-table)))
+ (modify-syntax-entry ?_ "w" table)
+ table)))
(set (make-local-variable 'font-lock-syntax-table)
erlang-font-lock-syntax-table)
(set (make-local-variable (if (boundp 'syntax-begin-function)
@@ -1567,23 +1575,23 @@ Other commands:
'erlang-beginning-of-clause)
(make-local-variable 'font-lock-keywords)
(let ((level (cond ((boundp 'font-lock-maximum-decoration)
- (symbol-value 'font-lock-maximum-decoration))
- ((boundp 'font-lock-use-maximal-decoration)
- (symbol-value 'font-lock-use-maximal-decoration))
- (t nil))))
+ (symbol-value 'font-lock-maximum-decoration))
+ ((boundp 'font-lock-use-maximal-decoration)
+ (symbol-value 'font-lock-use-maximal-decoration))
+ (t nil))))
(if (consp level)
- (setq level (cdr-safe (or (assq 'erlang-mode level)
- (assq t level)))))
+ (setq level (cdr-safe (or (assq 'erlang-mode level)
+ (assq t level)))))
;; `level' can here be:
;; A number - The fontification level
;; nil - Use the default
;; t - Use maximum
(cond ((eq level nil)
- (set 'font-lock-keywords erlang-font-lock-keywords))
- ((eq level 1)
- (set 'font-lock-keywords erlang-font-lock-keywords-1))
- ((eq level 2)
- (set 'font-lock-keywords erlang-font-lock-keywords-2))
+ (set 'font-lock-keywords erlang-font-lock-keywords))
+ ((eq level 1)
+ (set 'font-lock-keywords erlang-font-lock-keywords-1))
+ ((eq level 2)
+ (set 'font-lock-keywords erlang-font-lock-keywords-2))
((eq level 3)
(set 'font-lock-keywords erlang-font-lock-keywords-3))
(t
@@ -1592,11 +1600,11 @@ Other commands:
;; Modern font-locks can handle the above much more elegantly:
(set (make-local-variable 'font-lock-defaults)
'((erlang-font-lock-keywords erlang-font-lock-keywords-1
- erlang-font-lock-keywords-2
- erlang-font-lock-keywords-3
- erlang-font-lock-keywords-4)
- nil nil ((?_ . "w")) erlang-beginning-of-clause
- (font-lock-mark-block-function . erlang-mark-clause)
+ erlang-font-lock-keywords-2
+ erlang-font-lock-keywords-3
+ erlang-font-lock-keywords-4)
+ nil nil ((?_ . "w")) erlang-beginning-of-clause
+ (font-lock-mark-block-function . erlang-mark-clause)
(font-lock-syntactic-keywords
;; A dollar sign right before the double quote that ends a
;; string is not a character escape.
@@ -1610,8 +1618,8 @@ Other commands:
;; know whether matching started inside a string: limiting
;; search to a single line keeps things sane.
. (("\\(?:^\\|[^$]\\)\"\\(?:[^\"\n]\\|\\\\\"\\)*\\(\\$\\)\"" 1 "w")
- ;; Likewise for atoms
- ("\\(?:^\\|[^$]\\)'\\(?:[^'\n]\\|\\\\'\\)*\\(\\$\\)'" 1 "w")
+ ;; Likewise for atoms
+ ("\\(?:^\\|[^$]\\)'\\(?:[^'\n]\\|\\\\'\\)*\\(\\$\\)'" 1 "w")
;; And the dollar sign in $\" or $\' escapes two
;; characters, not just one.
("\\(\\$\\)\\\\[\"']" 1 "'"))))))
@@ -1657,17 +1665,17 @@ For a more elaborate example, please see the beginning of the file
(let ((res '()))
(while ks
(let* ((regexp (car (car ks)))
- (number (car (cdr (car ks))))
- (new-face (if (and faces (car faces))
- (car faces)
- (car (cdr (cdr (car ks))))))
- (overwrite (car (cdr (cdr (cdr (car ks))))))
- (new-keyword (list regexp number new-face)))
- (if overwrite (nconc new-keyword (list overwrite)))
- (setq res (cons new-keyword res))
- (setq ks (cdr ks))
- (if (and faces (cdr faces))
- (setq faces (cdr faces)))))
+ (number (car (cdr (car ks))))
+ (new-face (if (and faces (car faces))
+ (car faces)
+ (car (cdr (cdr (car ks))))))
+ (overwrite (car (cdr (cdr (cdr (car ks))))))
+ (new-keyword (list regexp number new-face)))
+ (if overwrite (nconc new-keyword (list overwrite)))
+ (setq res (cons new-keyword res))
+ (setq ks (cdr ks))
+ (if (and faces (cdr faces))
+ (setq faces (cdr faces)))))
(nreverse res)))
@@ -1759,57 +1767,57 @@ variable, i.e. it will popup when pressing the right mouse button.
Please see the variable `erlang-menu-base-items'."
(cond (erlang-xemacs-p
- (let ((menu (erlang-menu-xemacs name items keymap)))
- ;; We add the menu to the global menubar.
- ;;(funcall (symbol-function 'set-buffer-menubar)
- ;; (symbol-value 'current-menubar))
- (funcall (symbol-function 'add-submenu) nil menu)
- (setcdr erlang-xemacs-popup-menu (cdr menu))
- (if (and popup (boundp 'mode-popup-menu))
- (funcall (symbol-function 'set)
- 'mode-popup-menu erlang-xemacs-popup-menu))))
- ((>= erlang-emacs-major-version 19)
- (define-key keymap (vector 'menu-bar (intern name))
- (erlang-menu-make-keymap name items)))
- (t nil)))
+ (let ((menu (erlang-menu-xemacs name items keymap)))
+ ;; We add the menu to the global menubar.
+ ;;(funcall (symbol-function 'set-buffer-menubar)
+ ;; (symbol-value 'current-menubar))
+ (funcall (symbol-function 'add-submenu) nil menu)
+ (setcdr erlang-xemacs-popup-menu (cdr menu))
+ (if (and popup (boundp 'mode-popup-menu))
+ (funcall (symbol-function 'set)
+ 'mode-popup-menu erlang-xemacs-popup-menu))))
+ ((>= erlang-emacs-major-version 19)
+ (define-key keymap (vector 'menu-bar (intern name))
+ (erlang-menu-make-keymap name items)))
+ (t nil)))
(defun erlang-menu-make-keymap (name items)
"Build a menu for Emacs 19."
(let ((menumap (funcall (symbol-function 'make-sparse-keymap)
- name))
- (count 0)
- id def first second third)
+ name))
+ (count 0)
+ id def first second third)
(setq items (reverse items))
(while items
;; Replace any occurrence of atoms by their value.
(while (and items (atom (car items)) (not (null (car items))))
- (if (and (boundp (car items))
- (listp (symbol-value (car items))))
- (setq items (append (reverse (symbol-value (car items)))
- (cdr items)))
- (setq items (cdr items))))
+ (if (and (boundp (car items))
+ (listp (symbol-value (car items))))
+ (setq items (append (reverse (symbol-value (car items)))
+ (cdr items)))
+ (setq items (cdr items))))
(setq first (car-safe (car items)))
(setq second (car-safe (cdr-safe (car items))))
(setq third (car-safe (cdr-safe (cdr-safe (car items)))))
(cond ((null first)
- (setq count (+ count 1))
- (setq id (intern (format "separator-%d" count)))
- (setq def '("--" . nil)))
- ((and (consp second) (eq (car second) 'lambda))
- (setq count (+ count 1))
- (setq id (intern (format "lambda-%d" count)))
- (setq def (cons first second)))
- ((symbolp second)
- (setq id second)
- (setq def (cons first second)))
- (t
- (setq count (+ count 1))
- (setq id (intern (format "submenu-%d" count)))
- (setq def (erlang-menu-make-keymap first second))))
+ (setq count (+ count 1))
+ (setq id (intern (format "separator-%d" count)))
+ (setq def '("--" . nil)))
+ ((and (consp second) (eq (car second) 'lambda))
+ (setq count (+ count 1))
+ (setq id (intern (format "lambda-%d" count)))
+ (setq def (cons first second)))
+ ((symbolp second)
+ (setq id second)
+ (setq def (cons first second)))
+ (t
+ (setq count (+ count 1))
+ (setq id (intern (format "submenu-%d" count)))
+ (setq def (erlang-menu-make-keymap first second))))
(define-key menumap (vector id) def)
(if third
- (put id 'menu-enable third))
+ (put id 'menu-enable third))
(setq items (cdr items)))
(cons name menumap)))
@@ -1817,30 +1825,30 @@ Please see the variable `erlang-menu-base-items'."
(defun erlang-menu-xemacs (name items &optional keymap)
"Build a menu for XEmacs."
(let ((res '())
- first second third entry)
+ first second third entry)
(while items
;; Replace any occurrence of atoms by their value.
(while (and items (atom (car items)) (not (null (car items))))
- (if (and (boundp (car items))
- (listp (symbol-value (car items))))
- (setq items (append (reverse (symbol-value (car items)))
- (cdr items)))
- (setq items (cdr items))))
+ (if (and (boundp (car items))
+ (listp (symbol-value (car items))))
+ (setq items (append (reverse (symbol-value (car items)))
+ (cdr items)))
+ (setq items (cdr items))))
(setq first (car-safe (car items)))
(setq second (car-safe (cdr-safe (car items))))
(setq third (car-safe (cdr-safe (cdr-safe (car items)))))
(cond ((null first)
- (setq res (cons "------" res)))
- ((symbolp second)
- (setq res (cons (vector first second (or third t)) res)))
- ((and (consp second) (eq (car second) 'lambda))
- (setq res (cons (vector first (list 'call-interactively second)
- (or third t)) res)))
- (t
- (setq res (cons (cons first
- (cdr (erlang-menu-xemacs
- first second)))
- res))))
+ (setq res (cons "------" res)))
+ ((symbolp second)
+ (setq res (cons (vector first second (or third t)) res)))
+ ((and (consp second) (eq (car second) 'lambda))
+ (setq res (cons (vector first (list 'call-interactively second)
+ (or third t)) res)))
+ (t
+ (setq res (cons (cons first
+ (cdr (erlang-menu-xemacs
+ first second)))
+ res))))
(setq items (cdr items)))
(setq res (reverse res))
;; When adding a menu to a minor-mode keymap under Emacs,
@@ -1849,15 +1857,15 @@ Please see the variable `erlang-menu-base-items'."
;; (This could be expressed much clearer using backquotes,
;; but I don't want to pull in every package.)
(if keymap
- (let ((expr (list 'or
- (list 'eq keymap 'global-map)
- (list 'eq keymap (list 'current-local-map))
- (list 'symbol-value
- (list 'car-safe
- (list 'rassq
- keymap
- 'minor-mode-map-alist))))))
- (setq res (cons ':included (cons expr res)))))
+ (let ((expr (list 'or
+ (list 'eq keymap 'global-map)
+ (list 'eq keymap (list 'current-local-map))
+ (list 'symbol-value
+ (list 'car-safe
+ (list 'rassq
+ keymap
+ 'minor-mode-map-alist))))))
+ (setq res (cons ':included (cons expr res)))))
(cons name res)))
@@ -1872,13 +1880,13 @@ ALIST is list of pairs where the car is the old function and cdr the new."
(setq first (car-safe (car items)))
(setq second (car-safe (cdr-safe (car items))))
(cond ((null first))
- ((symbolp second)
- (setq pair (and second (assq second alist)))
- (if pair
- (setcar (cdr (car items)) (cdr pair))))
- ((and (consp second) (eq (car second) 'lambda)))
- (t
- (erlang-menu-substitute second alist)))
+ ((symbolp second)
+ (setq pair (and second (assq second alist)))
+ (if pair
+ (setcar (cdr (car items)) (cdr pair))))
+ ((and (consp second) (eq (car second) 'lambda)))
+ (t
+ (erlang-menu-substitute second alist)))
(setq items (cdr items)))))
@@ -1913,27 +1921,27 @@ Example:
\(setq erlang-menu-items
(erlang-menu-add-below 'my-erlang-menu-items
- 'erlang-menu-base-items
+ 'erlang-menu-base-items
erlang-menu-items))"
(if (memq entry items)
- items ; Return the original menu.
+ items ; Return the original menu.
(let ((head '())
- (done nil)
- res)
+ (done nil)
+ res)
(while (not done)
- (cond ((null items)
- (setq res (append head (list entry)))
- (setq done t))
- ((eq below (car items))
- (setq res
- (if above-p
- (append head (cons entry items))
- (append head (cons (car items)
- (cons entry (cdr items))))))
- (setq done t))
- (t
- (setq head (append head (list (car items))))
- (setq items (cdr items)))))
+ (cond ((null items)
+ (setq res (append head (list entry)))
+ (setq done t))
+ ((eq below (car items))
+ (setq res
+ (if above-p
+ (append head (cons entry items))
+ (append head (cons (car items)
+ (cons entry (cdr items))))))
+ (setq done t))
+ (t
+ (setq head (append head (list (car items))))
+ (setq items (cdr items)))))
res)))
(defun erlang-menu-delete (entry items)
@@ -1954,16 +1962,16 @@ the location of the manual pages."
(if erlang-man-inhibit
()
(setq erlang-menu-man-items
- '(nil
- ("Man - Function" erlang-man-function)))
+ '(nil
+ ("Man - Function" erlang-man-function)))
(if erlang-man-dirs
- (setq erlang-menu-man-items
- (append erlang-menu-man-items
- (erlang-man-make-top-menu erlang-man-dirs))))
+ (setq erlang-menu-man-items
+ (append erlang-menu-man-items
+ (erlang-man-make-top-menu erlang-man-dirs))))
(setq erlang-menu-items
- (erlang-menu-add-above 'erlang-menu-man-items
- 'erlang-menu-version-items
- erlang-menu-items))
+ (erlang-menu-add-above 'erlang-menu-man-items
+ 'erlang-menu-version-items
+ erlang-menu-items))
(erlang-menu-init)))
@@ -1971,7 +1979,7 @@ the location of the manual pages."
"Remove the man pages from the Erlang mode."
(interactive)
(setq erlang-menu-items
- (erlang-menu-delete 'erlang-menu-man-items erlang-menu-items))
+ (erlang-menu-delete 'erlang-menu-man-items erlang-menu-items))
(erlang-menu-init))
@@ -1985,28 +1993,28 @@ the location of the manual pages."
"Create one menu entry per element of DIR-LIST.
The format is described in the documentation of `erlang-man-dirs'."
(let ((menu '())
- dir)
+ dir)
(while dir-list
(setq dir (cond ((nth 2 (car dir-list))
- ;; Relative to `erlang-root-dir'.
- (and (stringp erlang-root-dir)
- (concat erlang-root-dir (nth 1 (car dir-list)))))
- (t
- ;; Absolute
- (nth 1 (car dir-list)))))
+ ;; Relative to `erlang-root-dir'.
+ (and (stringp erlang-root-dir)
+ (concat erlang-root-dir (nth 1 (car dir-list)))))
+ (t
+ ;; Absolute
+ (nth 1 (car dir-list)))))
(if (and dir
- (file-readable-p dir))
- (setq menu (cons (list (car (car dir-list))
- (erlang-man-make-middle-menu
- (erlang-man-get-files dir)))
- menu)))
+ (file-readable-p dir))
+ (setq menu (cons (list (car (car dir-list))
+ (erlang-man-make-middle-menu
+ (erlang-man-get-files dir)))
+ menu)))
(setq dir-list (cdr dir-list)))
;; Should no menus be found, generate a menu item which
;; will display a help text, when selected.
(if menu
- (nreverse menu)
+ (nreverse menu)
'(("Man Pages"
- (("Error! Why?" erlang-man-describe-error)))))))
+ (("Error! Why?" erlang-man-describe-error)))))))
;; Should the menu be to long, let's split it into a number of
@@ -2020,32 +2028,32 @@ menus is created."
(if (<= (length filelist) erlang-man-max-menu-size)
(erlang-man-make-menu filelist)
(let ((menu '())
- (filelist (copy-sequence filelist))
- segment submenu pair)
+ (filelist (copy-sequence filelist))
+ segment submenu pair)
(while filelist
- (setq pair (nthcdr (- erlang-man-max-menu-size 1) filelist))
- (setq segment filelist)
- (if (null pair)
- (setq filelist nil)
- (setq filelist (cdr pair))
- (setcdr pair nil))
- (setq submenu (erlang-man-make-menu segment))
- (setq menu (cons (list (concat (car (car submenu))
- " -- "
- (car (car (reverse submenu))))
- submenu)
- menu)))
+ (setq pair (nthcdr (- erlang-man-max-menu-size 1) filelist))
+ (setq segment filelist)
+ (if (null pair)
+ (setq filelist nil)
+ (setq filelist (cdr pair))
+ (setcdr pair nil))
+ (setq submenu (erlang-man-make-menu segment))
+ (setq menu (cons (list (concat (car (car submenu))
+ " -- "
+ (car (car (reverse submenu))))
+ submenu)
+ menu)))
(nreverse menu))))
(defun erlang-man-make-menu (filelist)
"Make a leaf menu based on FILELIST."
(let ((menu '())
- item)
+ item)
(while filelist
(setq item (erlang-man-make-menu-item (car filelist)))
(if item
- (setq menu (cons item menu)))
+ (setq menu (cons item menu)))
(setq filelist (cdr filelist)))
(nreverse menu)))
@@ -2054,11 +2062,11 @@ menus is created."
"Create a menu item containing the name of the man page."
(and (string-match ".+/\\([^/]+\\)\\.\\([124-9]\\|3\\(erl\\)?\\)\\(\\.gz\\)?$" file)
(let ((page (substring file (match-beginning 1) (match-end 1))))
- (list (capitalize page)
- (list 'lambda '()
- '(interactive)
- (list 'funcall 'erlang-man-display-function
- file))))))
+ (list (capitalize page)
+ (list 'lambda '()
+ '(interactive)
+ (list 'funcall 'erlang-man-display-function
+ file))))))
(defun erlang-man-get-files (dir)
@@ -2071,33 +2079,33 @@ menus is created."
This function is aware of imported functions."
(interactive
(list (let* ((mod (car-safe (erlang-get-function-under-point)))
- (input (read-string
- (format "Manual entry for module%s: "
- (if (or (null mod) (string= mod ""))
- ""
- (format " (default %s)" mod))))))
- (if (string= input "")
- mod
- input))))
+ (input (read-string
+ (format "Manual entry for module%s: "
+ (if (or (null mod) (string= mod ""))
+ ""
+ (format " (default %s)" mod))))))
+ (if (string= input "")
+ mod
+ input))))
(or module (setq module (car (erlang-get-function-under-point))))
(if (or (null module) (string= module ""))
(error "No Erlang module name given"))
(let ((dir-list erlang-man-dirs)
- (pat (concat "/" (regexp-quote module) "\\.\\([124-9]\\|3\\(erl\\)?\\)\\(\\.gz\\)?$"))
- (file nil)
- file-list)
+ (pat (concat "/" (regexp-quote module) "\\.\\([124-9]\\|3\\(erl\\)?\\)\\(\\.gz\\)?$"))
+ (file nil)
+ file-list)
(while (and dir-list (null file))
(setq file-list (erlang-man-get-files
- (if (nth 2 (car dir-list))
- (concat erlang-root-dir (nth 1 (car dir-list)))
- (nth 1 (car dir-list)))))
+ (if (nth 2 (car dir-list))
+ (concat erlang-root-dir (nth 1 (car dir-list)))
+ (nth 1 (car dir-list)))))
(while (and file-list (null file))
- (if (string-match pat (car file-list))
- (setq file (car file-list)))
- (setq file-list (cdr file-list)))
+ (if (string-match pat (car file-list))
+ (setq file (car file-list)))
+ (setq file-list (cdr file-list)))
(setq dir-list (cdr dir-list)))
(if file
- (funcall erlang-man-display-function file)
+ (funcall erlang-man-display-function file)
(error "No manual page for module %s found" module))))
@@ -2119,55 +2127,55 @@ The entry for `function' is displayed.
This function is aware of imported functions."
(interactive
(list (let* ((mod-func (erlang-get-function-under-point))
- (mod (car-safe mod-func))
- (func (nth 1 mod-func))
- (input (read-string
- (format
- "Manual entry for `module:func' or `module'%s: "
- (if (or (null mod) (string= mod ""))
- ""
- (format " (default %s:%s)" mod func))))))
- (if (string= input "")
- (if (and mod func)
- (concat mod ":" func)
- mod)
- input))))
+ (mod (car-safe mod-func))
+ (func (nth 1 mod-func))
+ (input (read-string
+ (format
+ "Manual entry for `module:func' or `module'%s: "
+ (if (or (null mod) (string= mod ""))
+ ""
+ (format " (default %s:%s)" mod func))))))
+ (if (string= input "")
+ (if (and mod func)
+ (concat mod ":" func)
+ mod)
+ input))))
;; Emacs 18 doesn't provide `man'...
(condition-case nil
(require 'man)
(error nil))
(let ((modname nil)
- (funcname nil))
+ (funcname nil))
(cond ((null name)
- (let ((mod-func (erlang-get-function-under-point)))
- (setq modname (car-safe mod-func))
- (setq funcname (nth 1 mod-func))))
- ((string-match ":" name)
- (setq modname (substring name 0 (match-beginning 0)))
- (setq funcname (substring name (match-end 0) nil)))
- ((stringp name)
- (setq modname name)))
+ (let ((mod-func (erlang-get-function-under-point)))
+ (setq modname (car-safe mod-func))
+ (setq funcname (nth 1 mod-func))))
+ ((string-match ":" name)
+ (setq modname (substring name 0 (match-beginning 0)))
+ (setq funcname (substring name (match-end 0) nil)))
+ ((stringp name)
+ (setq modname name)))
(if (or (null modname) (string= modname ""))
- (error "No Erlang module name given"))
+ (error "No Erlang module name given"))
(cond ((fboundp 'Man-notify-when-ready)
- ;; Emacs 19: The man command could possibly start an
- ;; asynchronous process, i.e. we must hook ourselves into
- ;; the system to be activated when the man-process
- ;; terminates.
- (if (null funcname)
- ()
- (erlang-man-patch-notify)
- (setq erlang-man-function-name funcname))
- (condition-case nil
- (erlang-man-module modname)
- (error (setq erlang-man-function-name nil))))
- (t
- (erlang-man-module modname)
- (if funcname
- (erlang-man-find-function
- (or (get-buffer "*Manual Entry*") ; Emacs 18
- (current-buffer)) ; XEmacs
- funcname))))))
+ ;; Emacs 19: The man command could possibly start an
+ ;; asynchronous process, i.e. we must hook ourselves into
+ ;; the system to be activated when the man-process
+ ;; terminates.
+ (if (null funcname)
+ ()
+ (erlang-man-patch-notify)
+ (setq erlang-man-function-name funcname))
+ (condition-case nil
+ (erlang-man-module modname)
+ (error (setq erlang-man-function-name nil))))
+ (t
+ (erlang-man-module modname)
+ (if funcname
+ (erlang-man-find-function
+ (or (get-buffer "*Manual Entry*") ; Emacs 18
+ (current-buffer)) ; XEmacs
+ funcname))))))
;; Should the defadvice be at the top level, the package `advice' would
@@ -2185,14 +2193,14 @@ command is executed asynchronously."
;; This should never happened since this is only called when
;; running under Emacs 19.
(error (error (concat "This command needs the package `advice', "
- "please upgrade your Emacs."))))
+ "please upgrade your Emacs."))))
(require 'man)
(defadvice Man-notify-when-ready
- (after erlang-Man-notify-when-ready activate)
+ (after erlang-Man-notify-when-ready activate)
"Set point at the documentation of the function name in
`erlang-man-function-name' when the man page is displayed."
(if erlang-man-function-name
- (erlang-man-find-function (ad-get-arg 0) erlang-man-function-name))
+ (erlang-man-find-function (ad-get-arg 0) erlang-man-function-name))
(setq erlang-man-function-name nil)))
@@ -2200,17 +2208,17 @@ command is executed asynchronously."
"Find manual page for function in `erlang-man-function-name' in buffer BUF."
(if func
(let ((win (get-buffer-window buf)))
- (if win
- (progn
- (set-buffer buf)
- (goto-char (point-min))
- (if (re-search-forward
- (concat "^[ \t]+" func " ?(")
- (point-max) t)
- (progn
- (forward-word -1)
- (set-window-point win (point)))
- (message "Could not find function `%s'" func)))))))
+ (if win
+ (progn
+ (set-buffer buf)
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "^[ \t]+" func " ?(")
+ (point-max) t)
+ (progn
+ (forward-word -1)
+ (set-window-point win (point)))
+ (message "Could not find function `%s'" func)))))))
(defun erlang-man-display (file)
@@ -2224,25 +2232,25 @@ to be used."
(error nil))
(if file
(let ((process-environment (copy-sequence process-environment)))
- (if (string-match "\\(.*\\)/man[^/]*/\\([^.]+\\)\\.\\([124-9]\\|3\\(erl\\)?\\)\\(\\.gz\\)?$" file)
- (let ((dir (substring file (match-beginning 1) (match-end 1)))
- (page (substring file (match-beginning 2) (match-end 2))))
- (if (fboundp 'setenv)
- (setenv "MANPATH" dir)
- ;; Emacs 18
- (setq process-environment (cons (concat "MANPATH=" dir)
- process-environment)))
- (cond ((not (and (not erlang-xemacs-p)
- (= erlang-emacs-major-version 19)
- (< erlang-emacs-minor-version 29)))
- (manual-entry page))
- (t
- ;; Emacs 19.28 and earlier versions of 19:
- ;; The manual-entry command unconditionally prompts
- ;; the user :-(
- (funcall (symbol-function 'Man-getpage-in-background)
- page))))
- (error "Can't find man page for %s\n" file)))))
+ (if (string-match "\\(.*\\)/man[^/]*/\\([^.]+\\)\\.\\([124-9]\\|3\\(erl\\)?\\)\\(\\.gz\\)?$" file)
+ (let ((dir (substring file (match-beginning 1) (match-end 1)))
+ (page (substring file (match-beginning 2) (match-end 2))))
+ (if (fboundp 'setenv)
+ (setenv "MANPATH" dir)
+ ;; Emacs 18
+ (setq process-environment (cons (concat "MANPATH=" dir)
+ process-environment)))
+ (cond ((not (and (not erlang-xemacs-p)
+ (= erlang-emacs-major-version 19)
+ (< erlang-emacs-minor-version 29)))
+ (manual-entry page))
+ (t
+ ;; Emacs 19.28 and earlier versions of 19:
+ ;; The manual-entry command unconditionally prompts
+ ;; the user :-(
+ (funcall (symbol-function 'Man-getpage-in-background)
+ page))))
+ (error "Can't find man page for %s\n" file)))))
(defun erlang-man-describe-error ()
@@ -2285,43 +2293,43 @@ package not be present, this function does nothing."
(error t))
(if (featurep 'tempo)
(let ((skel erlang-skel)
- (menu '()))
- (while skel
- (cond ((null (car skel))
- (setq menu (cons nil menu)))
- (t
- (funcall (symbol-function 'tempo-define-template)
- (concat "erlang-" (nth 1 (car skel)))
- ;; The tempo template used contains an `include'
- ;; function call only, hence changes to the
- ;; variables describing the templates take effect
- ;; immdiately.
- (list (list 'erlang-skel-include (nth 2 (car skel))))
- (nth 1 (car skel))
- (car (car skel))
- 'erlang-tempo-tags)
- (setq menu (cons (erlang-skel-make-menu-item
- (car skel)) menu))))
- (setq skel (cdr skel)))
- (setq erlang-menu-skel-items
- (list nil (list "Skeletons" (nreverse menu))))
- (setq erlang-menu-items
- (erlang-menu-add-above 'erlang-menu-skel-items
- 'erlang-menu-version-items
- erlang-menu-items))
- (erlang-menu-init))))
+ (menu '()))
+ (while skel
+ (cond ((null (car skel))
+ (setq menu (cons nil menu)))
+ (t
+ (funcall (symbol-function 'tempo-define-template)
+ (concat "erlang-" (nth 1 (car skel)))
+ ;; The tempo template used contains an `include'
+ ;; function call only, hence changes to the
+ ;; variables describing the templates take effect
+ ;; immdiately.
+ (list (list 'erlang-skel-include (nth 2 (car skel))))
+ (nth 1 (car skel))
+ (car (car skel))
+ 'erlang-tempo-tags)
+ (setq menu (cons (erlang-skel-make-menu-item
+ (car skel)) menu))))
+ (setq skel (cdr skel)))
+ (setq erlang-menu-skel-items
+ (list nil (list "Skeletons" (nreverse menu))))
+ (setq erlang-menu-items
+ (erlang-menu-add-above 'erlang-menu-skel-items
+ 'erlang-menu-version-items
+ erlang-menu-items))
+ (erlang-menu-init))))
(defun erlang-skel-make-menu-item (skel)
(let ((func (intern (concat "tempo-template-erlang-" (nth 1 skel)))))
(cond ((null (nth 3 skel))
- (list (car skel) func))
- (t
- (list (car skel)
- (list 'lambda '()
- '(interactive)
- (list 'funcall
- (list 'quote (nth 3 skel))
- (list 'quote func))))))))
+ (list (car skel) func))
+ (t
+ (list (car skel)
+ (list 'lambda '()
+ '(interactive)
+ (list 'funcall
+ (list 'quote (nth 3 skel))
+ (list 'quote func))))))))
;; Functions designed to be added to the skeleton menu.
;; (Not normally used)
@@ -2354,12 +2362,12 @@ Technically, this function returns the `tempo' attribute`(l ...)' which
can contain other `tempo' attributes. Please see the function
`tempo-define-template' for a description of the `(l ...)' attribute."
(let ((res '())
- entry)
+ entry)
(while args
(setq entry (car args))
(while entry
- (setq res (cons (car entry) res))
- (setq entry (cdr entry)))
+ (setq res (cons (car entry) res))
+ (setq entry (cdr entry)))
(setq args (cdr args)))
(cons 'l (nreverse res))))
@@ -2368,25 +2376,25 @@ can contain other `tempo' attributes. Please see the function
(defun erlang-skel-separator (&optional percent)
"Return a comment separator."
(let ((percent (or percent 3)))
- (concat (make-string percent ?%)
- (make-string (- erlang-skel-separator-length percent) ?-)
- "\n")))
+ (concat (make-string percent ?%)
+ (make-string (- erlang-skel-separator-length percent) ?-)
+ "\n")))
(defun erlang-skel-double-separator (&optional percent)
"Return a comment separator."
(let ((percent (or percent 3)))
- (concat (make-string percent ?%)
- (make-string (- erlang-skel-separator-length percent) ?=)
- "\n")))
+ (concat (make-string percent ?%)
+ (make-string (- erlang-skel-separator-length percent) ?=)
+ "\n")))
(defun erlang-skel-dd-mmm-yyyy ()
"Return the current date as a string in \"DD Mon YYYY\" form.
The first character of DD is space if the value is less than 10."
(let ((date (current-time-string)))
(format "%2d %s %s"
- (erlang-string-to-int (substring date 8 10))
- (substring date 4 7)
- (substring date -4))))
+ (erlang-string-to-int (substring date 8 10))
+ (substring date 4 7)
+ (substring date -4))))
;; Indentation code:
@@ -2399,23 +2407,23 @@ rigidly along with this one."
;; If arg, always indent this line as Erlang
;; and shift remaining lines of clause the same amount.
(let ((shift-amt (erlang-indent-line))
- beg end)
- (save-excursion
- (if erlang-tab-always-indent
- (beginning-of-line))
- (setq beg (point))
- (erlang-end-of-clause 1)
- (setq end (point))
- (goto-char beg)
- (forward-line 1)
- (setq beg (point)))
- (if (> end beg)
- (indent-code-rigidly beg end shift-amt "\n")))
+ beg end)
+ (save-excursion
+ (if erlang-tab-always-indent
+ (beginning-of-line))
+ (setq beg (point))
+ (erlang-end-of-clause 1)
+ (setq end (point))
+ (goto-char beg)
+ (forward-line 1)
+ (setq beg (point)))
+ (if (> end beg)
+ (indent-code-rigidly beg end shift-amt "\n")))
(if (and (not erlang-tab-always-indent)
- (save-excursion
- (skip-chars-backward " \t")
- (not (bolp))))
- (insert-tab)
+ (save-excursion
+ (skip-chars-backward " \t")
+ (not (bolp))))
+ (insert-tab)
(erlang-indent-line))))
@@ -2423,33 +2431,34 @@ rigidly along with this one."
"Indent current line as Erlang code.
Return the amount the indentation changed by."
(let ((pos (- (point-max) (point)))
- indent beg
- shift-amt)
+ indent beg
+ shift-amt)
(beginning-of-line 1)
(setq beg (point))
(skip-chars-forward " \t")
(cond ((looking-at "%")
- (setq indent (funcall comment-indent-function))
- (setq shift-amt (- indent (current-column))))
- (t
- (setq indent (erlang-calculate-indent))
- (cond ((null indent)
- (setq indent (current-indentation)))
- ((eq indent t)
- ;; This should never occur here.
- (error "Erlang mode error"))
- ;;((= (char-syntax (following-char)) ?\))
- ;; (setq indent (1- indent)))
- )
- (setq shift-amt (- indent (current-column)))))
+ (setq indent (funcall comment-indent-function))
+ (setq shift-amt (- indent (current-column))))
+ (t
+ (setq indent (erlang-calculate-indent))
+ (cond ((null indent)
+ (setq indent (current-indentation)))
+ ((eq indent t)
+ ;; This should never occur here.
+ (error "Erlang mode error"))
+ ;;((= (char-syntax (following-char)) ?\))
+ ;; (setq indent (1- indent)))
+ )
+ (setq shift-amt (- indent (current-column)))))
(if (zerop shift-amt)
- nil
+ nil
(delete-region beg (point))
(indent-to indent))
;; If initial point was within line's indentation, position
;; after the indentation. Else stay at same point in text.
(if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos)))
+ (goto-char (- (point-max) pos)))
+ (run-hooks 'erlang-indent-line-hook)
shift-amt))
@@ -2460,11 +2469,11 @@ This is automagically called by the user level function `indent-region'."
(interactive "r")
(save-excursion
(let ((case-fold-search nil)
- (continue t)
- (from-end (- (point-max) end))
- indent-point;; The beginning of the current line
- indent;; The indent amount
- state)
+ (continue t)
+ (from-end (- (point-max) end))
+ indent-point;; The beginning of the current line
+ indent;; The indent amount
+ state)
(goto-char beg)
(beginning-of-line)
(setq indent-point (point))
@@ -2478,39 +2487,39 @@ This is automagically called by the user level function `indent-region'."
(error "Illegal syntax"))))
;; Indent every line in the region
(while continue
- (goto-char indent-point)
- (skip-chars-forward " \t")
- (cond ((looking-at "%")
- ;; Do not use our stack to help the user to customize
- ;; comment indentation.
- (setq indent (funcall comment-indent-function)))
- ((looking-at "$")
- ;; Don't indent empty lines.
- (setq indent 0))
- (t
- (setq indent
- (save-excursion
- (erlang-calculate-stack-indent (point) state)))
- (cond ((null indent)
- (setq indent (current-indentation)))
- ((eq indent t)
- ;; This should never occur here.
- (error "Erlang mode error"))
- ;;((= (char-syntax (following-char)) ?\))
- ;; (setq indent (1- indent)))
- )))
- (if (zerop (- indent (current-column)))
- nil
- (delete-region indent-point (point))
- (indent-to indent))
- ;; Find the next line in the region
- (goto-char indent-point)
- (save-excursion
- (forward-line 1)
- (setq indent-point (point)))
- (if (>= from-end (- (point-max) indent-point))
- (setq continue nil)
- (while (< (point) indent-point)
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond ((looking-at "%")
+ ;; Do not use our stack to help the user to customize
+ ;; comment indentation.
+ (setq indent (funcall comment-indent-function)))
+ ((looking-at "$")
+ ;; Don't indent empty lines.
+ (setq indent 0))
+ (t
+ (setq indent
+ (save-excursion
+ (erlang-calculate-stack-indent (point) state)))
+ (cond ((null indent)
+ (setq indent (current-indentation)))
+ ((eq indent t)
+ ;; This should never occur here.
+ (error "Erlang mode error"))
+ ;;((= (char-syntax (following-char)) ?\))
+ ;; (setq indent (1- indent)))
+ )))
+ (if (zerop (- indent (current-column)))
+ nil
+ (delete-region indent-point (point))
+ (indent-to indent))
+ ;; Find the next line in the region
+ (goto-char indent-point)
+ (save-excursion
+ (forward-line 1)
+ (setq indent-point (point)))
+ (if (>= from-end (- (point-max) indent-point))
+ (setq continue nil)
+ (while (< (point) indent-point)
(let ((pt (point)))
(setq state (erlang-partial-parse
pt indent-point state))
@@ -2532,7 +2541,7 @@ This is automagically called by the user level function `indent-region'."
(interactive)
(save-excursion
(let ((end (progn (erlang-end-of-function 1) (point)))
- (beg (progn (erlang-beginning-of-function 1) (point))))
+ (beg (progn (erlang-beginning-of-function 1) (point))))
(erlang-indent-region beg end))))
@@ -2541,7 +2550,7 @@ This is automagically called by the user level function `indent-region'."
(interactive)
(save-excursion
(let ((end (progn (erlang-end-of-clause 1) (point)))
- (beg (progn (erlang-beginning-of-clause 1) (point))))
+ (beg (progn (erlang-beginning-of-clause 1) (point))))
(erlang-indent-region beg end))))
@@ -2556,11 +2565,11 @@ This is automagically called by the user level function `indent-region'."
Return nil if line starts inside string, t if in a comment."
(save-excursion
(let ((indent-point (point))
- (case-fold-search nil)
- (state nil))
+ (case-fold-search nil)
+ (state nil))
(if parse-start
- (goto-char parse-start)
- (erlang-beginning-of-clause))
+ (goto-char parse-start)
+ (erlang-beginning-of-clause))
(while (< (point) indent-point)
(let ((pt (point)))
(setq state (erlang-partial-parse pt indent-point state))
@@ -2575,25 +2584,25 @@ Return nil if line starts inside string, t if in a comment."
(save-excursion
(let ((starting-point (point))
- (case-fold-search nil)
- (state nil))
+ (case-fold-search nil)
+ (state nil))
(erlang-beginning-of-clause)
(while (< (point) starting-point)
- (setq state (erlang-partial-parse (point) starting-point state)))
+ (setq state (erlang-partial-parse (point) starting-point state)))
(message "%S" state))))
(defun erlang-partial-parse (from to &optional state)
"Parse Erlang syntax starting at FROM until TO, with an optional STATE.
Value is list (stack token-start token-type in-what)."
- (goto-char from) ; Start at the beginning
+ (goto-char from) ; Start at the beginning
(erlang-skip-blank to)
(let ((cs (char-syntax (following-char)))
- (stack (car state))
- (token (point))
- in-what)
- (cond
-
+ (stack (car state))
+ (token (point))
+ in-what)
+ (cond
+
;; Done: Return previous state.
((>= token to)
(setq token (nth 1 state))
@@ -2603,230 +2612,230 @@ Value is list (stack token-start token-type in-what)."
;; Word constituent: check and handle keywords.
((= cs ?w)
(cond ((looking-at "\\(end\\|after\\)[^_a-zA-Z0-9]")
- ;; Must pop top icr layer, `after' will push a new
- ;; layer next.
- (progn
- (while (and stack (eq (car (car stack)) '->))
- (erlang-pop stack))
- (if (and stack (memq (car (car stack)) '(icr begin fun try)))
- (erlang-pop stack))))
- ((looking-at "catch\\b.*of")
- t)
- ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
- ;; Must pop top icr layer, `catch' in try/catch
- ;;will push a new layer next.
- (progn
- (while (and stack (eq (car (car stack)) '->))
- (erlang-pop stack))
- (if (and stack (memq (car (car stack)) '(icr begin try)))
- (erlang-pop stack))))
- )
+ ;; Must pop top icr layer, `after' will push a new
+ ;; layer next.
+ (progn
+ (while (and stack (eq (car (car stack)) '->))
+ (erlang-pop stack))
+ (if (and stack (memq (car (car stack)) '(icr begin fun try)))
+ (erlang-pop stack))))
+ ((looking-at "catch\\b.*of")
+ t)
+ ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
+ ;; Must pop top icr layer, `catch' in try/catch
+ ;;will push a new layer next.
+ (progn
+ (while (and stack (eq (car (car stack)) '->))
+ (erlang-pop stack))
+ (if (and stack (memq (car (car stack)) '(icr begin try)))
+ (erlang-pop stack))))
+ )
(cond ((looking-at "\\(if\\|case\\|receive\\)[^_a-zA-Z0-9]")
- ;; Must push a new icr (if/case/receive) layer.
- (erlang-push (list 'icr token (current-column)) stack))
- ((looking-at "\\(try\\|after\\)[^_a-zA-Z0-9]")
- ;; Must handle separately, try catch or try X of -> catch
- ;; same for `after', it could be
- ;; receive after Time -> X end, or
- ;; try after X end
- (erlang-push (list 'try token (current-column)) stack))
- ((looking-at "\\(of\\)[^_a-zA-Z0-9]")
- ;; Must handle separately, try X of -> catch
- (if (and stack (eq (car (car stack)) 'try))
- (let ((try-column (nth 2 (car stack)))
- (try-pos (nth 1 (car stack))))
- (erlang-pop stack)
- (erlang-push (list 'icr try-pos try-column) stack))))
-
- ((looking-at "\\(fun\\)[^_a-zA-Z0-9]")
- ;; Push a new layer if we are defining a `fun'
- ;; expression, not when we are refering an existing
- ;; function. 'fun's defines are only indented one level now.
- (if (save-excursion
- (goto-char (match-end 1))
- (erlang-skip-blank to)
- ;; Use erlang-variable-regexp here to look for an
- ;; optional variable name to match EEP37 named funs.
- (if (looking-at erlang-variable-regexp)
- (progn
- (goto-char (match-end 0))
- (erlang-skip-blank to)))
- (eq (following-char) ?\())
- (erlang-push (list 'fun token (current-column)) stack)))
- ((looking-at "\\(begin\\)[^_a-zA-Z0-9]")
- (erlang-push (list 'begin token (current-column)) stack))
- ;; Normal when case
- ;;((looking-at "when\\s ")
- ;;((looking-at "when\\s *\\($\\|%\\)")
- ((looking-at "when[^_a-zA-Z0-9]")
- (erlang-push (list 'when token (current-column)) stack))
- ((looking-at "catch\\b.*of")
- t)
- ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
- (erlang-push (list 'icr token (current-column)) stack))
- ;;(erlang-push (list '-> token (current-column)) stack))
- ;;((looking-at "^of$")
- ;; (erlang-push (list 'icr token (current-column)) stack)
- ;;(erlang-push (list '-> token (current-column)) stack))
- )
+ ;; Must push a new icr (if/case/receive) layer.
+ (erlang-push (list 'icr token (current-column)) stack))
+ ((looking-at "\\(try\\|after\\)[^_a-zA-Z0-9]")
+ ;; Must handle separately, try catch or try X of -> catch
+ ;; same for `after', it could be
+ ;; receive after Time -> X end, or
+ ;; try after X end
+ (erlang-push (list 'try token (current-column)) stack))
+ ((looking-at "\\(of\\)[^_a-zA-Z0-9]")
+ ;; Must handle separately, try X of -> catch
+ (if (and stack (eq (car (car stack)) 'try))
+ (let ((try-column (nth 2 (car stack)))
+ (try-pos (nth 1 (car stack))))
+ (erlang-pop stack)
+ (erlang-push (list 'icr try-pos try-column) stack))))
+
+ ((looking-at "\\(fun\\)[^_a-zA-Z0-9]")
+ ;; Push a new layer if we are defining a `fun'
+ ;; expression, not when we are refering an existing
+ ;; function. 'fun's defines are only indented one level now.
+ (if (save-excursion
+ (goto-char (match-end 1))
+ (erlang-skip-blank to)
+ ;; Use erlang-variable-regexp here to look for an
+ ;; optional variable name to match EEP37 named funs.
+ (if (looking-at erlang-variable-regexp)
+ (progn
+ (goto-char (match-end 0))
+ (erlang-skip-blank to)))
+ (eq (following-char) ?\())
+ (erlang-push (list 'fun token (current-column)) stack)))
+ ((looking-at "\\(begin\\)[^_a-zA-Z0-9]")
+ (erlang-push (list 'begin token (current-column)) stack))
+ ;; Normal when case
+ ;;((looking-at "when\\s ")
+ ;;((looking-at "when\\s *\\($\\|%\\)")
+ ((looking-at "when[^_a-zA-Z0-9]")
+ (erlang-push (list 'when token (current-column)) stack))
+ ((looking-at "catch\\b.*of")
+ t)
+ ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
+ (erlang-push (list 'icr token (current-column)) stack))
+ ;;(erlang-push (list '-> token (current-column)) stack))
+ ;;((looking-at "^of$")
+ ;; (erlang-push (list 'icr token (current-column)) stack)
+ ;;(erlang-push (list '-> token (current-column)) stack))
+ )
(forward-sexp 1))
- ;; String: Try to skip over it. (Catch error if not complete.)
- ((= cs ?\")
- (condition-case nil
- (progn
- (forward-sexp 1)
- (if (> (point) to)
- (progn
- (setq in-what 'string)
- (goto-char to))))
- (error
- (setq in-what 'string)
- (goto-char to))))
+ ;; String: Try to skip over it. (Catch error if not complete.)
+ ((= cs ?\")
+ (condition-case nil
+ (progn
+ (forward-sexp 1)
+ (if (> (point) to)
+ (progn
+ (setq in-what 'string)
+ (goto-char to))))
+ (error
+ (setq in-what 'string)
+ (goto-char to))))
;; Expression prefix e.i. $ or ^ (Note ^ can be in the character
;; literal $^ or part of string and $ outside of a string denotes
;; a character literal)
((= cs ?')
- (cond
+ (cond
((= (following-char) ?\") ;; $ or ^ was the last char in a string
- (forward-char 1))
+ (forward-char 1))
(t
- ;; Maybe a character literal, quote the next char to avoid
- ;; situations as $" being seen as the begining of a string.
- ;; Note the quoting something in the middle of a string is harmless.
- (quote (following-char))
- (forward-char 1))))
+ ;; Maybe a character literal, quote the next char to avoid
+ ;; situations as $" being seen as the begining of a string.
+ ;; Note the quoting something in the middle of a string is harmless.
+ (quote (following-char))
+ (forward-char 1))))
;; Symbol constituent or punctuation
-
+
((memq cs '(?. ?_))
- (cond
-
+ (cond
+
;; Clause end
((= (following-char) ?\;)
- (if (eq (car (car (last stack))) 'spec)
- (while (memq (car (car stack)) '(when ::))
- (erlang-pop stack)))
- (if (and stack (eq (car (car stack)) '->))
- (erlang-pop stack))
- (forward-char 1))
-
+ (if (eq (car (car (last stack))) 'spec)
+ (while (memq (car (car stack)) '(when ::))
+ (erlang-pop stack)))
+ (if (and stack (eq (car (car stack)) '->))
+ (erlang-pop stack))
+ (forward-char 1))
+
;; Parameter separator
((looking-at ",")
- (forward-char 1)
- (if (and stack (eq (car (car stack)) '::))
- ;; Type or spec
- (erlang-pop stack)))
+ (forward-char 1)
+ (if (and stack (eq (car (car stack)) '::))
+ ;; Type or spec
+ (erlang-pop stack)))
;; Function end
((looking-at "\\.\\(\\s \\|\n\\|\\s<\\)")
- (setq stack nil)
- (forward-char 1))
-
+ (setq stack nil)
+ (forward-char 1))
+
;; Function head
((looking-at "->")
- (if (and stack (eq (car (car stack)) 'when))
- (erlang-pop stack))
- (erlang-push (list '-> token (current-column)) stack)
- (forward-char 2))
-
+ (if (and stack (eq (car (car stack)) 'when))
+ (erlang-pop stack))
+ (erlang-push (list '-> token (current-column)) stack)
+ (forward-char 2))
+
;; List-comprehension divider
((looking-at "||")
- (erlang-push (list '|| token (current-column)) stack)
- (forward-char 2))
+ (erlang-push (list '|| token (current-column)) stack)
+ (forward-char 2))
;; Bit-syntax open. Note that map syntax allows "<<" to follow ":="
;; or "=>" without intervening whitespace, so handle that case here
((looking-at "\\(:=\\|=>\\)?<<")
- (erlang-push (list '<< token (current-column)) stack)
- (forward-char (- (match-end 0) (match-beginning 0))))
-
+ (erlang-push (list '<< token (current-column)) stack)
+ (forward-char (- (match-end 0) (match-beginning 0))))
+
;; Bit-syntax close
((looking-at ">>")
- (while (memq (car (car stack)) '(|| ->))
- (erlang-pop stack))
- (cond ((eq (car (car stack)) '<<)
- (erlang-pop stack))
- ((memq (car (car stack)) '(icr begin fun))
- (error "Missing `end'"))
- (t
- (error "Unbalanced parentheses")))
- (forward-char 2))
-
+ (while (memq (car (car stack)) '(|| ->))
+ (erlang-pop stack))
+ (cond ((eq (car (car stack)) '<<)
+ (erlang-pop stack))
+ ((memq (car (car stack)) '(icr begin fun))
+ (error "Missing `end'"))
+ (t
+ (error "Unbalanced parentheses")))
+ (forward-char 2))
+
;; Macro
((= (following-char) ??)
- ;; Skip over the ?
- (forward-char 1)
- )
+ ;; Skip over the ?
+ (forward-char 1)
+ )
;; Type spec's
((looking-at "-type\\s \\|-opaque\\s ")
- (if stack
- (forward-char 1)
- (erlang-push (list 'icr token (current-column)) stack)
- (forward-char 6)))
+ (if stack
+ (forward-char 1)
+ (erlang-push (list 'icr token (current-column)) stack)
+ (forward-char 6)))
((looking-at "-spec\\s ")
- (if stack
- (forward-char 1)
- (forward-char 6)
- (skip-chars-forward "^(\n")
- (erlang-push (list 'spec (point) (current-column)) stack)
- ))
+ (if stack
+ (forward-char 1)
+ (forward-char 6)
+ (skip-chars-forward "^(\n")
+ (erlang-push (list 'spec (point) (current-column)) stack)
+ ))
;; Type spec delimiter
((looking-at "::")
- (erlang-push (list ':: token (current-column)) stack)
- (forward-char 2))
-
- ;; Don't follow through in the clause below
- ;; '|' don't need spaces around it
+ (erlang-push (list ':: token (current-column)) stack)
+ (forward-char 2))
+
+ ;; Don't follow through in the clause below
+ ;; '|' don't need spaces around it
((looking-at "|")
- (forward-char 1))
-
+ (forward-char 1))
+
;; Other punctuation: Skip over it and any following punctuation
((= cs ?.)
- ;; Skip over all characters in the operand.
- (skip-syntax-forward "."))
-
+ ;; Skip over all characters in the operand.
+ (skip-syntax-forward "."))
+
;; Other char: Skip over it.
(t
- (forward-char 1))))
-
+ (forward-char 1))))
+
;; Open parenthesis
((= cs ?\()
(erlang-push (list '\( token (current-column)) stack)
(forward-char 1))
-
+
;; Close parenthesis
((= cs ?\))
(while (memq (car (car stack)) '(|| -> :: when))
- (erlang-pop stack))
+ (erlang-pop stack))
(cond ((eq (car (car stack)) '\()
- (erlang-pop stack)
- (if (and (eq (car (car stack)) 'fun)
- (or (eq (car (car (last stack))) 'spec)
- (eq (car (car (cdr stack))) '::))) ;; -type()
- ;; Inside fun type def ') closes fun definition
- (erlang-pop stack)))
- ((eq (car (car stack)) 'icr)
- (erlang-pop stack)
- ;; Normal catch not try-catch might have caused icr
- ;; and then incr should be removed and is not an error.
- (if (eq (car (car stack)) '\()
- (erlang-pop stack)
- (error "Missing `end'")
- ))
- ((eq (car (car stack)) 'begin)
- (error "Missing `end'"))
- (t
- (error "Unbalanced parenthesis"))
- )
- (forward-char 1))
-
+ (erlang-pop stack)
+ (if (and (eq (car (car stack)) 'fun)
+ (or (eq (car (car (last stack))) 'spec)
+ (eq (car (car (cdr stack))) '::))) ;; -type()
+ ;; Inside fun type def ') closes fun definition
+ (erlang-pop stack)))
+ ((eq (car (car stack)) 'icr)
+ (erlang-pop stack)
+ ;; Normal catch not try-catch might have caused icr
+ ;; and then incr should be removed and is not an error.
+ (if (eq (car (car stack)) '\()
+ (erlang-pop stack)
+ (error "Missing `end'")
+ ))
+ ((eq (car (car stack)) 'begin)
+ (error "Missing `end'"))
+ (t
+ (error "Unbalanced parenthesis"))
+ )
+ (forward-char 1))
+
;; Character quote: Skip it and the quoted char.
((= cs ?/)
(forward-char 2))
-
+
;; Character escape: Skip it and the escape sequence.
((= cs ?\\)
(forward-char 1)
@@ -2855,49 +2864,49 @@ Return nil if inside string, t if in a comment."
((eq (car stack-top) '\()
;; Element of list, tuple or part of an expression,
(cond ((null erlang-argument-indent)
- ;; indent to next column.
- (1+ (nth 2 stack-top)))
- ((= (char-syntax (following-char)) ?\))
- (goto-char (nth 1 stack-top))
- (cond ((looking-at "[({]\\s *\\($\\|%\\)")
- ;; Line ends with parenthesis.
- (let ((previous (erlang-indent-find-preceding-expr))
- (stack-pos (nth 2 stack-top)))
- (if (>= previous stack-pos) stack-pos
- (- (+ previous erlang-argument-indent) 1))))
- (t
- (nth 2 stack-top))))
- ((= (following-char) ?,)
- ;; a comma at the start of the line: line up with opening parenthesis.
- (nth 2 stack-top))
- (t
- (goto-char (nth 1 stack-top))
- (let ((base (cond ((looking-at "[({]\\s *\\($\\|%\\)")
- ;; Line ends with parenthesis.
- (erlang-indent-parenthesis (nth 2 stack-top)))
- (t
- ;; Indent to the same column as the first
- ;; argument.
- (goto-char (1+ (nth 1 stack-top)))
- (skip-chars-forward " \t")
- (current-column)))))
- (erlang-indent-standard indent-point token base 't)))))
- ;;
- ((eq (car stack-top) '<<)
- ;; Element of binary (possible comprehension) expression,
- (cond ((null erlang-argument-indent)
- ;; indent to next column.
- (+ 2 (nth 2 stack-top)))
- ((looking-at "\\(>>\\)[^_a-zA-Z0-9]")
- (nth 2 stack-top))
- (t
- (goto-char (nth 1 stack-top))
- ;; Indent to the same column as the first
- ;; argument.
- (goto-char (+ 2 (nth 1 stack-top)))
- (skip-chars-forward " \t")
- (current-column))))
-
+ ;; indent to next column.
+ (1+ (nth 2 stack-top)))
+ ((= (char-syntax (following-char)) ?\))
+ (goto-char (nth 1 stack-top))
+ (cond ((looking-at "[({]\\s *\\($\\|%\\)")
+ ;; Line ends with parenthesis.
+ (let ((previous (erlang-indent-find-preceding-expr))
+ (stack-pos (nth 2 stack-top)))
+ (if (>= previous stack-pos) stack-pos
+ (- (+ previous erlang-argument-indent) 1))))
+ (t
+ (nth 2 stack-top))))
+ ((= (following-char) ?,)
+ ;; a comma at the start of the line: line up with opening parenthesis.
+ (nth 2 stack-top))
+ (t
+ (goto-char (nth 1 stack-top))
+ (let ((base (cond ((looking-at "[({]\\s *\\($\\|%\\)")
+ ;; Line ends with parenthesis.
+ (erlang-indent-parenthesis (nth 2 stack-top)))
+ (t
+ ;; Indent to the same column as the first
+ ;; argument.
+ (goto-char (1+ (nth 1 stack-top)))
+ (skip-chars-forward " \t")
+ (current-column)))))
+ (erlang-indent-standard indent-point token base 't)))))
+ ;;
+ ((eq (car stack-top) '<<)
+ ;; Element of binary (possible comprehension) expression,
+ (cond ((null erlang-argument-indent)
+ ;; indent to next column.
+ (+ 2 (nth 2 stack-top)))
+ ((looking-at "\\(>>\\)[^_a-zA-Z0-9]")
+ (nth 2 stack-top))
+ (t
+ (goto-char (nth 1 stack-top))
+ ;; Indent to the same column as the first
+ ;; argument.
+ (goto-char (+ 2 (nth 1 stack-top)))
+ (skip-chars-forward " \t")
+ (current-column))))
+
((memq (car stack-top) '(icr fun spec))
;; The default indentation is the column of the option
;; directly following the keyword. (This does not apply to
@@ -2908,156 +2917,160 @@ Return nil if inside string, t if in a comment."
;; `after' should be indented to the same level as the
;; corresponding receive.
(cond ((looking-at "\\(after\\|of\\)\\($\\|[^_a-zA-Z0-9]\\)")
- (nth 2 stack-top))
- ((looking-at "when[^_a-zA-Z0-9]")
- ;; Handling one when part
- (+ (nth 2 stack-top) erlang-indent-level erlang-indent-guard))
- (t
- (save-excursion
- (goto-char (nth 1 stack-top))
- (if (looking-at "case[^_a-zA-Z0-9]")
- (+ (nth 2 stack-top) erlang-indent-level)
- (skip-chars-forward "a-z")
- (skip-chars-forward " \t")
- (if (memq (following-char) '(?% ?\n))
- (+ (nth 2 stack-top) erlang-indent-level)
- (current-column))))))
- )
- ((and (eq (car stack-top) '||) (looking-at "\\(]\\|>>\\)[^_a-zA-Z0-9]"))
- (nth 2 (car (cdr stack))))
+ (nth 2 stack-top))
+ ((looking-at "when[^_a-zA-Z0-9]")
+ ;; Handling one when part
+ (+ (nth 2 stack-top) erlang-indent-level erlang-indent-guard))
+ (t
+ (save-excursion
+ (goto-char (nth 1 stack-top))
+ (if (and erlang-icr-indent
+ (looking-at "\\(if\\|case\\|receive\\)[^_a-zA-Z0-9]"))
+ (+ (nth 2 stack-top) erlang-icr-indent)
+ (if (looking-at "\\(case\\|receive\\)[^_a-zA-Z0-9]")
+ (+ (nth 2 stack-top) erlang-indent-level)
+ (skip-chars-forward "a-z")
+ (skip-chars-forward " \t")
+ (if (memq (following-char) '(?% ?\n))
+ (+ (nth 2 stack-top) erlang-indent-level)
+ (current-column))))))))
+ ((and (eq (car stack-top) '||) (looking-at "\\(]\\|>>\\)[^_a-zA-Z0-9]"))
+ (nth 2 (car (cdr stack))))
;; Real indentation, where operators create extra indentation etc.
((memq (car stack-top) '(-> || try begin))
- (if (looking-at "\\(of\\)[^_a-zA-Z0-9]")
- (nth 2 stack-top)
- (goto-char (nth 1 stack-top))
- ;; Check if there is more code after the '->' on the
- ;; same line. If so use this indentation as base, else
- ;; use parent indentation + 2 * level as base.
- (let ((off erlang-indent-level)
- (skip 2))
- (cond ((null (cdr stack))) ; Top level in function.
- ((eq (car stack-top) 'begin)
- (setq skip 5))
- ((eq (car stack-top) 'try)
- (setq skip 5))
- ((eq (car stack-top) '->)
- ;; If in fun definition use standard indent level not double
- ;;(if (not (eq (car (car (cdr stack))) 'fun))
- ;; Removed it made multi clause fun's look to bad
- (setq off (* 2 erlang-indent-level)))) ;; )
- (let ((base (erlang-indent-find-base stack indent-point off skip)))
- ;; Special cases
- (goto-char indent-point)
- (cond ((looking-at "\\(end\\|after\\)\\($\\|[^_a-zA-Z0-9]\\)")
- (if (eq (car stack-top) '->)
- (erlang-pop stack))
- (if stack
- (erlang-caddr (car stack))
- 0))
- ((looking-at "catch\\b\\($\\|[^_a-zA-Z0-9]\\)")
- ;; Are we in a try
- (let ((start (if (eq (car stack-top) '->)
- (car (cdr stack))
- stack-top)))
- (if (null start) nil
- (goto-char (nth 1 start)))
- (cond ((looking-at "try\\($\\|[^_a-zA-Z0-9]\\)")
- (progn
- (if (eq (car stack-top) '->)
- (erlang-pop stack))
- (if stack
- (erlang-caddr (car stack))
- 0)))
- (t (erlang-indent-standard indent-point token base 'nil))))) ;; old catch
- (t
- (erlang-indent-standard indent-point token base 'nil)
- ))))
- ))
- ((eq (car stack-top) 'when)
- (goto-char (nth 1 stack-top))
- (if (looking-at "when\\s *\\($\\|%\\)")
- (progn
- (erlang-pop stack)
- (if (and stack (memq (nth 0 (car stack)) '(icr fun)))
- (progn
- (goto-char (nth 1 (car stack)))
- (+ (nth 2 (car stack)) erlang-indent-guard
- ;; receive XYZ or receive
- ;; XYZ
- ;; This if thing does not seem to be needed
- ;;(if (looking-at "[a-z]+\\s *\\($\\|%\\)")
- ;; erlang-indent-level
- ;; (* 2 erlang-indent-level))))
- (* 2 erlang-indent-level)))
- ;;erlang-indent-level))
- (+ erlang-indent-level erlang-indent-guard)))
+ (if (looking-at "\\(of\\)[^_a-zA-Z0-9]")
+ (nth 2 stack-top)
+ (goto-char (nth 1 stack-top))
+ ;; Check if there is more code after the '->' on the
+ ;; same line. If so use this indentation as base, else
+ ;; use parent indentation + 2 * level as base.
+ (let ((off erlang-indent-level)
+ (skip 2))
+ (cond ((null (cdr stack))) ; Top level in function.
+ ((eq (car stack-top) 'begin)
+ (setq skip 5))
+ ((eq (car stack-top) 'try)
+ (setq skip 5))
+ ((eq (car stack-top) '->)
+ ;; If in fun definition use standard indent level not double
+ ;;(if (not (eq (car (car (cdr stack))) 'fun))
+ ;; Removed it made multi clause fun's look to bad
+ (setq off (+ erlang-indent-level (if (not erlang-icr-indent)
+ erlang-indent-level
+ erlang-icr-indent)))))
+ (let ((base (erlang-indent-find-base stack indent-point off skip)))
+ ;; Special cases
+ (goto-char indent-point)
+ (cond ((looking-at "\\(end\\|after\\)\\($\\|[^_a-zA-Z0-9]\\)")
+ (if (eq (car stack-top) '->)
+ (erlang-pop stack))
+ (if stack
+ (erlang-caddr (car stack))
+ 0))
+ ((looking-at "catch\\b\\($\\|[^_a-zA-Z0-9]\\)")
+ ;; Are we in a try
+ (let ((start (if (eq (car stack-top) '->)
+ (car (cdr stack))
+ stack-top)))
+ (if (null start) nil
+ (goto-char (nth 1 start)))
+ (cond ((looking-at "try\\($\\|[^_a-zA-Z0-9]\\)")
+ (progn
+ (if (eq (car stack-top) '->)
+ (erlang-pop stack))
+ (if stack
+ (erlang-caddr (car stack))
+ 0)))
+ (t (erlang-indent-standard indent-point token base 'nil))))) ;; old catch
+ (t
+ (erlang-indent-standard indent-point token base 'nil)
+ ))))
+ ))
+ ((eq (car stack-top) 'when)
+ (goto-char (nth 1 stack-top))
+ (if (looking-at "when\\s *\\($\\|%\\)")
+ (progn
+ (erlang-pop stack)
+ (if (and stack (memq (nth 0 (car stack)) '(icr fun)))
+ (progn
+ (goto-char (nth 1 (car stack)))
+ (+ (nth 2 (car stack)) erlang-indent-guard
+ ;; receive XYZ or receive
+ ;; XYZ
+ ;; This if thing does not seem to be needed
+ ;;(if (looking-at "[a-z]+\\s *\\($\\|%\\)")
+ ;; erlang-indent-level
+ ;; (* 2 erlang-indent-level))))
+ (* 2 erlang-indent-level)))
+ ;;erlang-indent-level))
+ (+ erlang-indent-level erlang-indent-guard)))
;; "when" is followed by code, let's indent to the same
;; column.
(forward-char 4) ; Skip "when"
(skip-chars-forward " \t")
(current-column)))
- ;; Type and Spec indentation
- ((eq (car stack-top) '::)
- (if (looking-at "[},)]")
- ;; Closing function spec, record definition with types,
+ ;; Type and Spec indentation
+ ((eq (car stack-top) '::)
+ (if (looking-at "[},)]")
+ ;; Closing function spec, record definition with types,
;; or a comma at the start of the line
- ;; pop stack and recurse
- (erlang-calculate-stack-indent indent-point
- (cons (erlang-pop stack) (cdr state)))
- (cond ((null erlang-argument-indent)
- ;; indent to next column.
- (+ 2 (nth 2 stack-top)))
- ((looking-at "::[^_a-zA-Z0-9]")
- (nth 2 stack-top))
- (t
- (let ((start-alternativ (if (looking-at "|") 2 0)))
- (goto-char (nth 1 stack-top))
- (- (cond ((looking-at "::\\s *\\($\\|%\\)")
- ;; Line ends with ::
- (if (eq (car (car (last stack))) 'spec)
- (+ (erlang-indent-find-preceding-expr 1)
- erlang-argument-indent)
- (+ (erlang-indent-find-preceding-expr 2)
- erlang-argument-indent)))
- (t
- ;; Indent to the same column as the first
- ;; argument.
- (goto-char (+ 2 (nth 1 stack-top)))
- (skip-chars-forward " \t")
- (current-column))) start-alternativ))))))
- )))
+ ;; pop stack and recurse
+ (erlang-calculate-stack-indent indent-point
+ (cons (erlang-pop stack) (cdr state)))
+ (cond ((null erlang-argument-indent)
+ ;; indent to next column.
+ (+ 2 (nth 2 stack-top)))
+ ((looking-at "::[^_a-zA-Z0-9]")
+ (nth 2 stack-top))
+ (t
+ (let ((start-alternativ (if (looking-at "|") 2 0)))
+ (goto-char (nth 1 stack-top))
+ (- (cond ((looking-at "::\\s *\\($\\|%\\)")
+ ;; Line ends with ::
+ (if (eq (car (car (last stack))) 'spec)
+ (+ (erlang-indent-find-preceding-expr 1)
+ erlang-argument-indent)
+ (+ (erlang-indent-find-preceding-expr 2)
+ erlang-argument-indent)))
+ (t
+ ;; Indent to the same column as the first
+ ;; argument.
+ (goto-char (+ 2 (nth 1 stack-top)))
+ (skip-chars-forward " \t")
+ (current-column))) start-alternativ))))))
+ )))
(defun erlang-indent-standard (indent-point token base inside-parenthesis)
"Standard indent when in blocks or tuple or arguments.
Look at last thing to see in what state we are, move relative to the base."
- (goto-char token)
+ (goto-char token)
(cond ((looking-at "||\\|,\\|->\\||")
- base)
- ((erlang-at-keyword)
- (+ (current-column) erlang-indent-level))
- ((or (= (char-syntax (following-char)) ?.)
- (erlang-at-operator))
- (+ base erlang-indent-level))
- (t
- (goto-char indent-point)
- (cond ((memq (following-char) '(?\( ))
- ;; Function application.
- (+ (erlang-indent-find-preceding-expr)
- erlang-argument-indent))
- ;; Empty line, or end; treat it as the end of
- ;; the block. (Here we have a choice: should
- ;; the user be forced to reindent continued
- ;; lines, or should the "end" be reindented?)
-
- ;; Avoid treating comments a continued line.
- ((= (following-char) ?%)
- base)
- ;; Continued line (e.g. line beginning
- ;; with an operator.)
- (t
- (if (or (erlang-at-operator) (not inside-parenthesis))
- (+ base erlang-indent-level)
- base))))))
+ base)
+ ((erlang-at-keyword)
+ (+ (current-column) erlang-indent-level))
+ ((or (= (char-syntax (following-char)) ?.)
+ (erlang-at-operator))
+ (+ base erlang-indent-level))
+ (t
+ (goto-char indent-point)
+ (cond ((memq (following-char) '(?\( ))
+ ;; Function application.
+ (+ (erlang-indent-find-preceding-expr)
+ erlang-argument-indent))
+ ;; Empty line, or end; treat it as the end of
+ ;; the block. (Here we have a choice: should
+ ;; the user be forced to reindent continued
+ ;; lines, or should the "end" be reindented?)
+
+ ;; Avoid treating comments a continued line.
+ ((= (following-char) ?%)
+ base)
+ ;; Continued line (e.g. line beginning
+ ;; with an operator.)
+ (t
+ (if (or (erlang-at-operator) (not inside-parenthesis))
+ (+ base erlang-indent-level)
+ base))))))
(defun erlang-indent-find-base (stack indent-point &optional offset skip)
"Find the base column for current stack."
@@ -3067,21 +3080,21 @@ Return nil if inside string, t if in a comment."
(let* ((stack-top (car stack)))
(goto-char (nth 1 stack-top))
(if (< skip (- (point-max) (point)))
- (progn
- (forward-char skip)
- (if (looking-at "\\s *\\($\\|%\\)")
- (progn
- (if (memq (car stack-top) '(-> ||))
- (erlang-pop stack))
- ;; Take parent identation + offset,
- ;; else just erlang-indent-level if no parent
- (if stack
- (+ (erlang-caddr (car stack))
- offset)
- erlang-indent-level))
- (erlang-skip-blank indent-point)
- (current-column)))
- (+ (current-column) skip)))))
+ (progn
+ (forward-char skip)
+ (if (looking-at "\\s *\\($\\|%\\)")
+ (progn
+ (if (memq (car stack-top) '(-> ||))
+ (erlang-pop stack))
+ ;; Take parent identation + offset,
+ ;; else just erlang-indent-level if no parent
+ (if stack
+ (+ (erlang-caddr (car stack))
+ offset)
+ erlang-indent-level))
+ (erlang-skip-blank indent-point)
+ (current-column)))
+ (+ (current-column) skip)))))
;; Does not handle `begin' .. `end'.
@@ -3100,51 +3113,51 @@ This assumes that the preceding expression is either simple
;; where the call (forward-sexp -1) will fail when point is at the `#'.
(or
(ignore-errors
- ;; Needed to match the colon in "'foo':'bar'".
- (cond ((eq (preceding-char) ?:)
- (backward-char 1)
- (forward-sexp -1)
- (current-column))
- ((eq (preceding-char) ?#)
- ;; We may now be at:
- ;; - either a construction of a new record
- ;; - or update of a record, in which case we want
- ;; the column of the expression to be updated.
- ;;
- ;; To see which of the two cases we are at, we first
- ;; move an expression backwards, check for keywords,
- ;; then immediately an expression forwards. Moving
- ;; backwards skips past tokens like `,' or `->', but
- ;; when moving forwards again, we won't skip past such
- ;; tokens. We use this: if, after having moved
- ;; forwards, we're back where we started, then it was
- ;; a record update.
- ;; The check for keywords is to detect cases like:
- ;; case Something of #record_construction{...}
- (backward-char 1)
- (let ((record-start (point))
- (record-start-col (current-column)))
- (forward-sexp -1)
- (let ((preceding-expr-col (current-column))
- ;; white space definition according to erl_scan
- (white-space "\000-\040\200-\240"))
- (if (erlang-at-keyword)
- ;; The (forward-sexp -1) call moved past a keyword
- (1+ record-start-col)
- (forward-sexp 1)
- (skip-chars-forward white-space record-start)
- ;; Are we back where we started? If so, it was an update.
- (if (= (point) record-start)
- preceding-expr-col
- (goto-char record-start)
- (1+ (current-column)))))))
- (t col)))
+ ;; Needed to match the colon in "'foo':'bar'".
+ (cond ((eq (preceding-char) ?:)
+ (backward-char 1)
+ (forward-sexp -1)
+ (current-column))
+ ((eq (preceding-char) ?#)
+ ;; We may now be at:
+ ;; - either a construction of a new record
+ ;; - or update of a record, in which case we want
+ ;; the column of the expression to be updated.
+ ;;
+ ;; To see which of the two cases we are at, we first
+ ;; move an expression backwards, check for keywords,
+ ;; then immediately an expression forwards. Moving
+ ;; backwards skips past tokens like `,' or `->', but
+ ;; when moving forwards again, we won't skip past such
+ ;; tokens. We use this: if, after having moved
+ ;; forwards, we're back where we started, then it was
+ ;; a record update.
+ ;; The check for keywords is to detect cases like:
+ ;; case Something of #record_construction{...}
+ (backward-char 1)
+ (let ((record-start (point))
+ (record-start-col (current-column)))
+ (forward-sexp -1)
+ (let ((preceding-expr-col (current-column))
+ ;; white space definition according to erl_scan
+ (white-space "\000-\040\200-\240"))
+ (if (erlang-at-keyword)
+ ;; The (forward-sexp -1) call moved past a keyword
+ (1+ record-start-col)
+ (forward-sexp 1)
+ (skip-chars-forward white-space record-start)
+ ;; Are we back where we started? If so, it was an update.
+ (if (= (point) record-start)
+ preceding-expr-col
+ (goto-char record-start)
+ (1+ (current-column)))))))
+ (t col)))
col))))
-(defun erlang-indent-parenthesis (stack-position)
+(defun erlang-indent-parenthesis (stack-position)
(let ((previous (erlang-indent-find-preceding-expr)))
(if (> previous stack-position)
- (+ stack-position erlang-argument-indent)
+ (+ stack-position erlang-argument-indent)
(+ previous erlang-argument-indent))))
(defun erlang-skip-blank (&optional lim)
@@ -3153,20 +3166,20 @@ This assumes that the preceding expression is either simple
(let (stop)
(while (and (not stop) (< (point) lim))
(cond ((= (following-char) ?%)
- (skip-chars-forward "^\n" lim))
- ((= (following-char) ?\n)
- (skip-chars-forward "\n" lim))
- ((looking-at "\\s ")
- (if (re-search-forward "\\S " lim 'move)
- (forward-char -1)))
- (t
- (setq stop t))))
+ (skip-chars-forward "^\n" lim))
+ ((= (following-char) ?\n)
+ (skip-chars-forward "\n" lim))
+ ((looking-at "\\s ")
+ (if (re-search-forward "\\S " lim 'move)
+ (forward-char -1)))
+ (t
+ (setq stop t))))
stop))
(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\\)\\b")))
+ "of\\|receive\\|after\\|catch\\|try\\)\\b")))
(defun erlang-at-operator ()
"Are we looking at an Erlang operator?"
@@ -3179,14 +3192,14 @@ This assumes that the preceding expression is either simple
Used both by `indent-for-comment' and the Erlang specific indentation
commands."
(cond ((looking-at "%%%") 0)
- ((looking-at "%%")
- (or (erlang-calculate-indent)
- (current-indentation)))
- (t
- (save-excursion
- (skip-chars-backward " \t")
- (max (if (bolp) 0 (1+ (current-column)))
- comment-column)))))
+ ((looking-at "%%")
+ (or (erlang-calculate-indent)
+ (current-indentation)))
+ (t
+ (save-excursion
+ (skip-chars-backward " \t")
+ (max (if (bolp) 0 (1+ (current-column)))
+ comment-column)))))
;;; Erlang movement commands
@@ -3214,18 +3227,18 @@ Return t unless search stops due to end of buffer."
;; that the regexp below includes the last character of the
;; previous line.
(if (bobp)
- (or (looking-at "\n")
- (forward-char 1))
- (forward-char -1)
- (if (looking-at "\\`\n")
- (forward-char 1))))
+ (or (looking-at "\n")
+ (forward-char 1))
+ (forward-char -1)
+ (if (looking-at "\\`\n")
+ (forward-char 1))))
;; The regexp matches a function header that isn't
;; included in a string.
(and (re-search-forward "\\(\\`\\|\\`\n\\|[^\\]\n\\)\\(-?[a-z]\\|'\\|-\\)"
- nil 'move (- arg))
+ nil 'move (- arg))
(let ((beg (match-beginning 2)))
- (and beg (goto-char beg))
- t)))
+ (and beg (goto-char beg))
+ t)))
(defun erlang-end-of-clause (&optional arg)
"Move to the end of the current clause.
@@ -3233,18 +3246,16 @@ With argument, do this that many times."
(interactive "p")
(or arg (setq arg 1))
(while (and (looking-at "[ \t]*[%\n]")
- (zerop (forward-line 1))))
+ (zerop (forward-line 1))))
;; Move to the next clause.
(erlang-beginning-of-clause (- arg))
(beginning-of-line);; Just to be sure...
(let ((continue t))
(while (and (not (bobp)) continue)
(forward-line -1)
- (skip-chars-forward " \t")
- (if (looking-at "[%\n]")
- nil
- (end-of-line)
- (setq continue nil)))))
+ (unless (looking-at "[ \t]*[%\n]")
+ (end-of-line)
+ (setq continue nil)))))
(defun erlang-mark-clause ()
"Put mark at end of clause, point at beginning."
@@ -3273,22 +3284,22 @@ Return t unless search stops due to end of buffer."
;; Search backward
((> arg 0)
(while (and (> arg 0)
- (and (erlang-beginning-of-clause 1)
- (let ((start (point))
- (name (erlang-name-of-function))
- (arity (erlang-get-function-arity)))
- ;; Note: "arity" is nil for e.g. "-import", hence
- ;; two "-import" clauses are not considered to
- ;; be part of the same function.
- (while (and (erlang-beginning-of-clause 1)
- (string-equal name
- (erlang-name-of-function))
- arity
- (equal arity
- (erlang-get-function-arity)))
- (setq start (point)))
- (goto-char start)
- t)))
+ (and (erlang-beginning-of-clause 1)
+ (let ((start (point))
+ (name (erlang-name-of-function))
+ (arity (erlang-get-function-arity)))
+ ;; Note: "arity" is nil for e.g. "-import", hence
+ ;; two "-import" clauses are not considered to
+ ;; be part of the same function.
+ (while (and (erlang-beginning-of-clause 1)
+ (string-equal name
+ (erlang-name-of-function))
+ arity
+ (equal arity
+ (erlang-get-function-arity)))
+ (setq start (point)))
+ (goto-char start)
+ t)))
(setq arg (1- arg))))
;; Search forward
((< arg 0)
@@ -3296,19 +3307,19 @@ Return t unless search stops due to end of buffer."
(erlang-beginning-of-clause 1)
;; Step -arg functions forward.
(while (and (< arg 0)
- ;; Step one function forward, or stop if the end of
- ;; the buffer was reached. Return t if we found the
- ;; function.
- (let ((name (erlang-name-of-function))
- (arity (erlang-get-function-arity))
- (found (erlang-beginning-of-clause -1)))
- (while (and found
- (string-equal name (erlang-name-of-function))
- arity
- (equal arity
- (erlang-get-function-arity)))
- (setq found (erlang-beginning-of-clause -1)))
- found))
+ ;; Step one function forward, or stop if the end of
+ ;; the buffer was reached. Return t if we found the
+ ;; function.
+ (let ((name (erlang-name-of-function))
+ (arity (erlang-get-function-arity))
+ (found (erlang-beginning-of-clause -1)))
+ (while (and found
+ (string-equal name (erlang-name-of-function))
+ arity
+ (equal arity
+ (erlang-get-function-arity)))
+ (setq found (erlang-beginning-of-clause -1)))
+ found))
(setq arg (1+ arg)))))
(zerop arg))
@@ -3324,35 +3335,35 @@ With negative argument go towards the beginning of the buffer."
;; Forward
(while (and (> arg 0) (< (point) (point-max)))
(let ((pos (point)))
- (while (progn
- (if (and first
- (progn
- (forward-char 1)
- (erlang-beginning-of-clause 1)))
- nil
- (or (bobp) (forward-char -1))
- (erlang-beginning-of-clause -1))
- (setq first nil)
- (erlang-pass-over-function)
- (skip-chars-forward " \t")
- (if (looking-at "[%\n]")
- (forward-line 1))
- (<= (point) pos))))
+ (while (progn
+ (if (and first
+ (progn
+ (forward-char 1)
+ (erlang-beginning-of-clause 1)))
+ nil
+ (or (bobp) (forward-char -1))
+ (erlang-beginning-of-clause -1))
+ (setq first nil)
+ (erlang-pass-over-function)
+ (skip-chars-forward " \t")
+ (if (looking-at "[%\n]")
+ (forward-line 1))
+ (<= (point) pos))))
(setq arg (1- arg)))
;; Backward
(while (< arg 0)
(let ((pos (point)))
- (erlang-beginning-of-clause 1)
- (erlang-pass-over-function)
- (forward-line 1)
- (if (>= (point) pos)
- (if (erlang-beginning-of-function 2)
- (progn
- (erlang-pass-over-function)
- (skip-chars-forward " \t")
- (if (looking-at "[%\n]")
- (forward-line 1)))
- (goto-char (point-min)))))
+ (erlang-beginning-of-clause 1)
+ (erlang-pass-over-function)
+ (forward-line 1)
+ (if (>= (point) pos)
+ (if (erlang-beginning-of-function 2)
+ (progn
+ (erlang-pass-over-function)
+ (skip-chars-forward " \t")
+ (if (looking-at "[%\n]")
+ (forward-line 1)))
+ (goto-char (point-min)))))
(setq arg (1+ arg)))))
(eval-and-compile
@@ -3366,18 +3377,18 @@ With negative argument go towards the beginning of the buffer."
;; Sets the region. In Emacs 19 and XEmacs, we want to activate
;; the region.
(condition-case nil
- (push-mark (point) nil t)
- (error (push-mark (point))))
+ (push-mark (point) nil t)
+ (error (push-mark (point))))
(erlang-beginning-of-function 1)
;; The above function deactivates the mark.
(if (boundp 'deactivate-mark)
- (funcall (symbol-function 'set) 'deactivate-mark nil)))))
+ (funcall (symbol-function 'set) 'deactivate-mark nil)))))
(defun erlang-pass-over-function ()
(while (progn
- (erlang-skip-blank)
- (and (not (looking-at "\\.\\(\\s \\|\n\\|\\s<\\)"))
- (not (eobp))))
+ (erlang-skip-blank)
+ (and (not (looking-at "\\.\\(\\s \\|\n\\|\\s<\\)"))
+ (not (eobp))))
(forward-sexp 1))
(if (not (eobp))
(forward-char 1)))
@@ -3386,7 +3397,7 @@ With negative argument go towards the beginning of the buffer."
(save-excursion
;; Skip over attribute leader.
(if (looking-at "-[ \t]*")
- (re-search-forward "-[ \t]*" nil 'move))
+ (re-search-forward "-[ \t]*" nil 'move))
(let ((start (point)))
(forward-sexp 1)
(buffer-substring start (point)))))
@@ -3401,54 +3412,54 @@ paragraph of it that point is in, preserving the comment's indentation
and initial `%':s."
(interactive "P")
(let ((has-comment nil)
- ;; If has-comment, the appropriate fill-prefix for the comment.
- comment-fill-prefix)
+ ;; If has-comment, the appropriate fill-prefix for the comment.
+ comment-fill-prefix)
;; Figure out what kind of comment we are looking at.
(save-excursion
(beginning-of-line)
(cond
;; Find the command prefix.
((looking-at (concat "\\s *" comment-start-skip))
- (setq has-comment t)
- (setq comment-fill-prefix (buffer-substring (match-beginning 0)
- (match-end 0))))
+ (setq has-comment t)
+ (setq comment-fill-prefix (buffer-substring (match-beginning 0)
+ (match-end 0))))
;; A line with some code, followed by a comment? Remember that the
;; % which starts the comment shouldn't be part of a string or
;; character.
((progn
- (while (not (looking-at "%\\|$"))
- (skip-chars-forward "^%\n\"\\\\")
- (cond
- ((eq (char-after (point)) ?\\) (forward-char 2))
- ((eq (char-after (point)) ?\") (forward-sexp 1))))
- (looking-at comment-start-skip))
- (setq has-comment t)
- (setq comment-fill-prefix
- (concat (make-string (current-column) ? )
- (buffer-substring (match-beginning 0) (match-end 0)))))))
+ (while (not (looking-at "%\\|$"))
+ (skip-chars-forward "^%\n\"\\\\")
+ (cond
+ ((eq (char-after (point)) ?\\) (forward-char 2))
+ ((eq (char-after (point)) ?\") (forward-sexp 1))))
+ (looking-at comment-start-skip))
+ (setq has-comment t)
+ (setq comment-fill-prefix
+ (concat (make-string (current-column) ? )
+ (buffer-substring (match-beginning 0) (match-end 0)))))))
(if (not has-comment)
- (fill-paragraph justify)
+ (fill-paragraph justify)
;; Narrow to include only the comment, and then fill the region.
(save-restriction
- (narrow-to-region
- ;; Find the first line we should include in the region to fill.
- (save-excursion
- (while (and (zerop (forward-line -1))
- (looking-at "^\\s *%")))
- ;; We may have gone to far. Go forward again.
- (or (looking-at "^\\s *%")
- (forward-line 1))
- (point))
- ;; Find the beginning of the first line past the region to fill.
- (save-excursion
- (while (progn (forward-line 1)
- (looking-at "^\\s *%")))
- (point)))
- ;; Lines with only % on them can be paragraph boundaries.
- (let ((paragraph-start (concat paragraph-start "\\|^[ \t%]*$"))
- (paragraph-separate (concat paragraph-start "\\|^[ \t%]*$"))
- (fill-prefix comment-fill-prefix))
- (fill-paragraph justify))))))
+ (narrow-to-region
+ ;; Find the first line we should include in the region to fill.
+ (save-excursion
+ (while (and (zerop (forward-line -1))
+ (looking-at "^\\s *%")))
+ ;; We may have gone to far. Go forward again.
+ (or (looking-at "^\\s *%")
+ (forward-line 1))
+ (point))
+ ;; Find the beginning of the first line past the region to fill.
+ (save-excursion
+ (while (progn (forward-line 1)
+ (looking-at "^\\s *%")))
+ (point)))
+ ;; Lines with only % on them can be paragraph boundaries.
+ (let ((paragraph-start (concat paragraph-start "\\|^[ \t%]*$"))
+ (paragraph-separate (concat paragraph-start "\\|^[ \t%]*$"))
+ (fill-prefix comment-fill-prefix))
+ (fill-paragraph justify))))))
(defun erlang-uncomment-region (beg end)
@@ -3467,22 +3478,22 @@ first parenthesis is preserved. The point is placed between
the parentheses."
(interactive)
(let ((name (save-excursion
- (and (erlang-beginning-of-clause)
- (erlang-get-function-name t))))
- (arrow (save-excursion
- (and (erlang-beginning-of-clause)
- (erlang-get-function-arrow)))))
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-name t))))
+ (arrow (save-excursion
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-arrow)))))
(if (or (null arrow) (null name))
- (error "Can't find name of current Erlang function"))
+ (error "Can't find name of current Erlang function"))
(if (and (bolp) (eolp))
- nil
+ nil
(end-of-line)
(newline))
(insert name)
(save-excursion
(insert ") " arrow))
(if erlang-new-clause-with-arguments
- (erlang-clone-arguments))))
+ (erlang-clone-arguments))))
(defun erlang-clone-arguments ()
@@ -3492,12 +3503,12 @@ The mark is set at the beginning of the inserted text, the point
at the end."
(interactive)
(let ((args (save-excursion
- (beginning-of-line)
- (and (erlang-beginning-of-clause)
- (erlang-get-function-arguments))))
- (p (point)))
+ (beginning-of-line)
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-arguments))))
+ (p (point)))
(if (null args)
- (error "Can't clone argument list"))
+ (error "Can't clone argument list"))
(insert args)
(set-mark p)))
@@ -3520,18 +3531,18 @@ Return nil if file contains no `-module' attribute."
(widen)
(goto-char (point-min))
(let ((md (match-data)))
- (unwind-protect
- (if (re-search-forward
- (eval-when-compile
- (concat "^-module\\s *(\\s *\\(\\("
- erlang-atom-regexp
- "\\)?\\)\\s *)\\s *\\."))
- (point-max) t)
- (erlang-remove-quotes
- (erlang-buffer-substring (match-beginning 1)
- (match-end 1)))
- nil)
- (store-match-data md))))))
+ (unwind-protect
+ (if (re-search-forward
+ (eval-when-compile
+ (concat "^-module\\s *(\\s *\\(\\("
+ erlang-atom-regexp
+ "\\)?\\)\\s *)\\s *\\."))
+ (point-max) t)
+ (erlang-remove-quotes
+ (erlang-buffer-substring (match-beginning 1)
+ (match-end 1)))
+ nil)
+ (store-match-data md))))))
(defun erlang-get-module-from-file-name (&optional file)
@@ -3551,7 +3562,7 @@ tags system could be used by files written in other languages."
nil
(setq file (file-name-nondirectory file))
(if (string-match erlang-file-name-extension-regexp file)
- (substring file 0 (match-beginning 0))
+ (substring file 0 (match-beginning 0))
nil)))
@@ -3572,30 +3583,30 @@ corresponds to the order of the parsed Erlang list."
(erlang-skip-blank)
(forward-char 1)
(if (not (eq (preceding-char) ?\[))
- '() ; Not looking at an Erlang list.
- (while ; Note: `while' has no body.
- (progn
- (erlang-skip-blank)
- (and (looking-at (eval-when-compile
- (concat erlang-atom-regexp "/\\([0-9]+\\)\\>")))
- (progn
- (setq res (cons
- (cons
- (erlang-remove-quotes
- (erlang-buffer-substring
- (match-beginning 1) (match-end 1)))
- (erlang-string-to-int
- (erlang-buffer-substring
- (match-beginning
- (+ 1 erlang-atom-regexp-matches))
- (match-end
- (+ 1 erlang-atom-regexp-matches)))))
- res))
- (goto-char (match-end 0))
- (erlang-skip-blank)
- (forward-char 1)
- ;; Test if there are more exported functions.
- (eq (preceding-char) ?,))))))
+ '() ; Not looking at an Erlang list.
+ (while ; Note: `while' has no body.
+ (progn
+ (erlang-skip-blank)
+ (and (looking-at (eval-when-compile
+ (concat erlang-atom-regexp "/\\([0-9]+\\)\\>")))
+ (progn
+ (setq res (cons
+ (cons
+ (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (erlang-string-to-int
+ (erlang-buffer-substring
+ (match-beginning
+ (+ 1 erlang-atom-regexp-matches))
+ (match-end
+ (+ 1 erlang-atom-regexp-matches)))))
+ res))
+ (goto-char (match-end 0))
+ (erlang-skip-blank)
+ (forward-char 1)
+ ;; Test if there are more exported functions.
+ (eq (preceding-char) ?,))))))
(nreverse res)))
@@ -3607,14 +3618,14 @@ corresponds to the order of the parsed Erlang list."
(save-excursion
(goto-char (point-min))
(let ((md (match-data))
- (res '()))
+ (res '()))
(unwind-protect
- (progn
- (while (re-search-forward "^-export\\s *(" (point-max) t)
- (erlang-skip-blank)
- (setq res (nconc res (erlang-get-function-arity-list))))
- res)
- (store-match-data md)))))
+ (progn
+ (while (re-search-forward "^-export\\s *(" (point-max) t)
+ (erlang-skip-blank)
+ (setq res (nconc res (erlang-get-function-arity-list))))
+ res)
+ (store-match-data md)))))
(defun erlang-get-import ()
@@ -3625,30 +3636,30 @@ function and arity as cdr part."
(save-excursion
(goto-char (point-min))
(let ((md (match-data))
- (res '()))
+ (res '()))
(unwind-protect
- (progn
- (while (re-search-forward "^-import\\s *(" (point-max) t)
- (erlang-skip-blank)
- (if (looking-at erlang-atom-regexp)
- (let ((module (erlang-remove-quotes
- (erlang-buffer-substring
- (match-beginning 0)
- (match-end 0)))))
- (goto-char (match-end 0))
- (erlang-skip-blank)
- (if (eq (following-char) ?,)
- (progn
- (forward-char 1)
- (erlang-skip-blank)
- (let ((funcs (erlang-get-function-arity-list))
- (pair (assoc module res)))
- (if pair
- (setcdr pair (nconc (cdr pair) funcs))
- (setq res (cons (cons module funcs)
- res)))))))))
- (nreverse res))
- (store-match-data md)))))
+ (progn
+ (while (re-search-forward "^-import\\s *(" (point-max) t)
+ (erlang-skip-blank)
+ (if (looking-at erlang-atom-regexp)
+ (let ((module (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 0)
+ (match-end 0)))))
+ (goto-char (match-end 0))
+ (erlang-skip-blank)
+ (if (eq (following-char) ?,)
+ (progn
+ (forward-char 1)
+ (erlang-skip-blank)
+ (let ((funcs (erlang-get-function-arity-list))
+ (pair (assoc module res)))
+ (if pair
+ (setcdr pair (nconc (cdr pair) funcs))
+ (setq res (cons (cons module funcs)
+ res)))))))))
+ (nreverse res))
+ (store-match-data md)))))
(defun erlang-get-function-name (&optional arg)
@@ -3660,12 +3671,12 @@ the first `(' is returned.
Normally used in conjunction with `erlang-beginning-of-clause', e.g.:
(save-excursion
(if (not (eobp)) (forward-char 1))
- (and (erlang-beginning-of-clause)
- (erlang-get-function-name t)))"
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-name t)))"
(let ((n (if arg 0 1)))
(and (looking-at (eval-when-compile
- (concat "^" erlang-atom-regexp "\\s *(")))
- (erlang-buffer-substring (match-beginning n) (match-end n)))))
+ (concat "^" erlang-atom-regexp "\\s *(")))
+ (erlang-buffer-substring (match-beginning n) (match-end n)))))
(defun erlang-get-function-arrow ()
@@ -3674,9 +3685,9 @@ Normally used in conjunction with `erlang-beginning-of-clause', e.g.:
Normally used in conjunction with `erlang-beginning-of-clause', e.g.:
(save-excursion
(if (not (eobp)) (forward-char 1))
- (and (erlang-beginning-of-clause)
- (erlang-get-function-arrow)))"
- (and
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-arrow)))"
+ (and
(save-excursion
(re-search-forward "->" (point-max) t)
(erlang-buffer-substring (- (point) 2) (+ (point) 1)))))
@@ -3684,33 +3695,33 @@ Normally used in conjunction with `erlang-beginning-of-clause', e.g.:
(defun erlang-get-function-arity ()
"Return the number of arguments of function at point, or nil."
(and (looking-at (eval-when-compile
- (concat "^" erlang-atom-regexp "\\s *(")))
+ (concat "^" erlang-atom-regexp "\\s *(")))
(save-excursion
- (goto-char (match-end 0))
- (condition-case nil
- (let ((res 0)
- (cont t))
- (while cont
- (cond ((eobp)
- (setq res nil)
- (setq cont nil))
- ((looking-at "\\s *)")
- (setq cont nil))
- ((looking-at "\\s *\\($\\|%\\)")
- (forward-line 1))
- ((looking-at "\\s *<<[^>]*?>>")
- (when (zerop res)
- (setq res (+ 1 res)))
- (goto-char (match-end 0)))
- ((looking-at "\\s *,")
- (setq res (+ 1 res))
- (goto-char (match-end 0)))
- (t
- (when (zerop res)
- (setq res (+ 1 res)))
- (forward-sexp 1))))
- res)
- (error nil)))))
+ (goto-char (match-end 0))
+ (condition-case nil
+ (let ((res 0)
+ (cont t))
+ (while cont
+ (cond ((eobp)
+ (setq res nil)
+ (setq cont nil))
+ ((looking-at "\\s *)")
+ (setq cont nil))
+ ((looking-at "\\s *\\($\\|%\\)")
+ (forward-line 1))
+ ((looking-at "\\s *<<[^>]*?>>")
+ (when (zerop res)
+ (setq res (+ 1 res)))
+ (goto-char (match-end 0)))
+ ((looking-at "\\s *,")
+ (setq res (+ 1 res))
+ (goto-char (match-end 0)))
+ (t
+ (when (zerop res)
+ (setq res (+ 1 res)))
+ (forward-sexp 1))))
+ res)
+ (error nil)))))
(defun erlang-get-function-name-and-arity ()
"Return the name and arity of the function at point, or nil.
@@ -3722,15 +3733,15 @@ The return value is a string of the form \"foo/1\"."
(defun erlang-get-function-arguments ()
"Return arguments of current function, or nil."
(if (not (looking-at (eval-when-compile
- (concat "^" erlang-atom-regexp "\\s *("))))
+ (concat "^" erlang-atom-regexp "\\s *("))))
nil
(save-excursion
(condition-case nil
- (let ((start (match-end 0)))
- (goto-char (- start 1))
- (forward-sexp)
- (erlang-buffer-substring start (- (point) 1)))
- (error nil)))))
+ (let ((start (match-end 0)))
+ (goto-char (- start 1))
+ (forward-sexp)
+ (erlang-buffer-substring start (- (point) 1)))
+ (error nil)))))
(defun erlang-get-function-under-point ()
@@ -3747,37 +3758,37 @@ The following could be returned:
In the future the list may contain more elements."
(save-excursion
(let ((md (match-data))
- (res nil))
+ (res nil))
(if (eq (char-syntax (following-char)) ? )
- (skip-chars-backward " \t"))
+ (skip-chars-backward " \t"))
(skip-chars-backward "a-zA-Z0-9_:'")
(cond ((looking-at (eval-when-compile
- (concat erlang-atom-regexp ":" erlang-atom-regexp)))
- (setq res (list
- (erlang-remove-quotes
- (erlang-buffer-substring
- (match-beginning 1) (match-end 1)))
- (erlang-remove-quotes
- (erlang-buffer-substring
- (match-beginning (1+ erlang-atom-regexp-matches))
- (match-end (1+ erlang-atom-regexp-matches)))))))
- ((looking-at erlang-atom-regexp)
- (let ((fk (erlang-remove-quotes
- (erlang-buffer-substring
- (match-beginning 0) (match-end 0))))
- (mod nil)
- (imports (erlang-get-import)))
- (while (and imports (null mod))
- (if (assoc fk (cdr (car imports)))
- (setq mod (car (car imports)))
- (setq imports (cdr imports))))
- (cond ((eq (preceding-char) ?#)
- (setq fk (concat "-record(" fk)))
- ((eq (preceding-char) ??)
- (setq fk (concat "-define(" fk)))
- ((and (null mod) (not (member fk erlang-int-bifs)))
- (setq mod (erlang-get-module))))
- (setq res (list mod fk)))))
+ (concat erlang-atom-regexp ":" erlang-atom-regexp)))
+ (setq res (list
+ (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning (1+ erlang-atom-regexp-matches))
+ (match-end (1+ erlang-atom-regexp-matches)))))))
+ ((looking-at erlang-atom-regexp)
+ (let ((fk (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 0) (match-end 0))))
+ (mod nil)
+ (imports (erlang-get-import)))
+ (while (and imports (null mod))
+ (if (assoc fk (cdr (car imports)))
+ (setq mod (car (car imports)))
+ (setq imports (cdr imports))))
+ (cond ((eq (preceding-char) ?#)
+ (setq fk (concat "-record(" fk)))
+ ((eq (preceding-char) ??)
+ (setq fk (concat "-define(" fk)))
+ ((and (null mod) (not (member fk erlang-int-bifs)))
+ (setq mod (erlang-get-module))))
+ (setq res (list mod fk)))))
(store-match-data md)
res)))
@@ -3788,11 +3799,11 @@ In the future the list may contain more elements."
"Return STR, possibly with quotes."
(let ((case-fold-search nil)) ; force string matching to be case sensitive
(if (and (stringp str)
- (not (string-match (eval-when-compile
- (concat "\\`" erlang-atom-regexp "\\'")) str)))
- (progn (if (fboundp 'replace-regexp-in-string)
- (setq str (replace-regexp-in-string "'" "\\'" str t t )))
- (concat "'" str "'"))
+ (not (string-match (eval-when-compile
+ (concat "\\`" erlang-atom-regexp "\\'")) str)))
+ (progn (if (fboundp 'replace-regexp-in-string)
+ (setq str (replace-regexp-in-string "'" "\\'" str t t )))
+ (concat "'" str "'"))
str)))
@@ -3800,9 +3811,9 @@ In the future the list may contain more elements."
"Return STR without quotes, if present."
(let ((md (match-data)))
(prog1
- (if (string-match "\\`'\\(.*\\)'\\'" str)
- (substring str 1 -1)
- str)
+ (if (string-match "\\`'\\(.*\\)'\\'" str)
+ (substring str 1 -1)
+ str)
(store-match-data md))))
(defun erlang-match-next-exported-function (max)
@@ -3872,30 +3883,30 @@ is prompted.
This function is normally placed in the hook `local-write-file-hooks'."
(if erlang-check-module-name
- (let ((mn (erlang-add-quotes-if-needed
- (erlang-get-module)))
- (fn (erlang-add-quotes-if-needed
- (erlang-get-module-from-file-name (buffer-file-name)))))
- (if (and (stringp mn) (stringp fn))
- (or (string-equal mn fn)
- (if (or (eq erlang-check-module-name t)
- (y-or-n-p
- "Module does not match file name. Modify source? "))
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (if (re-search-forward
- (eval-when-compile
- (concat "^-module\\s *(\\s *\\(\\("
- erlang-atom-regexp
- "\\)?\\)\\s *)\\s *\\."))
- (point-max) t)
- (progn
- (goto-char (match-beginning 1))
- (delete-region (match-beginning 1)
- (match-end 1))
- (insert fn))))))))))
+ (let ((mn (erlang-add-quotes-if-needed
+ (erlang-get-module)))
+ (fn (erlang-add-quotes-if-needed
+ (erlang-get-module-from-file-name (buffer-file-name)))))
+ (if (and (stringp mn) (stringp fn))
+ (or (string-equal mn fn)
+ (if (or (eq erlang-check-module-name t)
+ (y-or-n-p
+ "Module does not match file name. Modify source? "))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (if (re-search-forward
+ (eval-when-compile
+ (concat "^-module\\s *(\\s *\\(\\("
+ erlang-atom-regexp
+ "\\)?\\)\\s *)\\s *\\."))
+ (point-max) t)
+ (progn
+ (goto-char (match-beginning 1))
+ (delete-region (match-beginning 1)
+ (match-end 1))
+ (insert fn))))))))))
;; Must return nil since it is added to `local-write-file-hook'.
nil)
@@ -3921,13 +3932,13 @@ non-whitespace characters following the point on the current line."
(interactive "P")
(self-insert-command (prefix-numeric-value arg))
(if (or arg
- (and (listp erlang-electric-commands)
- (not (memq 'erlang-electric-semicolon
- erlang-electric-commands)))
- (erlang-in-literal)
- (not (looking-at "\\s *\\(%.*\\)?$"))
- (null (erlang-test-criteria-list
- erlang-electric-semicolon-criteria)))
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-semicolon
+ erlang-electric-commands)))
+ (erlang-in-literal)
+ (not (looking-at "\\s *\\(%.*\\)?$"))
+ (null (erlang-test-criteria-list
+ erlang-electric-semicolon-criteria)))
(setq erlang-electric-newline-inhibit nil)
(setq erlang-electric-newline-inhibit t)
(undo-boundary)
@@ -3935,20 +3946,20 @@ non-whitespace characters following the point on the current line."
(end-of-line)
(newline)
(if (condition-case nil
- (progn (erlang-indent-line) t)
- (error (if (bolp) (delete-char -1))))
- (if (not (bolp))
- (save-excursion
- (insert " ->"))
- (condition-case nil
- (progn
- (erlang-generate-new-clause)
- (if erlang-electric-semicolon-insert-blank-lines
- (save-excursion
- (beginning-of-line)
- (newline
- erlang-electric-semicolon-insert-blank-lines))))
- (error (if (bolp) (delete-char -1))))))))
+ (progn (erlang-indent-line) t)
+ (error (if (bolp) (delete-char -1))))
+ (if (not (bolp))
+ (save-excursion
+ (insert " ->"))
+ (condition-case nil
+ (progn
+ (erlang-generate-new-clause)
+ (if erlang-electric-semicolon-insert-blank-lines
+ (save-excursion
+ (beginning-of-line)
+ (newline
+ erlang-electric-semicolon-insert-blank-lines))))
+ (error (if (bolp) (delete-char -1))))))))
(defun erlang-electric-comma (&optional arg)
@@ -3964,12 +3975,12 @@ non-whitespace characters following the point on the current line."
(self-insert-command (prefix-numeric-value arg))
(if (or arg
- (and (listp erlang-electric-commands)
- (not (memq 'erlang-electric-comma erlang-electric-commands)))
- (erlang-in-literal)
- (not (looking-at "\\s *\\(%.*\\)?$"))
- (null (erlang-test-criteria-list
- erlang-electric-comma-criteria)))
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-comma erlang-electric-commands)))
+ (erlang-in-literal)
+ (not (looking-at "\\s *\\(%.*\\)?$"))
+ (null (erlang-test-criteria-list
+ erlang-electric-comma-criteria)))
(setq erlang-electric-newline-inhibit nil)
(setq erlang-electric-newline-inhibit t)
(undo-boundary)
@@ -3977,12 +3988,12 @@ non-whitespace characters following the point on the current line."
(end-of-line)
(newline)
(condition-case nil
- (erlang-indent-line)
+ (erlang-indent-line)
(error (if (bolp) (delete-char -1))))))
(defun erlang-electric-lt (&optional arg)
"Insert a less-than sign, and optionally mark it as an open paren."
-
+
(interactive "p")
(self-insert-command arg)
@@ -3992,48 +4003,48 @@ non-whitespace characters following the point on the current line."
(save-excursion
(backward-char 2)
(when (and (eq (char-after (point)) ?<)
- (not (eq (get-text-property (point) 'category)
- 'bitsyntax-open-inner)))
- ;; Then mark the two chars...
- (put-text-property (point) (1+ (point))
- 'category 'bitsyntax-open-outer)
- (forward-char 1)
- (put-text-property (point) (1+ (point))
- 'category 'bitsyntax-open-inner)
- ;;...and unmark any subsequent less-than chars.
- (forward-char 1)
- (while (eq (char-after (point)) ?<)
- (remove-text-properties (point) (1+ (point))
- '(category nil))
- (forward-char 1))))))
+ (not (eq (get-text-property (point) 'category)
+ 'bitsyntax-open-inner)))
+ ;; Then mark the two chars...
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-open-outer)
+ (forward-char 1)
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-open-inner)
+ ;;...and unmark any subsequent less-than chars.
+ (forward-char 1)
+ (while (eq (char-after (point)) ?<)
+ (remove-text-properties (point) (1+ (point))
+ '(category nil))
+ (forward-char 1))))))
(defun erlang-after-bitsyntax-close ()
"Return t if point is immediately after a bit-syntax close parenthesis (`>>')."
(and (>= (point) 3)
(save-excursion
- (backward-char 2)
- (and (eq (char-after (point)) ?>)
- (not (eq (get-text-property (point) 'category)
- 'bitsyntax-close-outer))))))
-
+ (backward-char 2)
+ (and (eq (char-after (point)) ?>)
+ (not (eq (get-text-property (point) 'category)
+ 'bitsyntax-close-outer))))))
+
(defun erlang-after-arrow ()
"Return true if point is immediately after a function arrow (`->')."
(and (>= (point) 2)
- (and
- (save-excursion
- (backward-char)
- (eq (char-before (point)) ?-))
- (or (not (listp erlang-electric-commands))
- (memq 'erlang-electric-gt
- erlang-electric-commands))
- (not (erlang-in-literal))
- (looking-at "\\s *\\(%.*\\)?$")
- (erlang-test-criteria-list erlang-electric-arrow-criteria))))
+ (and
+ (save-excursion
+ (backward-char)
+ (eq (char-before (point)) ?-))
+ (or (not (listp erlang-electric-commands))
+ (memq 'erlang-electric-gt
+ erlang-electric-commands))
+ (not (erlang-in-literal))
+ (looking-at "\\s *\\(%.*\\)?$")
+ (erlang-test-criteria-list erlang-electric-arrow-criteria))))
(defun erlang-electric-gt (&optional arg)
"Insert a greater-than sign, and optionally mark it as a close paren."
-
+
(interactive "p")
(self-insert-command arg)
@@ -4044,17 +4055,17 @@ non-whitespace characters following the point on the current line."
(save-excursion
;; Then mark the two chars...
(backward-char 2)
- (put-text-property (point) (1+ (point))
- 'category 'bitsyntax-close-inner)
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-close-inner)
(forward-char)
(put-text-property (point) (1+ (point))
- 'category 'bitsyntax-close-outer)
+ 'category 'bitsyntax-close-outer)
;;...and unmark any subsequent greater-than chars.
(forward-char)
(while (eq (char-after (point)) ?>)
- (remove-text-properties (point) (1+ (point))
- '(category nil))
- (forward-char))))
+ (remove-text-properties (point) (1+ (point))
+ '(category nil))
+ (forward-char))))
;; Did we just write a function arrow (`->')?
((erlang-after-arrow)
@@ -4063,13 +4074,13 @@ non-whitespace characters following the point on the current line."
(end-of-line)
(newline)
(condition-case nil
- (erlang-indent-line)
- (error (if (bolp) (delete-char -1))))))
+ (erlang-indent-line)
+ (error (if (bolp) (delete-char -1))))))
;; Then it's just a plain greater-than.
(t
nil)))
-
+
(defun erlang-electric-arrow\ off (&optional arg)
"Insert a '>'-sign and possibly a new indented line.
@@ -4089,22 +4100,22 @@ After being split/merged into `erlang-after-arrow' and
(let ((prec (preceding-char)))
(self-insert-command (prefix-numeric-value arg))
(if (or arg
- (and (listp erlang-electric-commands)
- (not (memq 'erlang-electric-arrow
- erlang-electric-commands)))
- (not (eq prec ?-))
- (erlang-in-literal)
- (not (looking-at "\\s *\\(%.*\\)?$"))
- (null (erlang-test-criteria-list
- erlang-electric-arrow-criteria)))
- (setq erlang-electric-newline-inhibit nil)
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-arrow
+ erlang-electric-commands)))
+ (not (eq prec ?-))
+ (erlang-in-literal)
+ (not (looking-at "\\s *\\(%.*\\)?$"))
+ (null (erlang-test-criteria-list
+ erlang-electric-arrow-criteria)))
+ (setq erlang-electric-newline-inhibit nil)
(setq erlang-electric-newline-inhibit t)
(undo-boundary)
(end-of-line)
(newline)
(condition-case nil
- (erlang-indent-line)
- (error (if (bolp) (delete-char -1)))))))
+ (erlang-indent-line)
+ (error (if (bolp) (delete-char -1)))))))
(defun erlang-electric-newline (&optional arg)
@@ -4119,30 +4130,30 @@ Should the previous command be another electric command we assume that
the user pressed newline out of old habit, hence we will do nothing."
(interactive "P")
(cond ((and (not arg)
- erlang-electric-newline-inhibit
- (memq last-command erlang-electric-newline-inhibit-list))
- ()) ; Do nothing!
- ((or arg
- (and (listp erlang-electric-commands)
- (not (memq 'erlang-electric-newline
- erlang-electric-commands)))
- (null (erlang-test-criteria-list
- erlang-electric-newline-criteria)))
- (newline (prefix-numeric-value arg)))
- (t
- (if (and comment-multi-line
- (save-excursion
- (beginning-of-line)
- (looking-at (concat "\\s *" comment-start-skip))))
- (let ((str (buffer-substring
- (or (match-end 1) (match-beginning 0))
- (min (match-end 0) (point)))))
- (newline)
- (undo-boundary)
- (insert str))
- (newline)
- (undo-boundary)
- (indent-according-to-mode)))))
+ erlang-electric-newline-inhibit
+ (memq last-command erlang-electric-newline-inhibit-list))
+ ()) ; Do nothing!
+ ((or arg
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-newline
+ erlang-electric-commands)))
+ (null (erlang-test-criteria-list
+ erlang-electric-newline-criteria)))
+ (newline (prefix-numeric-value arg)))
+ (t
+ (if (and comment-multi-line
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (concat "\\s *" comment-start-skip))))
+ (let ((str (buffer-substring
+ (or (match-end 1) (match-beginning 0))
+ (min (match-end 0) (point)))))
+ (newline)
+ (undo-boundary)
+ (insert str))
+ (newline)
+ (undo-boundary)
+ (indent-according-to-mode)))))
(defun erlang-test-criteria-list (criteria)
@@ -4167,14 +4178,14 @@ Return t if criteria fulfilled, nil otherwise."
t
(save-excursion
(let ((answer nil))
- (while (and criteria (null answer))
- (if (eq (car criteria) t)
- (setq answer t)
- (setq answer (funcall (car criteria))))
- (setq criteria (cdr criteria)))
- (if (and answer (not (eq answer 'stop)))
- t
- nil)))))
+ (while (and criteria (null answer))
+ (if (eq (car criteria) t)
+ (setq answer t)
+ (setq answer (funcall (car criteria))))
+ (setq criteria (cdr criteria)))
+ (if (and answer (not (eq answer 'stop)))
+ t
+ nil)))))
(defun erlang-in-literal (&optional lim)
@@ -4185,11 +4196,11 @@ Should the point be inside none of the above mentioned types of
context, nil is returned."
(save-excursion
(let* ((lim (or lim (save-excursion
- (erlang-beginning-of-clause)
- (point))))
- (state (if (fboundp 'syntax-ppss) ; post Emacs 21.3
- (funcall (symbol-function 'syntax-ppss))
- (parse-partial-sexp lim (point)))))
+ (erlang-beginning-of-clause)
+ (point))))
+ (state (if (fboundp 'syntax-ppss) ; post Emacs 21.3
+ (funcall (symbol-function 'syntax-ppss))
+ (parse-partial-sexp lim (point)))))
(cond
((eq (nth 3 state) ?') 'atom)
((nth 3 state) 'string)
@@ -4203,7 +4214,7 @@ context, nil is returned."
This function is designed to be a member of a criteria list."
(eq (save-excursion (erlang-skip-blank) (point))
(save-excursion
- (erlang-beginning-of-function -1) (point))))
+ (erlang-beginning-of-function -1) (point))))
(defun erlang-at-end-of-clause-p ()
@@ -4212,7 +4223,7 @@ This function is designed to be a member of a criteria list."
This function is designed to be a member of a criteria list."
(eq (save-excursion (erlang-skip-blank) (point))
(save-excursion
- (erlang-beginning-of-clause -1) (point))))
+ (erlang-beginning-of-clause -1) (point))))
(defun erlang-stop-when-inside-argument-list ()
@@ -4224,22 +4235,22 @@ after `||', `stop' is not returned.
This function is designed to be a member of a criteria list."
(save-excursion
(condition-case nil
- (let ((orig-point (point))
- (state nil))
- (up-list -1)
- (if (not (eq (following-char) ?\[))
- 'stop
- ;; Do not return `stop' when inside a list comprehension
- ;; construction. (The point must be after `||').
- (while (< (point) orig-point)
+ (let ((orig-point (point))
+ (state nil))
+ (up-list -1)
+ (if (not (eq (following-char) ?\[))
+ 'stop
+ ;; Do not return `stop' when inside a list comprehension
+ ;; construction. (The point must be after `||').
+ (while (< (point) orig-point)
(let ((pt (point)))
(setq state (erlang-partial-parse pt orig-point state))
(if (= pt (point))
(error "Illegal syntax"))))
- (if (and (car state) (eq (car (car (car state))) '||))
- nil
- 'stop)))
- (error
+ (if (and (car state) (eq (car (car (car state))) '||))
+ nil
+ 'stop)))
+ (error
nil))))
@@ -4250,11 +4261,11 @@ This function is designed to be a member of a criteria list."
(save-excursion
(beginning-of-line)
(if (and (looking-at (eval-when-compile
- (concat "^" erlang-atom-regexp "\\s *(")))
- (not (looking-at
- (eval-when-compile
- (concat "^" erlang-atom-regexp ".*->")))))
- 'stop
+ (concat "^" erlang-atom-regexp "\\s *(")))
+ (not (looking-at
+ (eval-when-compile
+ (concat "^" erlang-atom-regexp ".*->")))))
+ 'stop
nil)))
@@ -4279,13 +4290,13 @@ A line containing only spaces and tabs is considered empty.
This function is designed to be a member of a criteria list."
(and erlang-next-lines-empty-threshold
(save-excursion
- (let ((left erlang-next-lines-empty-threshold)
- (cont t))
- (while (and cont (> left 0))
- (forward-line 1)
- (setq cont (looking-at "\\s *$"))
- (setq left (- left 1)))
- cont))))
+ (let ((left erlang-next-lines-empty-threshold)
+ (cont t))
+ (while (and cont (> left 0))
+ (forward-line 1)
+ (setq cont (looking-at "\\s *$"))
+ (setq left (- left 1)))
+ cont))))
(defun erlang-at-keyword-end-p ()
@@ -4304,9 +4315,9 @@ This function is designed to be a member of a criteria list."
(eval-when-compile
(if (or (featurep 'bytecomp)
- (featurep 'byte-compile))
+ (featurep 'byte-compile))
(progn
- (require 'etags))))
+ (require 'etags))))
;; Variables:
@@ -4352,26 +4363,26 @@ as on the old form `tag'.
In the completion list, `module:tag' and `module:' shows up.
-Call this function from an appropriate init file, or add it to
-Erlang mode hook with the commands:
- (add-hook 'erlang-mode-hook 'erlang-tags-init)
- (add-hook 'erlang-shell-mode-hook 'erlang-tags-init)
-
This function only works under Emacs 18 and Emacs 19. Currently, It
is not implemented under XEmacs. (Hint: The Emacs 19 etags module
works under XEmacs.)"
(interactive)
(cond ((= erlang-emacs-major-version 18)
- (require 'tags)
- (erlang-tags-define-keys (current-local-map))
- (setq erlang-tags-installed t))
- (t
- (require 'etags)
- ;; Test on a function available in the Emacs 19 version
- ;; of tags but not in the XEmacs version.
- (when (fboundp 'find-tag-noselect)
- (erlang-tags-define-keys (current-local-map))
- (setq erlang-tags-installed t)))))
+ (require 'tags)
+ (erlang-tags-define-keys (current-local-map))
+ (setq erlang-tags-installed t))
+ (t
+ (require 'etags)
+ (set (make-local-variable 'find-tag-default-function)
+ 'erlang-find-tag-for-completion)
+ (if (>= emacs-major-version 25)
+ (add-hook 'xref-backend-functions
+ #'erlang-etags--xref-backend nil t)
+ ;; Test on a function available in the Emacs 19 version
+ ;; of tags but not in the XEmacs version.
+ (when (fboundp 'find-tag-noselect)
+ (erlang-tags-define-keys (current-local-map))
+ (setq erlang-tags-installed t))))))
@@ -4386,11 +4397,11 @@ works under XEmacs.)"
(let ((alist erlang-tags-function-alist))
(while alist
(let* ((old (car (car alist)))
- (new (cdr (car alist)))
- (keys (append (where-is-internal old global-map))))
- (while keys
- (define-key map (car keys) new)
- (setq keys (cdr keys))))
+ (new (cdr (car alist)))
+ (keys (append (where-is-internal old global-map))))
+ (while keys
+ (define-key map (car keys) new)
+ (setq keys (cdr keys))))
(setq alist (cdr alist))))
;; Update the menu.
(erlang-menu-substitute erlang-menu-base-items erlang-tags-function-alist)
@@ -4403,11 +4414,11 @@ Search `-import' list of imported functions.
Single quotes are been stripped away."
(let ((mod-func (erlang-get-function-under-point)))
(cond ((null mod-func)
- nil)
- ((null (car mod-func))
- (nth 1 mod-func))
- (t
- (concat (car mod-func) ":" (nth 1 mod-func))))))
+ nil)
+ ((null (car mod-func))
+ (nth 1 mod-func))
+ (t
+ (concat (car mod-func) ":" (nth 1 mod-func))))))
;; Return `t' since it is used inside `tags-loop-form'.
@@ -4426,31 +4437,31 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(defun erlang-find-tag-other-window (tagname &optional next-p regexp-p)
"Like `find-tag-other-window' but aware of Erlang modules."
(interactive (erlang-tag-interactive
- "Find `module:tag' or `tag' other window: "))
+ "Find `module:tag' or `tag' other window: "))
;; This is to deal with the case where the tag is found in the
;; selected window's buffer; without this, point is moved in both
;; windows. To prevent this, we save the selected window's point
;; before doing find-tag-noselect, and restore it afterwards.
(let* ((window-point (window-point (selected-window)))
- (tagbuf (erlang-find-tag-noselect tagname next-p regexp-p))
- (tagpoint (progn (set-buffer tagbuf) (point))))
+ (tagbuf (erlang-find-tag-noselect tagname next-p regexp-p))
+ (tagpoint (progn (set-buffer tagbuf) (point))))
(set-window-point (prog1
- (selected-window)
- (switch-to-buffer-other-window tagbuf)
- ;; We have to set this new window's point; it
- ;; might already have been displaying a
- ;; different portion of tagbuf, in which case
- ;; switch-to-buffer-other-window doesn't set
- ;; the window's point from the buffer.
- (set-window-point (selected-window) tagpoint))
- window-point)))
+ (selected-window)
+ (switch-to-buffer-other-window tagbuf)
+ ;; We have to set this new window's point; it
+ ;; might already have been displaying a
+ ;; different portion of tagbuf, in which case
+ ;; switch-to-buffer-other-window doesn't set
+ ;; the window's point from the buffer.
+ (set-window-point (selected-window) tagpoint))
+ window-point)))
(defun erlang-find-tag-other-frame (tagname &optional next-p)
"Like `find-tag-other-frame' but aware of Erlang modules."
(interactive (erlang-tag-interactive
- "Find `module:tag' or `tag' other frame: "))
+ "Find `module:tag' or `tag' other frame: "))
(let ((pop-up-frames t))
(erlang-find-tag-other-window tagname next-p)))
@@ -4458,13 +4469,13 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(defun erlang-find-tag-regexp (regexp &optional next-p other-window)
"Like `find-tag-regexp' but aware of Erlang modules."
(interactive (if (fboundp 'find-tag-regexp)
- (erlang-tag-interactive
- "Find `module:regexp' or `regexp': ")
- (error "This version of Emacs can't find tags by regexps")))
+ (erlang-tag-interactive
+ "Find `module:regexp' or `regexp': ")
+ (error "This version of Emacs can't find tags by regexps")))
(funcall (if other-window
- 'erlang-find-tag-other-window
- 'erlang-find-tag)
- regexp next-p t))
+ 'erlang-find-tag-other-window
+ 'erlang-find-tag)
+ regexp next-p t))
;; Just like C-u M-. This could be added to the menu.
@@ -4473,7 +4484,7 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(interactive)
(let ((current-prefix-arg '(4)))
(if erlang-tags-installed
- (call-interactively 'erlang-find-tag)
+ (call-interactively 'erlang-find-tag)
(call-interactively 'find-tag))))
@@ -4485,9 +4496,9 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
;; without extension and directory matches the module.
;;
;; * `module:tag'
-;; Emacs 19: Replace test functions with functions aware of
-;; Erlang modules. Tricky because the etags system wasn't
-;; built for these kind of operations...
+;; Emacs 19: Replace test functions with functions aware of
+;; Erlang modules. Tricky because the etags system wasn't
+;; built for these kind of operations...
;;
;; Emacs 18: We loop over `find-tag' until we find a file
;; whose module matches the requested module. The
@@ -4506,78 +4517,78 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
;; know where to restart a tags command.
(if (boundp 'tags-loop-form)
(funcall (symbol-function 'set)
- 'tags-loop-form '(erlang-find-tag nil t)))
+ 'tags-loop-form '(erlang-find-tag nil t)))
(save-window-excursion
(cond
((string-match ":$" modtagname)
;; Only the module name was given. Read all files whose file name
;; match.
(let ((modname (substring modtagname 0 (match-beginning 0)))
- (file nil))
- (if (not next-p)
- (save-excursion
- (visit-tags-table-buffer)
- (setq erlang-tags-file-list
- (funcall (symbol-function 'tags-table-files)))))
- (while (null file)
- (or erlang-tags-file-list
- (save-excursion
- (if (and (featurep 'etags)
- (funcall
- (symbol-function 'visit-tags-table-buffer) 'same)
- (funcall
- (symbol-function 'visit-tags-table-buffer) t))
- (setq erlang-tags-file-list
- (funcall (symbol-function 'tags-table-files)))
- (error "No %stags containing %s" (if next-p "more " "")
- modtagname))))
- (if erlang-tags-file-list
- (let ((this-module (erlang-get-module-from-file-name
- (car erlang-tags-file-list))))
- (if (and (stringp this-module)
- (string= modname this-module))
- (setq file (car erlang-tags-file-list)))
- (setq erlang-tags-file-list (cdr erlang-tags-file-list)))))
- (set-buffer (or (get-file-buffer file)
- (find-file-noselect file)))))
+ (file nil))
+ (if (not next-p)
+ (save-excursion
+ (visit-tags-table-buffer)
+ (setq erlang-tags-file-list
+ (funcall (symbol-function 'tags-table-files)))))
+ (while (null file)
+ (or erlang-tags-file-list
+ (save-excursion
+ (if (and (featurep 'etags)
+ (funcall
+ (symbol-function 'visit-tags-table-buffer) 'same)
+ (funcall
+ (symbol-function 'visit-tags-table-buffer) t))
+ (setq erlang-tags-file-list
+ (funcall (symbol-function 'tags-table-files)))
+ (error "No %stags containing %s" (if next-p "more " "")
+ modtagname))))
+ (if erlang-tags-file-list
+ (let ((this-module (erlang-get-module-from-file-name
+ (car erlang-tags-file-list))))
+ (if (and (stringp this-module)
+ (string= modname this-module))
+ (setq file (car erlang-tags-file-list)))
+ (setq erlang-tags-file-list (cdr erlang-tags-file-list)))))
+ (set-buffer (or (get-file-buffer file)
+ (find-file-noselect file)))))
((string-match ":" modtagname)
(if (boundp 'find-tag-tag-order)
- ;; Method one: Add module-recognising functions to the
- ;; list of order functions. However, the tags system
- ;; from Emacs 18, and derives thereof (read: XEmacs)
- ;; hasn't got this feature.
- (progn
- (erlang-tags-install-module-check)
- (unwind-protect
- (funcall (symbol-function 'find-tag)
- modtagname next-p regexp-p)
- (erlang-tags-remove-module-check)))
- ;; Method two: Call the tags system until a file matching
- ;; the module is found. This could result in that many
- ;; files are read. (e.g. The tag "foo:file" will take a
- ;; while to process.)
- (let* ((modname (substring modtagname 0 (match-beginning 0)))
- (tagname (substring modtagname (match-end 0) nil))
- (last-tag tagname)
- file)
- (while
- (progn
- (funcall (symbol-function 'find-tag) tagname next-p regexp-p)
- (setq next-p t)
- ;; Determine the module form the file name. (The
- ;; alternative, to check `-module', would make this
- ;; code useless for non-Erlang programs.)
- (setq file (erlang-get-module-from-file-name buffer-file-name))
- (not (and (stringp file)
- (string= modname file))))))))
+ ;; Method one: Add module-recognising functions to the
+ ;; list of order functions. However, the tags system
+ ;; from Emacs 18, and derives thereof (read: XEmacs)
+ ;; hasn't got this feature.
+ (progn
+ (erlang-tags-install-module-check)
+ (unwind-protect
+ (funcall (symbol-function 'find-tag)
+ modtagname next-p regexp-p)
+ (erlang-tags-remove-module-check)))
+ ;; Method two: Call the tags system until a file matching
+ ;; the module is found. This could result in that many
+ ;; files are read. (e.g. The tag "foo:file" will take a
+ ;; while to process.)
+ (let* ((modname (substring modtagname 0 (match-beginning 0)))
+ (tagname (substring modtagname (match-end 0) nil))
+ (last-tag tagname)
+ file)
+ (while
+ (progn
+ (funcall (symbol-function 'find-tag) tagname next-p regexp-p)
+ (setq next-p t)
+ ;; Determine the module form the file name. (The
+ ;; alternative, to check `-module', would make this
+ ;; code useless for non-Erlang programs.)
+ (setq file (erlang-get-module-from-file-name buffer-file-name))
+ (not (and (stringp file)
+ (string= modname file))))))))
(t
(funcall (symbol-function 'find-tag) modtagname next-p regexp-p)))
- (current-buffer))) ; Return the new buffer.
+ (current-buffer))) ; Return the new buffer.
+
-
@@ -4594,18 +4605,18 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(require 'tags)))
(if current-prefix-arg
(list nil (if (< (prefix-numeric-value current-prefix-arg) 0)
- '-
- t))
+ '-
+ t))
(let* ((default (erlang-find-tag-default))
- (prompt (if default
- (format "%s(default %s) " prompt default)
- prompt))
- (spec (if (featurep 'etags)
- (completing-read prompt 'erlang-tags-complete-tag)
- (read-string prompt))))
+ (prompt (if default
+ (format "%s(default %s) " prompt default)
+ prompt))
+ (spec (if (featurep 'etags)
+ (completing-read prompt 'erlang-tags-complete-tag)
+ (read-string prompt))))
(list (if (equal spec "")
- (or default (error "There is no default tag"))
- spec)))))
+ (or default (error "There is no default tag"))
+ spec)))))
;; Search tag functions which are aware of Erlang modules. The tactic
@@ -4632,21 +4643,21 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(setq erlang-tags-orig-format-hooks
(symbol-value 'tags-table-format-hooks))
(funcall (symbol-function 'set) 'tags-table-format-hooks
- (cons 'erlang-tags-recognize-tags-table
- erlang-tags-orig-format-hooks))
+ (cons 'erlang-tags-recognize-tags-table
+ erlang-tags-orig-format-hooks))
(setq erlang-tags-buffer-list '())
- ))
-
+ ))
+
;; Install our functions in the TAGS files already resident.
(save-excursion
(let ((files (symbol-value 'tags-table-computed-list)))
(while files
- (if (stringp (car files))
- (if (get-file-buffer (car files))
- (progn
- (set-buffer (get-file-buffer (car files)))
- (erlang-tags-install-local))))
- (setq files (cdr files))))))
+ (if (stringp (car files))
+ (if (get-file-buffer (car files))
+ (progn
+ (set-buffer (get-file-buffer (car files)))
+ (erlang-tags-install-local))))
+ (setq files (cdr files))))))
(defun erlang-tags-install-local ()
@@ -4656,23 +4667,23 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
;; Mark this buffer as "installed" and record.
(set (make-local-variable 'erlang-tags-buffer-installed-p) t)
(setq erlang-tags-buffer-list
- (cons (current-buffer) erlang-tags-buffer-list))
+ (cons (current-buffer) erlang-tags-buffer-list))
;; Save the original values.
(set (make-local-variable 'erlang-tags-orig-tag-order)
- (symbol-value 'find-tag-tag-order))
+ (symbol-value 'find-tag-tag-order))
(set (make-local-variable 'erlang-tags-orig-regexp-tag-order)
- (symbol-value 'find-tag-regexp-tag-order))
+ (symbol-value 'find-tag-regexp-tag-order))
(set (make-local-variable 'erlang-tags-orig-search-function)
- (symbol-value 'find-tag-search-function))
+ (symbol-value 'find-tag-search-function))
(set (make-local-variable 'erlang-tags-orig-regexp-search-function)
- (symbol-value 'find-tag-regexp-search-function))
+ (symbol-value 'find-tag-regexp-search-function))
;; Install our own functions.
(set (make-local-variable 'find-tag-search-function)
- 'erlang-tags-search-forward)
+ 'erlang-tags-search-forward)
(set (make-local-variable 'find-tag-regexp-search-function)
- 'erlang-tags-regexp-search-forward)
+ 'erlang-tags-regexp-search-forward)
(set (make-local-variable 'find-tag-tag-order)
(mapcar #'erlang-make-order-function-aware-of-modules
erlang-tags-orig-tag-order))
@@ -4700,13 +4711,13 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(cond
((>= erlang-emacs-major-version 20)
(funcall (symbol-function 'set)
- 'tags-table-format-functions
- erlang-tags-orig-format-functions)
+ 'tags-table-format-functions
+ erlang-tags-orig-format-functions)
)
- (t
+ (t
(funcall (symbol-function 'set)
- 'tags-table-format-hooks
- erlang-tags-orig-format-hooks)
+ 'tags-table-format-hooks
+ erlang-tags-orig-format-hooks)
))
;; Remove our functions from the TAGS files. (Note that
@@ -4715,11 +4726,11 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(save-excursion
(let ((buffers erlang-tags-buffer-list))
(while buffers
- (if (buffer-name (car buffers))
- (progn
- (set-buffer (car buffers))
- (erlang-tags-remove-local)))
- (setq buffers (cdr buffers))))))
+ (if (buffer-name (car buffers))
+ (progn
+ (set-buffer (car buffers))
+ (erlang-tags-remove-local)))
+ (setq buffers (cdr buffers))))))
(defun erlang-tags-remove-local ()
@@ -4728,14 +4739,14 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
()
(funcall (symbol-function 'set) 'erlang-tags-buffer-installed-p nil)
(funcall (symbol-function 'set)
- 'find-tag-tag-order erlang-tags-orig-tag-order)
+ 'find-tag-tag-order erlang-tags-orig-tag-order)
(funcall (symbol-function 'set)
- 'find-tag-regexp-tag-order erlang-tags-orig-regexp-tag-order)
+ 'find-tag-regexp-tag-order erlang-tags-orig-regexp-tag-order)
(funcall (symbol-function 'set)
- 'find-tag-search-function erlang-tags-orig-search-function)
+ 'find-tag-search-function erlang-tags-orig-search-function)
(funcall (symbol-function 'set)
- 'find-tag-regexp-search-function
- erlang-tags-orig-regexp-search-function)))
+ 'find-tag-regexp-search-function
+ erlang-tags-orig-regexp-search-function)))
(defun erlang-tags-recognize-tags-table ()
@@ -4764,10 +4775,10 @@ for a tag on the form `module:tag'."
(if (string-match ":" tag)
(setq tag (substring tag (match-end 0) nil)))
(if (eq erlang-tags-orig-regexp-search-function
- 'erlang-tags-regexp-search-forward)
+ 'erlang-tags-regexp-search-forward)
(re-search-forward tag bound noerror count)
(funcall erlang-tags-orig-regexp-search-function
- tag bound noerror count)))
+ tag bound noerror count)))
;;; Tags completion, Emacs 19 `etags' specific.
;;;
@@ -4775,8 +4786,6 @@ for a tag on the form `module:tag'."
;;; completion-table' containing all normal tags plus tags on the form
;;; `module:tag' and `module:'.
-;; PENDING - Should probably make use of the
-;; `completion-at-point-functions' hook instead of this advice.
(when (and (locate-library "etags")
(require 'etags)
(fboundp 'etags-tags-completion-table)
@@ -4784,11 +4793,7 @@ for a tag on the form `module:tag'."
(if (fboundp 'advice-add)
;; Emacs 24.4+
(advice-add 'etags-tags-completion-table :around
- (lambda (oldfun)
- (if erlang-replace-etags-tags-completion-table
- (erlang-etags-tags-completion-table)
- (funcall oldfun)))
- (list :name 'erlang-replace-tags-table))
+ #'erlang-etags-tags-completion-table-advice)
;; Emacs 23.1-24.3
(defadvice etags-tags-completion-table (around
erlang-replace-tags-table
@@ -4797,6 +4802,11 @@ for a tag on the form `module:tag'."
(setq ad-return-value (erlang-etags-tags-completion-table))
ad-do-it))))
+(defun erlang-etags-tags-completion-table-advice (oldfun)
+ (if erlang-replace-etags-tags-completion-table
+ (erlang-etags-tags-completion-table)
+ (funcall oldfun)))
+
(defun erlang-complete-tag ()
"Perform tags completion on the text around point.
Completes to the set of names listed in the current tags table.
@@ -4807,26 +4817,25 @@ about Erlang modules."
(condition-case nil
(require 'etags)
(error nil))
- (cond ((and erlang-tags-installed
- (fboundp 'etags-tags-completion-table)
+ (cond ((and (fboundp 'etags-tags-completion-table)
(fboundp 'tags-lazy-completion-table)) ; Emacs 23.1+
(let ((erlang-replace-etags-tags-completion-table t))
(complete-tag)))
((and erlang-tags-installed
(fboundp 'complete-tag)
(fboundp 'tags-complete-tag)) ; Emacs 19-22
- (let ((orig-tags-complete-tag (symbol-function 'tags-complete-tag)))
- (fset 'tags-complete-tag
- (symbol-function 'erlang-tags-complete-tag))
- (unwind-protect
+ (let ((orig-tags-complete-tag (symbol-function 'tags-complete-tag)))
+ (fset 'tags-complete-tag
+ (symbol-function 'erlang-tags-complete-tag))
+ (unwind-protect
(complete-tag)
- (fset 'tags-complete-tag orig-tags-complete-tag))))
- ((fboundp 'complete-tag) ; Emacs 19
+ (fset 'tags-complete-tag orig-tags-complete-tag))))
+ ((fboundp 'complete-tag) ; Emacs 19
(complete-tag))
- ((fboundp 'tag-complete-symbol) ; XEmacs
- (funcall (symbol-function 'tag-complete-symbol)))
- (t
- (error "This version of Emacs can't complete tags"))))
+ ((fboundp 'tag-complete-symbol) ; XEmacs
+ (funcall (symbol-function 'tag-complete-symbol)))
+ (t
+ (error "This version of Emacs can't complete tags"))))
(defun erlang-find-tag-for-completion ()
@@ -4850,9 +4859,9 @@ about Erlang modules."
;; If we need to ask for the tag table, allow that.
(let ((enable-recursive-minibuffers t))
(visit-tags-table-buffer))
- (if (eq what t)
- (all-completions string (erlang-tags-completion-table) predicate)
- (try-completion string (erlang-tags-completion-table) predicate)))))
+ (if (eq what t)
+ (all-completions string (erlang-tags-completion-table) predicate)
+ (try-completion string (erlang-tags-completion-table) predicate)))))
;; `tags-completion-table' calls itself recursively, make it
@@ -4862,22 +4871,22 @@ about Erlang modules."
(defun erlang-tags-completion-table ()
"Build completion table. Tags on the form `tag' or `module:tag'."
(setq erlang-tags-orig-completion-table
- (symbol-function 'tags-completion-table))
+ (symbol-function 'tags-completion-table))
(fset 'tags-completion-table
- (symbol-function 'erlang-tags-completion-table-1))
+ (symbol-function 'erlang-tags-completion-table-1))
(unwind-protect
(erlang-tags-completion-table-1)
(fset 'tags-completion-table
- erlang-tags-orig-completion-table)))
+ erlang-tags-orig-completion-table)))
(defun erlang-tags-completion-table-1 ()
(make-local-variable 'erlang-tags-completion-table)
(or erlang-tags-completion-table
(let ((tags-completion-table nil)
- (tags-completion-table-function
- 'erlang-etags-tags-completion-table))
- (funcall erlang-tags-orig-completion-table)
- (setq erlang-tags-completion-table tags-completion-table))))
+ (tags-completion-table-function
+ 'erlang-etags-tags-completion-table))
+ (funcall erlang-tags-orig-completion-table)
+ (setq erlang-tags-completion-table tags-completion-table))))
@@ -4978,7 +4987,7 @@ about Erlang modules."
(cl-defmethod xref-backend-identifier-completion-table
((_backend (eql erlang-etags)))
(let ((erlang-replace-etags-tags-completion-table t))
- (tags-completion-table))))))
+ (tags-completion-table))))))
@@ -5213,44 +5222,36 @@ The following special commands are available:
(setq comint-input-ignoredups t)
(setq comint-scroll-show-maximum-output t)
(setq comint-scroll-to-bottom-on-output t)
- ;; In Emacs 19.30, `add-hook' has got a `local' flag, use it. If
- ;; the call fails, just call the normal `add-hook'.
- (condition-case nil
- (progn
- (add-hook 'comint-output-filter-functions
- 'inferior-erlang-strip-delete nil t)
- (add-hook 'comint-output-filter-functions
- 'inferior-erlang-strip-ctrl-m nil t))
- (error
- (funcall (symbol-function 'make-local-hook)
- 'comint-output-filter-functions) ; obsolete as of Emacs 21.1
- (add-hook 'comint-output-filter-functions 'inferior-erlang-strip-delete)
- (add-hook 'comint-output-filter-functions 'inferior-erlang-strip-ctrl-m)))
+ (add-hook 'comint-output-filter-functions
+ 'inferior-erlang-strip-delete nil t)
+ (add-hook 'comint-output-filter-functions
+ 'inferior-erlang-strip-ctrl-m nil t)
;; Some older versions of comint don't have an input ring.
(if (fboundp 'comint-read-input-ring)
(progn
- (setq comint-input-ring-file-name erlang-input-ring-file-name)
- (comint-read-input-ring t)
- (make-local-variable 'kill-buffer-hook)
- (add-hook 'kill-buffer-hook 'comint-write-input-ring)))
+ (setq comint-input-ring-file-name erlang-input-ring-file-name)
+ (comint-read-input-ring t)
+ (make-local-variable 'kill-buffer-hook)
+ (add-hook 'kill-buffer-hook 'comint-write-input-ring)))
;; At least in Emacs 21, we need to be in `compilation-minor-mode'
;; for `next-error' to work. We can avoid it clobbering the shell
;; keys thus.
(when inferior-erlang-use-cmm
(compilation-minor-mode 1)
(set (make-local-variable 'minor-mode-overriding-map-alist)
- `((compilation-minor-mode
- . ,(let ((map (make-sparse-keymap)))
- ;; It would be useful to put keymap properties on the
- ;; error lines so that we could use RET and mouse-2
- ;; on them directly.
- (when (boundp 'compilation-skip-threshold) ; new compile.el
- (define-key map [mouse-2] #'erlang-mouse-2-command)
- (define-key map "\C-m" #'erlang-RET-command))
- (if (boundp 'compilation-menu-map)
- (define-key map [menu-bar compilation]
- (cons "Errors" compilation-menu-map)))
- map)))))
+ `((compilation-minor-mode
+ . ,(let ((map (make-sparse-keymap)))
+ ;; It would be useful to put keymap properties on the
+ ;; error lines so that we could use RET and mouse-2
+ ;; on them directly.
+ (when (boundp 'compilation-skip-threshold) ; new compile.el
+ (define-key map [mouse-2] #'erlang-mouse-2-command)
+ (define-key map "\C-m" #'erlang-RET-command))
+ (if (boundp 'compilation-menu-map)
+ (define-key map [menu-bar compilation]
+ (cons "Errors" compilation-menu-map)))
+ map)))))
+ (erlang-tags-init)
(run-hooks 'erlang-shell-mode-hook))
@@ -5259,9 +5260,9 @@ The following special commands are available:
Selects Comint or Compilation mode command as appropriate."
(interactive "e")
(if (save-window-excursion
- (save-excursion
- (mouse-set-point event)
- (consp (get-text-property (line-beginning-position) 'message))))
+ (save-excursion
+ (mouse-set-point event)
+ (consp (get-text-property (line-beginning-position) 'message))))
(call-interactively (lookup-key compilation-mode-map [mouse-2]))
(call-interactively (lookup-key comint-mode-map [mouse-2]))))
@@ -5277,7 +5278,7 @@ Selects Comint or Compilation mode command as appropriate."
(define-key map "\M-\t" 'erlang-complete-tag)
(define-key map "\C-a" 'comint-bol) ; Normally the other way around.
(define-key map "\C-c\C-a" 'beginning-of-line)
- (define-key map "\C-d" nil) ; Was `comint-delchar-or-maybe-eof'
+ (define-key map "\C-d" nil) ; Was `comint-delchar-or-maybe-eof'
(define-key map "\M-\C-m" 'compile-goto-error)
(unless inferior-erlang-use-cmm
(define-key map "\C-x`" 'erlang-next-error)))
@@ -5351,8 +5352,8 @@ editing control characters:
(when current-prefix-arg
(list (if (fboundp 'read-shell-command)
;; `read-shell-command' is a new function in Emacs 23.
- (read-shell-command "Erlang command: ")
- (read-string "Erlang command: ")))))
+ (read-shell-command "Erlang command: ")
+ (read-string "Erlang command: ")))))
(require 'comint)
(let (cmd opts)
(if command
@@ -5379,16 +5380,16 @@ editing control characters:
(setq list-buffers-directory fake-file-name))))
(setq inferior-erlang-process
- (get-buffer-process inferior-erlang-buffer))
- (if (> 21 erlang-emacs-major-version) ; funcalls to avoid compiler warnings
- (funcall (symbol-function 'set-process-query-on-exit-flag)
- inferior-erlang-process nil)
+ (get-buffer-process inferior-erlang-buffer))
+ (if (> 21 erlang-emacs-major-version) ; funcalls to avoid compiler warnings
+ (funcall (symbol-function 'set-process-query-on-exit-flag)
+ inferior-erlang-process nil)
(funcall (symbol-function 'process-kill-without-query) inferior-erlang-process))
(if erlang-inferior-shell-split-window
(switch-to-buffer-other-window inferior-erlang-buffer)
- (switch-to-buffer inferior-erlang-buffer))
+ (switch-to-buffer inferior-erlang-buffer))
(if (and (not (eq system-type 'windows-nt))
- (eq inferior-erlang-shell-type 'newshell))
+ (eq inferior-erlang-shell-type 'newshell))
(setq comint-process-echoes t))
(erlang-shell-mode))
@@ -5420,22 +5421,22 @@ frame will become deselected before the next command."
(or (inferior-erlang-running-p)
(error "No inferior Erlang process is running"))
(let ((win (inferior-erlang-window
- inferior-erlang-display-buffer-any-frame))
- (frames-p (fboundp 'selected-frame)))
+ inferior-erlang-display-buffer-any-frame))
+ (frames-p (fboundp 'selected-frame)))
(if (null win)
- (let ((old-win (selected-window)))
- (save-excursion
- (switch-to-buffer-other-window inferior-erlang-buffer)
- (setq win (selected-window)))
- (select-window old-win))
+ (let ((old-win (selected-window)))
+ (save-excursion
+ (switch-to-buffer-other-window inferior-erlang-buffer)
+ (setq win (selected-window)))
+ (select-window old-win))
(if (and window-system
- frames-p
- (or select
- (eq inferior-erlang-display-buffer-any-frame 'raise))
- (not (eq (selected-frame) (window-frame win))))
- (raise-frame (window-frame win))))
+ frames-p
+ (or select
+ (eq inferior-erlang-display-buffer-any-frame 'raise))
+ (not (eq (selected-frame) (window-frame win))))
+ (raise-frame (window-frame win))))
(if select
- (select-window win))
+ (select-window win))
(sit-for 0)
win))
@@ -5452,8 +5453,8 @@ frame will become deselected before the next command."
"Return the window containing the inferior Erlang, or nil."
(and (inferior-erlang-running-p)
(if (and all-frames (>= erlang-emacs-major-version 19))
- (get-buffer-window inferior-erlang-buffer t)
- (get-buffer-window inferior-erlang-buffer))))
+ (get-buffer-window inferior-erlang-buffer t)
+ (get-buffer-window inferior-erlang-buffer))))
(defun inferior-erlang-wait-prompt ()
@@ -5461,21 +5462,21 @@ frame will become deselected before the next command."
(if (eq inferior-erlang-prompt-timeout t)
()
(or (inferior-erlang-running-p)
- (error "No inferior Erlang shell is running"))
+ (error "No inferior Erlang shell is running"))
(with-current-buffer inferior-erlang-buffer
(let ((msg nil))
- (while (save-excursion
- (goto-char (process-mark inferior-erlang-process))
- (forward-line 0)
- (not (looking-at comint-prompt-regexp)))
- (if msg
- ()
- (setq msg t)
- (message "Waiting for Erlang shell prompt (press C-g to abort)."))
- (or (accept-process-output inferior-erlang-process
- inferior-erlang-prompt-timeout)
- (error "No Erlang shell prompt before timeout")))
- (if msg (message ""))))))
+ (while (save-excursion
+ (goto-char (process-mark inferior-erlang-process))
+ (forward-line 0)
+ (not (looking-at comint-prompt-regexp)))
+ (if msg
+ ()
+ (setq msg t)
+ (message "Waiting for Erlang shell prompt (press C-g to abort)."))
+ (or (accept-process-output inferior-erlang-process
+ inferior-erlang-prompt-timeout)
+ (error "No Erlang shell prompt before timeout")))
+ (if msg (message ""))))))
(defun inferior-erlang-send-empty-cmd-unless-already-at-prompt ()
"If not already at a prompt, try to send an empty cmd to get a prompt.
@@ -5484,12 +5485,12 @@ situations, for instance if a crash or error report from sasl
has been printed after the last prompt."
(with-current-buffer inferior-erlang-buffer
(if (> (point-max) 1)
- ;; make sure we get a prompt if buffer contains data
- (if (save-excursion
- (goto-char (process-mark inferior-erlang-process))
- (forward-line 0)
- (not (looking-at comint-prompt-regexp)))
- (inferior-erlang-send-command "")))))
+ ;; make sure we get a prompt if buffer contains data
+ (if (save-excursion
+ (goto-char (process-mark inferior-erlang-process))
+ (forward-line 0)
+ (not (looking-at comint-prompt-regexp)))
+ (inferior-erlang-send-command "")))))
(autoload 'comint-send-input "comint")
@@ -5506,10 +5507,10 @@ Return the position after the newly inserted command."
(or (inferior-erlang-running-p)
(error "No inferior Erlang process is running"))
(let ((old-buffer (current-buffer))
- (insert-point (marker-position (process-mark inferior-erlang-process)))
- (insert-length (if comint-process-echoes
- 0
- (1+ (length cmd)))))
+ (insert-point (marker-position (process-mark inferior-erlang-process)))
+ (insert-length (if comint-process-echoes
+ 0
+ (1+ (length cmd)))))
(set-buffer inferior-erlang-buffer)
(goto-char insert-point)
(insert cmd)
@@ -5522,21 +5523,21 @@ Return the position after the newly inserted command."
;; This was previously cautioned against in the Lisp manual. It
;; has been sorted out in Emacs 21. -- fx
(let ((comint-eol-on-send nil)
- (comint-input-filter (if hist comint-input-filter 'ignore)))
+ (comint-input-filter (if hist comint-input-filter 'ignore)))
(if (and (not erlang-xemacs-p)
- (>= emacs-major-version 22))
- (comint-send-input nil t)
- (comint-send-input)))
+ (>= emacs-major-version 22))
+ (comint-send-input nil t)
+ (comint-send-input)))
;; Adjust all windows whose points are incorrect.
(if (null comint-process-echoes)
- (walk-windows
- (function
- (lambda (window)
- (if (and (eq (window-buffer window) inferior-erlang-buffer)
- (= (window-point window) insert-point))
- (set-window-point window
- (+ insert-point insert-length)))))
- nil t))
+ (walk-windows
+ (function
+ (lambda (window)
+ (if (and (eq (window-buffer window) inferior-erlang-buffer)
+ (= (window-point window) insert-point))
+ (set-window-point window
+ (+ insert-point insert-length)))))
+ nil t))
(set-buffer old-buffer)
(+ insert-point insert-length)))
@@ -5545,17 +5546,17 @@ Return the position after the newly inserted command."
"Remove `^H' (delete) and the characters it was supposed to remove."
(interactive)
(if (and (boundp 'comint-last-input-end)
- (boundp 'comint-last-output-start))
+ (boundp 'comint-last-output-start))
(save-excursion
- (goto-char
- (if (erlang-interactive-p)
- (symbol-value 'comint-last-input-end)
- (symbol-value 'comint-last-output-start)))
- (while (progn (skip-chars-forward "^\C-h")
- (not (eq (point) (point-max))))
- (delete-char 1)
- (or (bolp)
- (backward-delete-char 1))))))
+ (goto-char
+ (if (erlang-interactive-p)
+ (symbol-value 'comint-last-input-end)
+ (symbol-value 'comint-last-output-start)))
+ (while (progn (skip-chars-forward "^\C-h")
+ (not (eq (point) (point-max))))
+ (delete-char 1)
+ (or (bolp)
+ (backward-delete-char 1))))))
;; Basically `comint-strip-ctrl-m', with a few extra checks.
@@ -5563,15 +5564,15 @@ Return the position after the newly inserted command."
"Strip trailing `^M' characters from the current output group."
(interactive)
(if (and (boundp 'comint-last-input-end)
- (boundp 'comint-last-output-start))
+ (boundp 'comint-last-output-start))
(let ((pmark (process-mark (get-buffer-process (current-buffer)))))
- (save-excursion
- (goto-char
- (if (erlang-interactive-p)
- (symbol-value 'comint-last-input-end)
- (symbol-value 'comint-last-output-start)))
- (while (re-search-forward "\r+$" pmark t)
- (replace-match "" t t))))))
+ (save-excursion
+ (goto-char
+ (if (erlang-interactive-p)
+ (symbol-value 'comint-last-input-end)
+ (symbol-value 'comint-last-output-start)))
+ (while (re-search-forward "\r+$" pmark t)
+ (replace-match "" t t))))))
(defun inferior-erlang-compile (arg)
@@ -5594,18 +5595,18 @@ There exists two workarounds for this bug:
(save-some-buffers)
(inferior-erlang-prepare-for-input)
(let* ((dir (inferior-erlang-compile-outdir))
- (noext (substring (erlang-local-buffer-file-name) 0 -4))
- (opts (append (list (cons 'outdir dir))
- (if current-prefix-arg
- (list 'debug_info 'export_all))
- erlang-compile-extra-opts))
- end)
+ (noext (substring (erlang-local-buffer-file-name) 0 -4))
+ (opts (append (list (cons 'outdir dir))
+ (if current-prefix-arg
+ (list 'debug_info 'export_all))
+ erlang-compile-extra-opts))
+ end)
(with-current-buffer inferior-erlang-buffer
(when (fboundp 'compilation-forget-errors)
(compilation-forget-errors)))
(setq end (inferior-erlang-send-command
- (inferior-erlang-compute-compile-command noext opts)
- nil))
+ (inferior-erlang-compute-compile-command noext opts)
+ nil))
(sit-for 0)
(inferior-erlang-wait-prompt)
(with-current-buffer inferior-erlang-buffer
@@ -5619,7 +5620,7 @@ The buffer is displayed, according to `inferior-erlang-display-buffer'
unless the optional NO-DISPLAY is non-nil."
(or (inferior-erlang-running-p)
(save-excursion
- (inferior-erlang)))
+ (inferior-erlang)))
(or (inferior-erlang-running-p)
(error "Error starting inferior Erlang shell"))
(if (not no-display)
@@ -5631,96 +5632,96 @@ unless the optional NO-DISPLAY is non-nil."
(defun inferior-erlang-compile-outdir ()
"Return the directory to compile the current buffer into."
(let* ((buffer-dir (directory-file-name
- (file-name-directory (erlang-local-buffer-file-name))))
- (parent-dir (directory-file-name
- (file-name-directory buffer-dir)))
+ (file-name-directory (erlang-local-buffer-file-name))))
+ (parent-dir (directory-file-name
+ (file-name-directory buffer-dir)))
(ebin-dir (concat (file-name-as-directory parent-dir) "ebin"))
- (buffer-dir-base-name (file-name-nondirectory
- (expand-file-name
- (concat (file-name-as-directory buffer-dir)
- ".")))))
+ (buffer-dir-base-name (file-name-nondirectory
+ (expand-file-name
+ (concat (file-name-as-directory buffer-dir)
+ ".")))))
(if (and (string= buffer-dir-base-name "src")
- (file-directory-p ebin-dir))
- (file-name-as-directory ebin-dir)
+ (file-directory-p ebin-dir))
+ (file-name-as-directory ebin-dir)
(file-name-as-directory buffer-dir))))
(defun inferior-erlang-compute-compile-command (module-name opts)
(let ((ccfn erlang-compile-command-function-alist)
- (res (inferior-erlang-compute-erl-compile-command module-name opts))
- ccfn-entry
- done
+ (res (inferior-erlang-compute-erl-compile-command module-name opts))
+ ccfn-entry
+ done
result)
(if (not (null (erlang-local-buffer-file-name)))
- (while (and (not done) (not (null ccfn)))
- (setq ccfn-entry (car ccfn))
- (setq ccfn (cdr ccfn))
- (if (string-match (car ccfn-entry) (erlang-local-buffer-file-name))
- (let ((c-fn (cdr ccfn-entry)))
- (setq done t)
- (if (not (null c-fn))
- (setq result (funcall c-fn module-name opts)))))))
+ (while (and (not done) (not (null ccfn)))
+ (setq ccfn-entry (car ccfn))
+ (setq ccfn (cdr ccfn))
+ (if (string-match (car ccfn-entry) (erlang-local-buffer-file-name))
+ (let ((c-fn (cdr ccfn-entry)))
+ (setq done t)
+ (if (not (null c-fn))
+ (setq result (funcall c-fn module-name opts)))))))
result))
(defun inferior-erlang-compute-erl-compile-command (module-name opts)
(let* ((out-dir-opt (assoc 'outdir opts))
- (out-dir (cdr out-dir-opt)))
+ (out-dir (cdr out-dir-opt)))
(if erlang-compile-use-outdir
- (format "%s(\"%s\"%s)."
- erlang-compile-erlang-function
- module-name
- (inferior-erlang-format-comma-opts opts))
+ (format "%s(\"%s\"%s)."
+ erlang-compile-erlang-function
+ module-name
+ (inferior-erlang-format-comma-opts opts))
(let (;; Hopefully, noone else will ever use these...
- (tmpvar "Tmp7236")
- (tmpvar2 "Tmp8742"))
- (format
- (concat
- "f(%s), {ok, %s} = file:get_cwd(), "
- "file:set_cwd(\"%s\"), "
- "%s = %s(\"%s\"%s), file:set_cwd(%s), f(%s), %s.")
- tmpvar2 tmpvar
- out-dir
- tmpvar2
- erlang-compile-erlang-function
- module-name (inferior-erlang-format-comma-opts
- (remq out-dir-opt opts))
- tmpvar tmpvar tmpvar2)))))
+ (tmpvar "Tmp7236")
+ (tmpvar2 "Tmp8742"))
+ (format
+ (concat
+ "f(%s), {ok, %s} = file:get_cwd(), "
+ "file:set_cwd(\"%s\"), "
+ "%s = %s(\"%s\"%s), file:set_cwd(%s), f(%s), %s.")
+ tmpvar2 tmpvar
+ out-dir
+ tmpvar2
+ erlang-compile-erlang-function
+ module-name (inferior-erlang-format-comma-opts
+ (remq out-dir-opt opts))
+ tmpvar tmpvar tmpvar2)))))
(defun inferior-erlang-compute-leex-compile-command (module-name opts)
(let ((file-name (erlang-local-buffer-file-name))
- (erl-compile-expr (inferior-erlang-remove-any-trailing-dot
- (inferior-erlang-compute-erl-compile-command
- module-name opts))))
+ (erl-compile-expr (inferior-erlang-remove-any-trailing-dot
+ (inferior-erlang-compute-erl-compile-command
+ module-name opts))))
(format (concat "f(LErr1__), f(LErr2__), "
- "case case leex:file(\"%s\", [%s]) of"
- " ok -> ok;"
- " {ok,_} -> ok;"
- " {ok,_,_} -> ok;"
- " LErr1__ -> LErr1__ "
- "end of"
- " ok -> %s;"
- " LErr2__ -> LErr2__ "
- "end.")
- file-name
- (inferior-erlang-format-comma-opts erlang-leex-compile-opts)
- erl-compile-expr)))
+ "case case leex:file(\"%s\", [%s]) of"
+ " ok -> ok;"
+ " {ok,_} -> ok;"
+ " {ok,_,_} -> ok;"
+ " LErr1__ -> LErr1__ "
+ "end of"
+ " ok -> %s;"
+ " LErr2__ -> LErr2__ "
+ "end.")
+ file-name
+ (inferior-erlang-format-comma-opts erlang-leex-compile-opts)
+ erl-compile-expr)))
(defun inferior-erlang-compute-yecc-compile-command (module-name opts)
(let ((file-name (erlang-local-buffer-file-name))
- (erl-compile-expr (inferior-erlang-remove-any-trailing-dot
- (inferior-erlang-compute-erl-compile-command
- module-name opts))))
+ (erl-compile-expr (inferior-erlang-remove-any-trailing-dot
+ (inferior-erlang-compute-erl-compile-command
+ module-name opts))))
(format (concat "f(YErr1__), f(YErr2__), "
- "case case yecc:file(\"%s\", [%s]) of"
- " {ok,_} -> ok;"
- " {ok,_,_} -> ok;"
- " YErr1__ -> YErr1__ "
- "end of"
- " ok -> %s;"
- " YErr2__ -> YErr2__ "
- "end.")
- file-name
- (inferior-erlang-format-comma-opts erlang-yecc-compile-opts)
- erl-compile-expr)))
+ "case case yecc:file(\"%s\", [%s]) of"
+ " {ok,_} -> ok;"
+ " {ok,_,_} -> ok;"
+ " YErr1__ -> YErr1__ "
+ "end of"
+ " ok -> %s;"
+ " YErr2__ -> YErr2__ "
+ "end.")
+ file-name
+ (inferior-erlang-format-comma-opts erlang-yecc-compile-opts)
+ erl-compile-expr)))
(defun inferior-erlang-remove-any-trailing-dot (str)
(if (string= (substring str -1) ".")
@@ -5730,31 +5731,29 @@ unless the optional NO-DISPLAY is non-nil."
(defun inferior-erlang-format-comma-opts (opts)
(if (null opts)
""
- (concat ", " (inferior-erlang-format-opts opts))))
-
-(defun inferior-erlang-format-opts (opts)
- (concat "[" (inferior-erlang-string-join (mapcar 'inferior-erlang-format-opt
- opts)
- ", ")
- "]"))
+ (concat ", " (inferior-erlang-format-opt opts))))
(defun inferior-erlang-format-opt (opt)
(cond ((stringp opt) (concat "\"" opt "\""))
- ((atom opt) (format "%s" opt))
- ((consp opt) (concat "{" (inferior-erlang-string-join
- (mapcar 'inferior-erlang-format-opt
- (list (car opt) (cdr opt)))
- ", ")
- "}"))
- (t (error (format "Unexpected opt %s" opt)))))
-
-(defun inferior-erlang-string-join (strs sep)
- (let ((result (or (car strs) "")))
- (setq strs (cdr strs))
- (while strs
- (setq result (concat result sep (car strs)))
- (setq strs (cdr strs)))
- result))
+ ((vectorp opt) (inferior-erlang-tuple (append opt nil)))
+ ((atom opt) (format "%s" opt))
+ ((consp opt) (if (listp (cdr opt))
+ (inferior-erlang-list opt)
+ (inferior-erlang-tuple (list (car opt) (cdr opt)))))
+ (t (error "Unexpected erlang compile option %s" opt))))
+
+(defun inferior-erlang-tuple (opts)
+ (concat "{" (mapconcat 'inferior-erlang-format-opt
+ opts
+ ", ")
+ "}"))
+
+(defun inferior-erlang-list (opts)
+ (concat "[" (mapconcat 'inferior-erlang-format-opt
+ opts
+ ", ")
+ "]"))
+
(defun erlang-local-buffer-file-name ()
;; When editing a file remotely via tramp,
@@ -5768,11 +5767,11 @@ unless the optional NO-DISPLAY is non-nil."
;; the file name "/some/path/x.erl" without the
;; tramp-prefix "/ssh:host.example.com:".
(cond ((null (buffer-file-name))
- nil)
- ((erlang-tramp-remote-file-p)
- (erlang-tramp-get-localname))
- (t
- (buffer-file-name))))
+ nil)
+ ((erlang-tramp-remote-file-p)
+ (erlang-tramp-get-localname))
+ (t
+ (buffer-file-name))))
(defun erlang-tramp-remote-file-p ()
(and (fboundp 'tramp-tramp-file-p)
@@ -5798,22 +5797,22 @@ unless the optional NO-DISPLAY is non-nil."
Capable of finding error messages in an inferior Erlang buffer."
(interactive "P")
(let ((done nil)
- (buf (or (and (boundp 'next-error-last-buffer)
- next-error-last-buffer)
- (and (boundp 'compilation-last-buffer)
- compilation-last-buffer))))
+ (buf (or (and (boundp 'next-error-last-buffer)
+ next-error-last-buffer)
+ (and (boundp 'compilation-last-buffer)
+ compilation-last-buffer))))
(if (and (bufferp buf)
- (with-current-buffer buf
- (and (eq major-mode 'erlang-shell-mode)
- (setq major-mode 'compilation-mode))))
- (unwind-protect
- (progn
- (setq done t)
- (next-error argp))
- (with-current-buffer buf
- (setq major-mode 'erlang-shell-mode))))
+ (with-current-buffer buf
+ (and (eq major-mode 'erlang-shell-mode)
+ (setq major-mode 'compilation-mode))))
+ (unwind-protect
+ (progn
+ (setq done t)
+ (next-error argp))
+ (with-current-buffer buf
+ (setq major-mode 'erlang-shell-mode))))
(or done
- (next-error argp))))
+ (next-error argp))))
(defun inferior-erlang-change-directory (&optional dir)
@@ -5850,44 +5849,44 @@ sum([], Sum) -> Sum."
(interactive "r")
(save-excursion
(let (;; regexp for matching arrows. without a prefix argument,
- ;; the regexp matches function heads. With a prefix, it
- ;; matches any arrow.
- (re (if current-prefix-arg
- "^.*\\(\\)->"
- (eval-when-compile
- (concat "^" erlang-atom-regexp ".*\\(\\)->"))))
- ;; part of regexp matching directly before the arrow
- (arrow-match-pos (if current-prefix-arg
- 1
- (1+ erlang-atom-regexp-matches)))
- ;; accumulator for positions where arrows are found, ordered
- ;; by buffer position (from greatest to smallest)
- (arrow-positions '())
- ;; accumulator for longest distance from start of line to arrow
- (most-indent 0)
- ;; marker to track the end of the region we're aligning
- (end-marker (progn (goto-char end)
- (point-marker))))
+ ;; the regexp matches function heads. With a prefix, it
+ ;; matches any arrow.
+ (re (if current-prefix-arg
+ "^.*\\(\\)->"
+ (eval-when-compile
+ (concat "^" erlang-atom-regexp ".*\\(\\)->"))))
+ ;; part of regexp matching directly before the arrow
+ (arrow-match-pos (if current-prefix-arg
+ 1
+ (1+ erlang-atom-regexp-matches)))
+ ;; accumulator for positions where arrows are found, ordered
+ ;; by buffer position (from greatest to smallest)
+ (arrow-positions '())
+ ;; accumulator for longest distance from start of line to arrow
+ (most-indent 0)
+ ;; marker to track the end of the region we're aligning
+ (end-marker (progn (goto-char end)
+ (point-marker))))
;; Pass 1: Find the arrow positions, adjust the whitespace
;; before each arrow to one space, and find the greatest
;; indentation level.
(goto-char start)
(while (re-search-forward re end-marker t)
- (goto-char (match-beginning arrow-match-pos))
- (just-one-space) ; adjust whitespace
- (setq arrow-positions (cons (point) arrow-positions))
- (setq most-indent (max most-indent (erlang-column-number))))
- (set-marker end-marker nil) ; free the marker
+ (goto-char (match-beginning arrow-match-pos))
+ (just-one-space) ; adjust whitespace
+ (setq arrow-positions (cons (point) arrow-positions))
+ (setq most-indent (max most-indent (erlang-column-number))))
+ (set-marker end-marker nil) ; free the marker
;; Pass 2: Insert extra padding so that all arrow indentation is
;; equal. This is done last-to-first by buffer position, so that
;; inserting spaces before one arrow doesn't change the
;; positions of the next ones.
(mapc (lambda (arrow-pos)
- (goto-char arrow-pos)
- (let* ((pad (- most-indent (erlang-column-number))))
- (when (> pad 0)
- (insert-char ?\ pad))))
- arrow-positions))))
+ (goto-char arrow-pos)
+ (let* ((pad (- most-indent (erlang-column-number))))
+ (when (> pad 0)
+ (insert-char ?\ pad))))
+ arrow-positions))))
(defun erlang-column-number ()
"Return the column number of the current position in the buffer.
@@ -5899,7 +5898,7 @@ Tab characters are counted by their visual width."
(save-excursion
(erlang-beginning-of-function)
(if (looking-at "[a-z0-9_]+")
- (match-string 0))))
+ (match-string 0))))
;; Aliases for backward compatibility with older versions of Erlang Mode.
;;
@@ -5918,7 +5917,7 @@ it assumes that NEWDEF is loaded."
(erlang-obsolete 'calculate-erlang-indent 'erlang-calculate-indent)
(erlang-obsolete 'calculate-erlang-stack-indent
- 'erlang-calculate-stack-indent)
+ 'erlang-calculate-stack-indent)
(erlang-obsolete 'at-erlang-keyword 'erlang-at-keyword)
(erlang-obsolete 'at-erlang-operator 'erlang-at-operator)
(erlang-obsolete 'beginning-of-erlang-clause 'erlang-beginning-of-clause)
@@ -5933,12 +5932,12 @@ it assumes that NEWDEF is loaded."
(defconst erlang-unload-hook
(list (lambda ()
- (when (featurep 'advice)
- (ad-unadvise 'Man-notify-when-ready)
- (ad-unadvise 'set-visited-file-name)))))
+ (when (featurep 'advice)
+ (ad-unadvise 'Man-notify-when-ready)
+ (ad-unadvise 'set-visited-file-name)))))
-(defun erlang-string-to-int (string)
+(defun erlang-string-to-int (string)
(if (fboundp 'string-to-number)
(string-to-number string)
(funcall (symbol-function 'string-to-int) string)))
@@ -5951,6 +5950,7 @@ it assumes that NEWDEF is loaded."
;; Local variables:
;; coding: iso-8859-1
+;; indent-tabs-mode: nil
;; End:
;;; erlang.el ends here
diff --git a/lib/tools/emacs/erldoc.el b/lib/tools/emacs/erldoc.el
new file mode 100644
index 0000000000..cb355374d9
--- /dev/null
+++ b/lib/tools/emacs/erldoc.el
@@ -0,0 +1,508 @@
+;;; erldoc.el --- browse Erlang/OTP documentation -*- lexical-binding: t; -*-
+
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2016. All Rights Reserved.
+;;
+;; Licensed under the Apache License, Version 2.0 (the "License");
+;; you may not use this file except in compliance with the License.
+;; You may obtain a copy of the License at
+;;
+;; http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
+;;
+;; %CopyrightEnd%
+
+;;; Commentary:
+
+;; Crawl Erlang/OTP HTML documentation and generate lookup tables.
+;;
+;; This package depends on `cl-lib', `pcase' and
+;; `libxml-parse-html-region'; emacs 24+ compiled with libxml2 should
+;; work. On emacs 24.1 and 24.2 do `M-x package-install RET cl-lib
+;; RET' to install `cl-lib'.
+;;
+;; Please customise `erldoc-man-index' to point to your local OTP
+;; documentation.
+;;
+;; To use:
+;;
+;; (define-key help-map "u" 'erldoc-browse)
+;; (define-key help-map "t" 'erldoc-browse-topic)
+;; (define-key help-map "a" 'erldoc-apropos)
+;;
+;; Note: these commands trigger indexing OTP documentation on first
+;; run with cache to disk which may take 1-2 minutes.
+
+
+;;; Examples:
+
+;; 1. `M-x erldoc-browse RET erlang:integer_to_binary/2 RET' opens the
+;; `erlang' manual anchored on the entry for `integer_to_binary/2'.
+;;
+;; 2. `M-x erldoc-apropos RET first RET' list all MFAs matching
+;; substring `first'.
+;;
+;; 3. `M-x erldoc-browse-topic RET efficiency_guide#Introduction RET'
+;; opens chapter `Introduction' of the `Efficiency Guide' in the
+;; browser.
+
+;;; History:
+
+;; Written in December 2013 as a temporary solution to help me browse
+;; the rich Erlang/OTP documentation. Three years on I find myself
+;; still using it every day. - Leo (2016)
+
+;;; Code:
+
+(eval-when-compile (require 'url-parse))
+(require 'cl-lib)
+(require 'erlang)
+
+(eval-and-compile ;for emacs < 24.3
+ (or (fboundp 'user-error) (defalias 'user-error 'error)))
+
+(defgroup erldoc nil
+ "Browse Erlang document."
+ :group 'help)
+
+(defcustom erldoc-man-index "http://www.erlang.org/doc/man_index.html"
+ "The URL to the man_index.html page.
+Note it is advisable to customise this to a local URL for example
+`file:///usr/local/19.1/lib/erlang/doc/man_index.html' to speed
+up the indexing."
+ :type 'string
+ :group 'erldoc)
+
+(defcustom erldoc-verify-man-path nil
+ "If non-nil verify man path existence for `file://'."
+ :type 'boolean
+ :group 'erldoc)
+
+(defcustom erldoc-output-file (locate-user-emacs-file "cache/erldoc")
+ "File to store the parsed results."
+ :type 'file
+ :group 'erldoc)
+
+(defun erldoc-strip-string (s)
+ (let* ((re "[ \t\n\r\f\v\u00a0]+")
+ (from (if (string-match (concat "\\`" re) s) (match-end 0) 0))
+ (to (and (string-match (concat re "\\'") s) (match-beginning 0))))
+ (substring s from (and to (max to from)))))
+
+;; Note: don't know how to get the BASE-URL to
+;; `libxml-parse-html-region' to work.
+(defun erldoc-expand-url (url base-url)
+ (if (url-type (url-generic-parse-url url))
+ url
+ (let* ((base (url-generic-parse-url base-url))
+ (dir (directory-file-name (file-name-directory (url-filename base)))))
+ (setf (url-filename base) (expand-file-name url dir))
+ (url-recreate-url base))))
+
+(defun erldoc-parse-html (url)
+ (with-temp-buffer
+ (url-insert-file-contents url)
+ (libxml-parse-html-region (point-min) (point-max))))
+
+(defalias 'erldoc-dom-text-node-p #'stringp)
+
+(defun erldoc-dom-attributes (dom)
+ (and (not (erldoc-dom-text-node-p dom)) (cadr dom)))
+
+(defun erldoc-dom-get-attribute (dom attrib-name)
+ (cdr (assq attrib-name (erldoc-dom-attributes dom))))
+
+(defun erldoc-dom-children (dom)
+ (and (not (erldoc-dom-text-node-p dom)) (cddr dom)))
+
+(defun erldoc-dom-get-text (dom)
+ (let ((text (car (last (erldoc-dom-children dom)))))
+ (and (erldoc-dom-text-node-p text) text)))
+
+(defvar erldoc-dom-walk-parent nil)
+(defvar erldoc-dom-walk-siblings nil)
+
+(defun erldoc-dom-walk (dom k)
+ (funcall k dom)
+ (let ((erldoc-dom-walk-parent dom)
+ (erldoc-dom-walk-siblings (unless (erldoc-dom-text-node-p dom)
+ (cddr dom))))
+ (dolist (child erldoc-dom-walk-siblings)
+ (erldoc-dom-walk child k))))
+
+(defun erldoc-dom-get-element (dom element-name)
+ (catch 'return
+ (erldoc-dom-walk dom (lambda (d)
+ (when (eq (car-safe d) element-name)
+ (throw 'return d))))))
+
+(defun erldoc-dom-get-element-by-id (dom id)
+ (catch 'return
+ (erldoc-dom-walk dom (lambda (d)
+ (when (equal (erldoc-dom-get-attribute d 'id) id)
+ (throw 'return d))))))
+
+(defun erldoc-dom-get-elements-by-id (dom id)
+ (let (result)
+ (erldoc-dom-walk dom (lambda (d)
+ (when (equal (erldoc-dom-get-attribute d 'id) id)
+ (push d result))))
+ (nreverse result)))
+
+(defun erldoc-fix-path (url)
+ (if (and erldoc-verify-man-path
+ ;; Could only verify local files
+ (equal (url-type (url-generic-parse-url url)) "file"))
+ (let* ((obj (url-generic-parse-url url))
+ (new (car (file-expand-wildcards
+ (replace-regexp-in-string
+ "-[0-9]+\\(?:[.][0-9]+\\)*" "*"
+ (url-filename obj))))))
+ (or new (error "File %s does not exist" (url-filename obj)))
+ (setf (url-filename obj) new)
+ (url-recreate-url obj))
+ url))
+
+(defun erldoc-parse-man-index (url)
+ (let ((table (erldoc-dom-get-element (erldoc-parse-html url) 'table))
+ (mans))
+ (erldoc-dom-walk
+ table
+ (lambda (d)
+ (when (eq (car-safe d) 'a)
+ (let ((href (erldoc-dom-get-attribute d 'href)))
+ (when (and href (not (string-match-p "index\\.html\\'" href)))
+ (with-demoted-errors "erldoc-parse-man-index: %S"
+ (push (cons (erldoc-dom-get-text d)
+ (erldoc-fix-path (erldoc-expand-url href url)))
+ mans)))))))
+ (nreverse mans)))
+
+(defun erldoc-parse-man (man)
+ (let ((dom (erldoc-parse-html (cdr man)))
+ (table (make-hash-table :test #'equal)))
+ (erldoc-dom-walk
+ (erldoc-dom-get-element-by-id dom "loadscrollpos")
+ (lambda (d)
+ (let ((href (erldoc-dom-get-attribute d 'href)))
+ (when (and href (string-match "#" href))
+ (puthash (substring href (match-end 0))
+ (list (concat (car man) ":" (erldoc-strip-string
+ (erldoc-dom-get-text d)))
+ (erldoc-expand-url href (cdr man)))
+ table)))))
+ (let ((span-content
+ (lambda (span)
+ (let ((texts))
+ (erldoc-dom-walk span
+ (lambda (d)
+ (and (erldoc-dom-text-node-p d)
+ (push (erldoc-strip-string d) texts))))
+ (and texts (mapconcat 'identity (nreverse texts) " ")))))
+ entries)
+ (erldoc-dom-walk
+ dom
+ (lambda (d)
+ ;; Get the full function signature.
+ (when (and (eq (car-safe d) 'a)
+ (gethash (erldoc-dom-get-attribute d 'name) table))
+ (push (append (gethash (erldoc-dom-get-attribute d 'name) table)
+ (list (funcall span-content
+ (or (erldoc-dom-get-element d 'span)
+ (cadr (memq d erldoc-dom-walk-siblings))))))
+ entries))
+ ;; Get data types
+ (when (and (eq (car-safe d) 'a)
+ (string-prefix-p "type-"
+ (or (erldoc-dom-get-attribute d 'name) "")))
+ (push (list (concat (car man) ":" (funcall span-content d))
+ (concat (cdr man) "#" (erldoc-dom-get-attribute d 'name))
+ (funcall span-content erldoc-dom-walk-parent))
+ entries))))
+ entries)))
+
+(defun erldoc-parse-all (man-index output &optional json)
+ (let* ((output (expand-file-name output))
+ (table (make-hash-table :size 11503 :test #'equal))
+ (mans (erldoc-parse-man-index man-index))
+ (progress 1)
+ (reporter (make-progress-reporter "Parsing Erlang/OTP documentation"
+ progress (length mans)))
+ fails all)
+ (dolist (man mans)
+ (condition-case err
+ (push (erldoc-parse-man man) all)
+ (error (push (error-message-string err) fails)))
+ (accept-process-output nil 0.01)
+ (progress-reporter-update reporter (cl-incf progress)))
+ (when fails
+ (display-warning 'erldoc-parse-all
+ (format "\n\n%s" (mapconcat #'identity fails "\n"))
+ :error))
+ (progress-reporter-done reporter)
+ (mapc (lambda (x) (puthash (car x) (cdr x) table))
+ (apply #'nconc (nreverse all)))
+ (with-temp-buffer
+ (if (not json)
+ (pp table (current-buffer))
+ (eval-and-compile (require 'json))
+ (let ((json-encoding-pretty-print t))
+ (insert (json-encode table))))
+ (unless (file-directory-p (file-name-directory output))
+ (make-directory (file-name-directory output) t))
+ (write-region nil nil output nil nil nil 'ask))))
+
+(defun erldoc-otp-release ()
+ "Get the otp release version (as string) or nil if not found."
+ (let ((otp (erldoc-dom-get-text
+ (erldoc-dom-get-element
+ (erldoc-parse-html
+ (erldoc-expand-url "index.html" erldoc-man-index))
+ 'title))))
+ (and (string-match "[0-9.]+\\'" otp) (match-string 0 otp))))
+
+(defvar erldoc-browse-history nil)
+(defvar erldoc-lookup-table nil)
+
+(defun erldoc-lookup-table ()
+ (or erldoc-lookup-table
+ (progn
+ (unless (file-exists-p erldoc-output-file)
+ (let ((of (pcase (erldoc-otp-release)
+ (`nil erldoc-output-file)
+ (ver (concat erldoc-output-file "-" ver)))))
+ (unless (file-exists-p of)
+ (erldoc-parse-all erldoc-man-index of))
+ (unless (string= erldoc-output-file of)
+ (make-symbolic-link of erldoc-output-file))))
+ (setq erldoc-lookup-table
+ (with-temp-buffer
+ (insert-file-contents erldoc-output-file)
+ (read (current-buffer)))))))
+
+(defun erldoc-best-matches (mfa)
+ (pcase mfa
+ ((and `(,m ,f) (let a (erlang-get-function-arity)))
+ (let ((mfa (format "%s:%s/%s" m f a)))
+ (cond ((gethash mfa (erldoc-lookup-table)) (list mfa))
+ (m (all-completions (concat m ":" f "/") (erldoc-lookup-table)))
+ (t (let* ((mod (erlang-get-module))
+ (mf1 (and mod (concat mod ":" f "/")))
+ (mf2 (concat "erlang:" f "/"))
+ (re (concat ":" (regexp-quote f) "/")))
+ (or (and mf1 (all-completions mf1 (erldoc-lookup-table)))
+ (all-completions mf2 (erldoc-lookup-table))
+ (cl-loop for k being the hash-keys of (erldoc-lookup-table)
+ when (string-match-p re k)
+ collect k)))))))))
+
+;;;###autoload
+(defun erldoc-browse (mfa)
+ (interactive
+ (let ((default
+ ;; `erlang-mode-syntax-table' is lazily initialised.
+ (with-syntax-table (or erlang-mode-syntax-table (standard-syntax-table))
+ (ignore-errors
+ (erldoc-best-matches
+ (or (erlang-get-function-under-point)
+ (save-excursion
+ (goto-char (or (cadr (syntax-ppss)) (point)))
+ (erlang-get-function-under-point))))))))
+ (list (completing-read (format (if default "Function {%d %s} (default %s): "
+ "Function: ")
+ (length default)
+ (if (= (length default) 1) "guess" "guesses")
+ (car default))
+ (erldoc-lookup-table)
+ nil t nil 'erldoc-browse-history default))))
+ (or (stringp mfa)
+ (signal 'wrong-type-argument (list 'string mfa 'mfa)))
+ (browse-url (or (car (gethash mfa (erldoc-lookup-table)))
+ (user-error "No documentation for %s" mfa))))
+
+;;;###autoload
+(defun erldoc-apropos (pattern)
+ (interactive "sPattern: ")
+ (with-help-window (help-buffer)
+ (with-current-buffer standard-output
+ (princ (concat "Erldoc apropos pattern: " pattern "\n\n"))
+ (maphash (lambda (k v)
+ (when (string-match-p pattern k)
+ (insert-text-button k :type 'help-url
+ 'help-args (list (car v)))
+ (insert "\n")))
+ (erldoc-lookup-table)))))
+
+(defun erldoc-tokenize-signature (sig)
+ ;; Divide SIG into (MF ARGLIST RETTYPE)
+ (let ((from (if (string-match "\\`.+?(" sig)
+ (1- (match-end 0))
+ 0))
+ (to (and (string-match "\\s-*->\\s-*.*?\\'" sig) (match-beginning 0))))
+ (list (erldoc-strip-string (substring sig 0 from))
+ (erldoc-strip-string (substring sig from (and to (max from to))))
+ (and to (erldoc-strip-string (substring sig to))))))
+
+(defun erldoc-format-signature (mod fn)
+ (when (and mod fn (or erldoc-lookup-table
+ (file-exists-p erldoc-output-file)))
+ (let ((re (concat "\\`" mod ":" fn "/\\([0-9]+\\)\\'"))
+ (sigs))
+ (maphash (lambda (k v)
+ (when (string-match re k)
+ (push (cons (string-to-number (match-string 1 k))
+ (cdr (erldoc-tokenize-signature (cadr v))))
+ sigs)))
+ (erldoc-lookup-table))
+ (when sigs
+ ;; Mostly single return type but there are exceptions such as
+ ;; `beam_lib:chunks/2,3'.
+ (let ((single-rettype
+ (cl-reduce (lambda (x1 x2) (and x1 x2 (equal x1 x2) x1))
+ sigs :key #'cl-caddr))
+ (sigs (sort sigs #'car-less-than-car)))
+ (if single-rettype
+ (concat mod ":" fn (mapconcat #'cadr sigs " | ") " " single-rettype)
+ (mapconcat (lambda (x) (concat mod ":" fn (nth 1 x) " " (nth 2 x)))
+ sigs "\n")))))))
+
+;;;###autoload
+(defun erldoc-eldoc-function ()
+ "A function suitable for `eldoc-documentation-function'."
+ (save-excursion
+ (pcase (erlang-get-function-under-point)
+ (`(,_ nil) )
+ (`(nil ,fn) (erldoc-format-signature "erlang" fn))
+ (`(,mod ,fn) (erldoc-format-signature mod fn)))))
+
+(defun erldoc-parse-eeps-index ()
+ (let* ((url "http://www.erlang.org/eeps/")
+ (table (catch 'return
+ (erldoc-dom-walk (erldoc-parse-html url)
+ (lambda (d)
+ (and (eq (car-safe d) 'table)
+ (equal (erldoc-dom-get-attribute d 'summary)
+ "Numerical Index of EEPs")
+ (throw 'return d))))))
+ (fix-title (lambda (title)
+ (replace-regexp-in-string
+ "`` *" "" (replace-regexp-in-string " *``, *" " by " title))))
+ (result))
+ (erldoc-dom-walk
+ table (lambda (d)
+ (when (eq (car-safe d) 'a)
+ (push (cons (funcall fix-title (erldoc-dom-get-attribute d 'title))
+ (erldoc-expand-url
+ (erldoc-dom-get-attribute d 'href)
+ url))
+ result))))
+ (nreverse result)))
+
+(defvar erldoc-user-guides nil)
+
+(defvar erldoc-missing-user-guides
+ '("compiler" "hipe" "kernel" "os_mon" "parsetools" "typer")
+ "List of standard Erlang applications with no user guides.")
+
+;; Search in `code:lib_dir/0' using find LIB_DIR -type f -name
+;; '*_app.html'.
+(defvar erldoc-app-manuals '("crypto" "diameter" "erl_docgen"
+ "kernel" "observer" "os_mon"
+ "runtime_tools" "sasl" "snmp"
+ "ssl" "test_server"
+ ("ssh" . "SSH") ("stdlib" . "STDLIB")
+ ("hipe" . "HiPE") ("typer" . "TypEr"))
+ "List of applications that come with a manual.")
+
+(defun erldoc-user-guide-chapters (user-guide)
+ (pcase-let ((`(,name . ,url) user-guide))
+ (unless (member name erldoc-missing-user-guides)
+ (let ((chaps (erldoc-dom-get-elements-by-id
+ (erldoc-dom-get-element-by-id (erldoc-parse-html url) "leftnav")
+ "no")))
+ (or chaps (warn "erldoc-user-guide-chapters no chapters found for `%s'"
+ (cdr user-guide)))
+ (mapcar (lambda (li)
+ (cons (concat name "#" (erldoc-dom-get-attribute li 'title))
+ (erldoc-expand-url (erldoc-dom-get-attribute
+ (erldoc-dom-get-element li 'a) 'href)
+ url)))
+ chaps)))))
+
+(defun erldoc-user-guides-1 ()
+ (let ((url (erldoc-expand-url "applications.html" erldoc-man-index))
+ app-guides app-mans)
+ (erldoc-dom-walk
+ (erldoc-parse-html url)
+ (lambda (d)
+ (when (and (eq (car-safe d) 'a)
+ (not (string-match-p "\\`[0-9.]+\\'" (erldoc-dom-get-text d))))
+ (with-demoted-errors "erldoc-user-guides-1: %S"
+ (let ((name (erldoc-strip-string (erldoc-dom-get-text d)))
+ (index-page (erldoc-fix-path (erldoc-expand-url
+ (erldoc-dom-get-attribute d 'href) url))))
+ (push (cons name (if (member name erldoc-missing-user-guides)
+ index-page
+ (erldoc-expand-url "users_guide.html" index-page)))
+ app-guides)
+ ;; Collect application manuals.
+ (pcase (assoc name (mapcar (lambda (x) (if (consp x) x (cons x x)))
+ erldoc-app-manuals))
+ (`(,_ . ,manual)
+ (push (cons name
+ (erldoc-expand-url (format "%s_app.html" manual)
+ index-page))
+ app-mans))))))))
+ (list (nreverse app-guides)
+ (nreverse app-mans))))
+
+(defun erldoc-user-guides ()
+ (or erldoc-user-guides
+ (let ((file (concat erldoc-output-file "-topics")))
+ (unless (file-exists-p file)
+ (unless (file-directory-p (file-name-directory file))
+ (make-directory (file-name-directory file) t))
+ (with-temp-buffer
+ (pcase-let ((`(,guides ,mans) (erldoc-user-guides-1)))
+ (pp (append (cl-mapcan #'erldoc-user-guide-chapters
+ (append (mapcar
+ (lambda (dir)
+ (cons dir (erldoc-expand-url
+ (concat dir "/users_guide.html")
+ erldoc-man-index)))
+ '("design_principles"
+ "efficiency_guide"
+ "embedded"
+ "getting_started"
+ "installation_guide"
+ "oam"
+ "programming_examples"
+ "reference_manual"
+ "system_architecture_intro"
+ "system_principles"
+ "tutorial"))
+ guides))
+ (mapcar (lambda (man)
+ (pcase-let ((`(,name . ,url) man))
+ (cons (concat name " (App)") url)))
+ mans)
+ (erldoc-parse-eeps-index))
+ (current-buffer)))
+ (write-region nil nil file nil nil nil 'ask)))
+ (setq erldoc-user-guides (with-temp-buffer (insert-file-contents file)
+ (read (current-buffer)))))))
+
+;;;###autoload
+(defun erldoc-browse-topic (topic)
+ (interactive
+ (list (completing-read "User guide: " (erldoc-user-guides) nil t)))
+ (browse-url (cdr (assoc topic (erldoc-user-guides)))))
+
+(provide 'erldoc)
+;;; erldoc.el ends here
diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented
index 7a1ff6a954..14a4eca7c3 100644
--- a/lib/tools/emacs/test.erl.indented
+++ b/lib/tools/emacs/test.erl.indented
@@ -1,4 +1,4 @@
-%% -*- erlang -*-
+%% -*- Mode: erlang; indent-tabs-mode: nil -*-
%%
%% %CopyrightBegin%
%%
@@ -27,7 +27,7 @@
%%% Created : 6 Oct 2009 by Dan Gudmundsson <[email protected]>
%%%-------------------------------------------------------------------
-%% Start off with syntax highlighting you have to verify this by looking here
+%% Start off with syntax highlighting you have to verify this by looking here
%% and see that the code looks alright
-module(test).
@@ -44,175 +44,175 @@ foo() ->
%% Module attributes should be highlighted
-export([t/1]).
--record(record1, {a,
- b,
- c
- }).
+-record(record1, {a,
+ b,
+ c
+ }).
-record(record2, {
- a,
- b
- }).
+ a,
+ b
+ }).
-record(record3, {a = 8#42423 bor
- 8#4234,
- b = 8#5432
- bor 2#1010101
- c = 123 +
- 234,
+ 8#4234,
+ b = 8#5432
+ bor 2#1010101
+ c = 123 +
+ 234,
d}).
-record(record4, {
- a = 8#42423 bor
- 8#4234,
- b = 8#5432
- bor 2#1010101
- c = 123 +
- 234,
- d}).
+ a = 8#42423 bor
+ 8#4234,
+ b = 8#5432
+ bor 2#1010101
+ c = 123 +
+ 234,
+ d}).
-record(record5, { a = 1 :: integer()
- , b = foobar :: atom()
- }).
+ , b = foobar :: atom()
+ }).
-define(MACRO_1, macro).
-define(MACRO_2(_), macro).
-spec t(integer()) -> any().
--type ann() :: Var :: integer().
--type ann2() :: Var ::
- 'return'
- | 'return_white_spaces'
- | 'return_comments'
- | 'text' | ann().
--type paren() ::
- (ann2()).
--type t1() :: atom().
--type t2() :: [t1()].
--type t3(Atom) :: integer(Atom).
--type t4() :: t3(foobar).
--type t5() :: {t1(), t3(foo)}.
--type t6() :: 1 | 2 | 3 |
- 'foo' | 'bar'.
--type t7() :: [].
--type t71() :: [_].
+-type ann() :: Var :: integer().
+-type ann2() :: Var ::
+ 'return'
+ | 'return_white_spaces'
+ | 'return_comments'
+ | 'text' | ann().
+-type paren() ::
+ (ann2()).
+-type t1() :: atom().
+-type t2() :: [t1()].
+-type t3(Atom) :: integer(Atom).
+-type t4() :: t3(foobar).
+-type t5() :: {t1(), t3(foo)}.
+-type t6() :: 1 | 2 | 3 |
+ 'foo' | 'bar'.
+-type t7() :: [].
+-type t71() :: [_].
-type t8() :: {any(),none(),pid(),port(),
- reference(),float()}.
--type t9() :: [1|2|3|foo|bar] |
- list(a | b | c) | t71().
--type t10() :: {1|2|3|foo|t9()} | {}.
--type t11() :: 1..2.
--type t13() :: maybe_improper_list(integer(), t11()).
--type t14() :: [erl_scan:foo() |
- %% Should be highlighted
- term() |
- bool() |
- byte() |
- char() |
- non_neg_integer() | nonempty_list() |
- pos_integer() |
- neg_integer() |
- number() |
- list() |
- nonempty_improper_list() | nonempty_maybe_improper_list() |
- maybe_improper_list() | string() | iolist() | byte() |
- module() |
- mfa() |
- node() |
- timeout() |
- no_return() |
- %% Should not be highlighted
- nonempty_() | nonlist() |
- erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)].
+ reference(),float()}.
+-type t9() :: [1|2|3|foo|bar] |
+ list(a | b | c) | t71().
+-type t10() :: {1|2|3|foo|t9()} | {}.
+-type t11() :: 1..2.
+-type t13() :: maybe_improper_list(integer(), t11()).
+-type t14() :: [erl_scan:foo() |
+ %% Should be highlighted
+ term() |
+ bool() |
+ byte() |
+ char() |
+ non_neg_integer() | nonempty_list() |
+ pos_integer() |
+ neg_integer() |
+ number() |
+ list() |
+ nonempty_improper_list() | nonempty_maybe_improper_list() |
+ maybe_improper_list() | string() | iolist() | byte() |
+ module() |
+ mfa() |
+ node() |
+ timeout() |
+ no_return() |
+ %% Should not be highlighted
+ nonempty_() | nonlist() |
+ erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)].
-type t15() :: {binary(),<<>>,<<_:34>>,<<_:_*42>>,
<<_:3,_:_*14>>,<<>>} | [<<>>|<<_:34>>|<<_:16>>|
- <<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>|
- <<_:34>>|<<_:34>>|<<_:34>>].
--type t16() :: fun().
--type t17() :: fun((...) -> paren()).
--type t18() :: fun(() -> t17() | t16()).
+ <<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>|
+ <<_:34>>|<<_:34>>|<<_:34>>].
+-type t16() :: fun().
+-type t17() :: fun((...) -> paren()).
+-type t18() :: fun(() -> t17() | t16()).
-type t19() :: fun((t18()) -> t16()) |
- fun((nonempty_maybe_improper_list('integer', any())|
- 1|2|3|a|b|<<_:3,_:_*14>>|integer()) ->
- nonempty_maybe_improper_list('integer', any())|
- 1|2|3|a|b|<<_:3,_:_*14>>|integer()).
--type t20() :: [t19(), ...].
--type t21() :: tuple().
--type t21(A) :: A.
--type t22() :: t21(integer()).
--type t23() :: #rec1{}.
--type t24() :: #rec2{a :: t23(), b :: [atom()]}.
--type t25() :: #rec3{f123 :: [t24() |
- 1|2|3|4|a|b|c|d|
- nonempty_maybe_improper_list(integer, any())]}.
+ fun((nonempty_maybe_improper_list('integer', any())|
+ 1|2|3|a|b|<<_:3,_:_*14>>|integer()) ->
+ nonempty_maybe_improper_list('integer', any())|
+ 1|2|3|a|b|<<_:3,_:_*14>>|integer()).
+-type t20() :: [t19(), ...].
+-type t21() :: tuple().
+-type t21(A) :: A.
+-type t22() :: t21(integer()).
+-type t23() :: #rec1{}.
+-type t24() :: #rec2{a :: t23(), b :: [atom()]}.
+-type t25() :: #rec3{f123 :: [t24() |
+ 1|2|3|4|a|b|c|d|
+ nonempty_maybe_improper_list(integer, any())]}.
-type t26() :: #rec4{ a :: integer()
- , b :: any()
- }.
+ , b :: any()
+ }.
-type t27() :: { integer()
- , atom()
- }.
+ , atom()
+ }.
-type t99() ::
- {t2(),t4(),t5(),t6(),t7(),t8(),t10(),t14(),
- t15(),t20(),t21(), t22(),t25()}.
+ {t2(),t4(),t5(),t6(),t7(),t8(),t10(),t14(),
+ t15(),t20(),t21(), t22(),t25()}.
-spec t1(FooBar :: t99()) -> t99();
- (t2()) -> t2();
+ (t2()) -> t2();
(t4()) -> t4() when is_subtype(t4(), t24);
- (t23()) -> t23() when is_subtype(t23(), atom()),
- is_subtype(t23(), t14());
- (t24()) -> t24() when is_subtype(t24(), atom()),
- is_subtype(t24(), t14()),
- is_subtype(t24(), t4()).
+ (t23()) -> t23() when is_subtype(t23(), atom()),
+ is_subtype(t23(), t14());
+ (t24()) -> t24() when is_subtype(t24(), atom()),
+ is_subtype(t24(), t14()),
+ is_subtype(t24(), t4()).
-spec over(I :: integer()) -> R1 :: foo:typen();
- (A :: atom()) -> R2 :: foo:atomen();
- (T :: tuple()) -> R3 :: bar:typen().
+ (A :: atom()) -> R2 :: foo:atomen();
+ (T :: tuple()) -> R3 :: bar:typen().
--spec mod:t2() -> any().
+-spec mod:t2() -> any().
--spec handle_cast(Cast :: {'exchange', node(), [[name(),...]]}
- | {'del_member', name(), pid()},
- #state{}) -> {'noreply', #state{}}.
+-spec handle_cast(Cast :: {'exchange', node(), [[name(),...]]}
+ | {'del_member', name(), pid()},
+ #state{}) -> {'noreply', #state{}}.
--spec handle_cast(Cast ::
- {'exchange', node(), [[name(),...]]}
- | {'del_member', name(), pid()},
- #state{}) -> {'noreply', #state{}}.
+-spec handle_cast(Cast ::
+ {'exchange', node(), [[name(),...]]}
+ | {'del_member', name(), pid()},
+ #state{}) -> {'noreply', #state{}}.
-spec all(fun((T) -> boolean()), List :: [T]) ->
- boolean() when is_subtype(T, term()). % (*)
+ boolean() when is_subtype(T, term()). % (*)
--spec get_closest_pid(term()) ->
- Return :: pid()
- | {'error', {'no_process', term()}
- | {'no_such_group', term()}}.
+-spec get_closest_pid(term()) ->
+ Return :: pid()
+ | {'error', {'no_process', term()}
+ | {'no_such_group', term()}}.
-spec add( X :: integer()
- , Y :: integer()
- ) -> integer().
+ , Y :: integer()
+ ) -> integer().
--opaque attributes_data() ::
- [{'column', column()} | {'line', info_line()} |
- {'text', string()}] | {line(),column()}.
+-opaque attributes_data() ::
+ [{'column', column()} | {'line', info_line()} |
+ {'text', string()}] | {line(),column()}.
-record(r,{
f1 :: attributes_data(),
- f222 = foo:bar(34, #rec3{}, 234234234423,
- aassdsfsdfsdf, 2234242323) ::
- [t24() | 1|2|3|4|a|b|c|d|
- nonempty_maybe_improper_list(integer, any())],
- f333 :: [t24() | 1|2|3|4|a|b|c|d|
- nonempty_maybe_improper_list(integer, any())],
- f3 = x:y(),
- f4 = x:z() :: t99(),
- f17 :: 'undefined',
- f18 :: 1 | 2 | 'undefined',
- f19 = 3 :: integer()|undefined,
- f5 = 3 :: undefined|integer()}).
+ f222 = foo:bar(34, #rec3{}, 234234234423,
+ aassdsfsdfsdf, 2234242323) ::
+ [t24() | 1|2|3|4|a|b|c|d|
+ nonempty_maybe_improper_list(integer, any())],
+ f333 :: [t24() | 1|2|3|4|a|b|c|d|
+ nonempty_maybe_improper_list(integer, any())],
+ f3 = x:y(),
+ f4 = x:z() :: t99(),
+ f17 :: 'undefined',
+ f18 :: 1 | 2 | 'undefined',
+ f19 = 3 :: integer()|undefined,
+ f5 = 3 :: undefined|integer()}).
-record(state, {
- sequence_number = 1 :: integer()
- }).
+ sequence_number = 1 :: integer()
+ }).
highlighting(X) % Function definitions should be highlighted
@@ -230,12 +230,12 @@ highlighting(X) % Function definitions should be highlighted
'#1',atom,
$", atom, % atom should be ok
- $', atom,
+ $', atom,
"string$", atom, "string$", atom, % currently buggy I know...
"string\$", atom, % workaround for bug above
- "char $in string", atom,
+ "char $in string", atom,
'atom$', atom, 'atom$', atom,
'atom\$', atom,
@@ -270,15 +270,15 @@ highlighting(X) % Function definitions should be highlighted
erlang:anything(lists),
%% Guards
is_atom(foo), is_float(2.3), is_integer(32), is_number(4323.3),
- is_function(Fun), is_pid(self()),
+ is_function(Fun), is_pid(self()),
not_a_guard:is_list([]),
%% Other Types
atom, % not (currently) hightlighted
- 234234,
+ 234234,
234.43,
- [list, are, not, higlighted],
+ [list, are, not, higlighted],
{nor, is, tuple},
ok.
@@ -290,35 +290,35 @@ highlighting(X) % Function definitions should be highlighted
%% Indented
- % Right
+ % Right
-indent_basics(X, Y, Z)
+indent_basics(X, Y, Z)
when X > 42,
Z < 13;
Y =:= 4711 ->
%% comments
- % right comments
- case lists:filter(fun(_, AlongName,
- B,
- C) ->
- true
- end,
- [a,v,b])
+ % right comments
+ case lists:filter(fun(_, AlongName,
+ B,
+ C) ->
+ true
+ end,
+ [a,v,b])
of
- [] ->
- Y = 5 * 43,
- ok;
- [_|_] ->
- Y = 5 * 43,
- ok
+ [] ->
+ Y = 5 * 43,
+ ok;
+ [_|_] ->
+ Y = 5 * 43,
+ ok
end,
Y,
%% List, tuples and binaries
- [a,
+ [a,
b, c
],
- [ a,
+ [ a,
b, c
],
@@ -326,10 +326,10 @@ indent_basics(X, Y, Z)
a,
b
],
- {a,
+ {a,
b,c
},
- { a,
+ { a,
b,c
},
@@ -366,16 +366,16 @@ indent_basics(X, Y, Z)
c
),
- call(2#42423 bor
- #4234,
- 2#5432,
- other_arg),
+ call(2#42423 bor
+ #4234,
+ 2#5432,
+ other_arg),
ok;
-indent_basics(Xlongname,
- #struct{a=Foo,
- b=Bar},
- [X|
- Y]) ->
+indent_basics(Xlongname,
+ #struct{a=Foo,
+ b=Bar},
+ [X|
+ Y]) ->
testing_next_clause,
ok;
indent_basics( % AD added clause
@@ -408,295 +408,295 @@ indent_nested() ->
indent_icr(Z) -> % icr = if case receive
%% If
if Z >= 0 ->
- X = 43 div 4,
- foo(X);
+ X = 43 div 4,
+ foo(X);
Z =< 10 ->
- X = 43 div 4,
- foo(X);
+ X = 43 div 4,
+ foo(X);
Z == 5 orelse
Z == 7 ->
- X = 43 div 4,
- foo(X);
+ X = 43 div 4,
+ foo(X);
true ->
- if_works
+ if_works
end,
%% Case
case {Z, foo, bar} of
- {Z,_,_} ->
- X = 43 div 4,
- foo(X);
- {Z,_,_} when
- Z =:= 42 -> % AD line should be indented as a when
- X = 43 div 4,
- foo(X);
- {Z,_,_}
- when Z < 10 -> % AD when should be indented
- X = 43 div 4,
- foo(X);
- {Z,_,_}
- when % AD when should be indented
- Z < 10 % and the guards should follow when
- andalso % unsure about how though
- true ->
- X = 43 div 4,
- foo(X)
+ {Z,_,_} ->
+ X = 43 div 4,
+ foo(X);
+ {Z,_,_} when
+ Z =:= 42 -> % AD line should be indented as a when
+ X = 43 div 4,
+ foo(X);
+ {Z,_,_}
+ when Z < 10 -> % AD when should be indented
+ X = 43 div 4,
+ foo(X);
+ {Z,_,_}
+ when % AD when should be indented
+ Z < 10 % and the guards should follow when
+ andalso % unsure about how though
+ true ->
+ X = 43 div 4,
+ foo(X)
end,
%% begin
begin
- sune,
- X = 74234 + foo(8456) +
- 345 div 43,
- ok
+ sune,
+ X = 74234 + foo(8456) +
+ 345 div 43,
+ ok
end,
%% receive
- receive
- {Z,_,_} ->
- X = 43 div 4,
- foo(X);
- Z ->
- X = 43 div 4,
- foo(X)
+ receive
+ {Z,_,_} ->
+ X = 43 div 4,
+ foo(X);
+ Z ->
+ X = 43 div 4,
+ foo(X)
end,
receive
- {Z,_,_} ->
- X = 43 div 4,
- foo(X);
- Z % AD added clause
- when Z =:= 1 -> % This line should be indented by 2
- X = 43 div 4,
- foo(X);
- Z when % AD added clause
- Z =:= 2 -> % This line should be indented by 2
- X = 43 div 4,
- foo(X);
- Z ->
- X = 43 div 4,
- foo(X)
+ {Z,_,_} ->
+ X = 43 div 4,
+ foo(X);
+ Z % AD added clause
+ when Z =:= 1 -> % This line should be indented by 2
+ X = 43 div 4,
+ foo(X);
+ Z when % AD added clause
+ Z =:= 2 -> % This line should be indented by 2
+ X = 43 div 4,
+ foo(X);
+ Z ->
+ X = 43 div 4,
+ foo(X)
after infinity ->
- foo(X),
- asd(X),
- 5*43
+ foo(X),
+ asd(X),
+ 5*43
end,
receive
- after 10 ->
- foo(X),
- asd(X),
- 5*43
+ after 10 ->
+ foo(X),
+ asd(X),
+ 5*43
end,
ok.
indent_fun() ->
%% Changed fun to one indention level
- Var = spawn(fun(X)
- when X == 2;
- X > 10 ->
- hello,
- case Hello() of
- true when is_atom(X) ->
- foo;
- false ->
- bar
- end;
- (Foo) when is_atom(Foo),
- is_integer(X) ->
- X = 6* 45,
- Y = true andalso
- kalle
- end),
+ Var = spawn(fun(X)
+ when X == 2;
+ X > 10 ->
+ hello,
+ case Hello() of
+ true when is_atom(X) ->
+ foo;
+ false ->
+ bar
+ end;
+ (Foo) when is_atom(Foo),
+ is_integer(X) ->
+ X = 6* 45,
+ Y = true andalso
+ kalle
+ end),
%% check EEP37 named funs
Fn1 = fun Fact(N) when N > 0 ->
- F = Fact(N-1),
- N * F;
- Fact(0) ->
- 1
- end,
+ F = Fact(N-1),
+ N * F;
+ Fact(0) ->
+ 1
+ end,
%% check anonymous funs too
Fn2 = fun(0) ->
- 1;
- (N) ->
- N
- end,
+ 1;
+ (N) ->
+ N
+ end,
ok.
indent_try_catch() ->
try
- io:format(stdout, "Parsing file ~s, ",
- [St0#leex.xfile]),
- {ok,Line3,REAs,Actions,St3} =
- parse_rules(Xfile, Line2, Macs, St2)
+ io:format(stdout, "Parsing file ~s, ",
+ [St0#leex.xfile]),
+ {ok,Line3,REAs,Actions,St3} =
+ parse_rules(Xfile, Line2, Macs, St2)
catch
- exit:{badarg,R} ->
- foo(R),
- io:format(stdout,
- "ERROR reason ~p~n",
- R);
- error:R % AD added clause
- when R =:= 42 -> % when should be indented
- foo(R);
- error:R % AD added clause
- when % when should be indented
- R =:= 42 -> % but unsure about this (maybe 2 more)
- foo(R);
- error:R when % AD added clause
- R =:= foo -> % line should be 2 indented (works)
- foo(R);
- error:R ->
- foo(R),
- io:format(stdout,
- "ERROR reason ~p~n",
- R)
+ exit:{badarg,R} ->
+ foo(R),
+ io:format(stdout,
+ "ERROR reason ~p~n",
+ R);
+ error:R % AD added clause
+ when R =:= 42 -> % when should be indented
+ foo(R);
+ error:R % AD added clause
+ when % when should be indented
+ R =:= 42 -> % but unsure about this (maybe 2 more)
+ foo(R);
+ error:R when % AD added clause
+ R =:= foo -> % line should be 2 indented (works)
+ foo(R);
+ error:R ->
+ foo(R),
+ io:format(stdout,
+ "ERROR reason ~p~n",
+ R)
after
- foo('after'),
- file:close(Xfile)
+ foo('after'),
+ file:close(Xfile)
end;
indent_try_catch() ->
try
- foo(bar)
+ foo(bar)
of
- X when true andalso
- kalle ->
- io:format(stdout, "Parsing file ~s, ",
- [St0#leex.xfile]),
- {ok,Line3,REAs,Actions,St3} =
- parse_rules(Xfile, Line2, Macs, St2);
- X % AD added clause
- when false andalso % when should be 2 indented
- bengt ->
- gurka();
- X when % AD added clause
- false andalso % line should be 2 indented
- not bengt ->
- gurka();
- X ->
- io:format(stdout, "Parsing file ~s, ",
- [St0#leex.xfile]),
- {ok,Line3,REAs,Actions,St3} =
- parse_rules(Xfile, Line2, Macs, St2)
+ X when true andalso
+ kalle ->
+ io:format(stdout, "Parsing file ~s, ",
+ [St0#leex.xfile]),
+ {ok,Line3,REAs,Actions,St3} =
+ parse_rules(Xfile, Line2, Macs, St2);
+ X % AD added clause
+ when false andalso % when should be 2 indented
+ bengt ->
+ gurka();
+ X when % AD added clause
+ false andalso % line should be 2 indented
+ not bengt ->
+ gurka();
+ X ->
+ io:format(stdout, "Parsing file ~s, ",
+ [St0#leex.xfile]),
+ {ok,Line3,REAs,Actions,St3} =
+ parse_rules(Xfile, Line2, Macs, St2)
catch
- exit:{badarg,R} ->
- foo(R),
- io:format(stdout,
- "ERROR reason ~p~n",
- R);
- error:R ->
- foo(R),
- io:format(stdout,
- "ERROR reason ~p~n",
- R)
+ exit:{badarg,R} ->
+ foo(R),
+ io:format(stdout,
+ "ERROR reason ~p~n",
+ R);
+ error:R ->
+ foo(R),
+ io:format(stdout,
+ "ERROR reason ~p~n",
+ R)
after
- foo('after'),
- file:close(Xfile),
- bar(with_long_arg,
- with_second_arg)
+ foo('after'),
+ file:close(Xfile),
+ bar(with_long_arg,
+ with_second_arg)
end;
indent_try_catch() ->
try foo()
- after
- foo(),
- bar(with_long_arg,
- with_second_arg)
+ after
+ foo(),
+ bar(with_long_arg,
+ with_second_arg)
end.
indent_catch() ->
D = B +
- float(43.1),
+ float(43.1),
B = catch oskar(X),
- A = catch (baz +
- bax),
+ A = catch (baz +
+ bax),
catch foo(),
- C = catch B +
- float(43.1),
+ C = catch B +
+ float(43.1),
case catch foo(X) of
- A ->
- B
+ A ->
+ B
end,
case
- catch foo(X)
+ catch foo(X)
of
- A ->
- B
+ A ->
+ B
end,
case
- foo(X)
+ foo(X)
of
- A ->
- catch B,
- X
+ A ->
+ catch B,
+ X
end,
try sune of
- _ -> foo
+ _ -> foo
catch _:_ -> baf
end,
try
- sune
+ sune
of
- _ ->
- X = 5,
- (catch foo(X)),
- X + 10
+ _ ->
+ X = 5,
+ (catch foo(X)),
+ X + 10
catch _:_ -> baf
end,
try
- (catch sune)
+ (catch sune)
of
- _ ->
- catch foo() %% BUGBUG can't handle catch inside try without parentheses
+ _ ->
+ catch foo() %% BUGBUG can't handle catch inside try without parentheses
catch _:_ ->
- baf
+ baf
end,
try
- (catch exit())
+ (catch exit())
catch
- _ ->
- catch baf()
+ _ ->
+ catch baf()
end,
ok.
indent_binary() ->
X = lists:foldr(fun(M) ->
- <<Ma/binary, " ">>
- end, [], A),
+ <<Ma/binary, " ">>
+ end, [], A),
A = <<X/binary, 0:8>>,
B.
indent_comprehensions() ->
- %% I don't have a good idea how we want to handle this
+ %% I don't have a good idea how we want to handle this
%% but they are here to show how they are indented today.
- Result1 = [X ||
- #record{a=X} <- lists:seq(1, 10),
- true = (X rem 2)
- ],
+ Result1 = [X ||
+ #record{a=X} <- lists:seq(1, 10),
+ true = (X rem 2)
+ ],
Result2 = [X || <<X:32,_:32>> <= <<0:512>>,
- true = (X rem 2)
- ],
+ true = (X rem 2)
+ ],
- Binary1 = << <<X:8>> ||
- #record{a=X} <- lists:seq(1, 10),
- true = (X rem 2)
- >>,
+ Binary1 = << <<X:8>> ||
+ #record{a=X} <- lists:seq(1, 10),
+ true = (X rem 2)
+ >>,
Binary2 = << <<X:8>> || <<X:32,_:32>> <= <<0:512>>,
- true = (X rem 2)
- >>,
+ true = (X rem 2)
+ >>,
ok.
%% This causes an error in earlier erlang-mode versions.
foo() ->
[#foo{
- foo = foo}].
+ foo = foo}].
%% Record indentation
some_function_with_a_very_long_name() ->
@@ -704,20 +704,20 @@ some_function_with_a_very_long_name() ->
field1=a,
field2=b},
case dummy_function_with_a_very_very_long_name(x) of
- #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
- field1=a,
- field2=b} ->
- ok;
- Var = #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
- field1=a,
- field2=b} ->
- Var#'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
- field1=a,
- field2=b};
- #xyz{
- a=1,
- b=2} ->
- ok
+ #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b} ->
+ ok;
+ Var = #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b} ->
+ Var#'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b};
+ #xyz{
+ a=1,
+ b=2} ->
+ ok
end.
another_function_with_a_very_very_long_name() ->
@@ -726,45 +726,45 @@ another_function_with_a_very_very_long_name() ->
field2=1}.
some_function_name_xyz(xyzzy, #some_record{
- field1=Field1,
- field2=Field2}) ->
+ field1=Field1,
+ field2=Field2}) ->
SomeVariable = f(#'Some-long-record-name'{
- field_a = 1,
- 'inter-xyz-parameters' =
- #'Some-other-very-long-record-name'{
- field2 = Field1,
- field2 = Field2}}),
+ field_a = 1,
+ 'inter-xyz-parameters' =
+ #'Some-other-very-long-record-name'{
+ field2 = Field1,
+ field2 = Field2}}),
{ok, SomeVariable}.
commas_first() ->
{abc, [ {some_var, 1}
- , {some_other_var, 2}
- , {erlang_ftw, 9}
- , {erlang_cookie, 'cookie'}
- , {cmds,
- [ {one, "sudo ls"}
- , {one, "sudo ls"}
- , {two, "sudo ls"}
- , {three, "sudo ls"}
- , {four, "sudo ls"}
- , {three, "sudo ls"}
- ] }
- , {ssh_username, "yow"}
- , {cluster,
- [ {aaaa, [ {"10.198.55.12" , "" }
- , {"10.198.55.13" , "" }
- ] }
- , {bbbb, [ {"10.198.55.151", "" }
- , {"10.198.55.123", "" }
- , {"10.198.55.34" , "" }
- , {"10.198.55.85" , "" }
- , {"10.198.55.67" , "" }
- ] }
- , {cccc, [ {"10.198.55.68" , "" }
- , {"10.198.55.69" , "" }
- ] }
- ] }
- ]
+ , {some_other_var, 2}
+ , {erlang_ftw, 9}
+ , {erlang_cookie, 'cookie'}
+ , {cmds,
+ [ {one, "sudo ls"}
+ , {one, "sudo ls"}
+ , {two, "sudo ls"}
+ , {three, "sudo ls"}
+ , {four, "sudo ls"}
+ , {three, "sudo ls"}
+ ] }
+ , {ssh_username, "yow"}
+ , {cluster,
+ [ {aaaa, [ {"10.198.55.12" , "" }
+ , {"10.198.55.13" , "" }
+ ] }
+ , {bbbb, [ {"10.198.55.151", "" }
+ , {"10.198.55.123", "" }
+ , {"10.198.55.34" , "" }
+ , {"10.198.55.85" , "" }
+ , {"10.198.55.67" , "" }
+ ] }
+ , {cccc, [ {"10.198.55.68" , "" }
+ , {"10.198.55.69" , "" }
+ ] }
+ ] }
+ ]
}.
@@ -776,9 +776,9 @@ commas_first() ->
%% body, due to the function name being mistaken for a keyword
catcher(N) ->
try generate_exception(N) of
- Val -> {N, normal, Val}
+ Val -> {N, normal, Val}
catch
- throw:X -> {N, caught, thrown, X};
- exit:X -> {N, caught, exited, X};
- error:X -> {N, caught, error, X}
+ 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 2552c71baf..c0cf1749b6 100644
--- a/lib/tools/emacs/test.erl.orig
+++ b/lib/tools/emacs/test.erl.orig
@@ -1,4 +1,4 @@
-%% -*- erlang -*-
+%% -*- Mode: erlang; indent-tabs-mode: nil -*-
%%
%% %CopyrightBegin%
%%
@@ -27,7 +27,7 @@
%%% Created : 6 Oct 2009 by Dan Gudmundsson <[email protected]>
%%%-------------------------------------------------------------------
-%% Start off with syntax highlighting you have to verify this by looking here
+%% Start off with syntax highlighting you have to verify this by looking here
%% and see that the code looks alright
-module(test).
@@ -44,18 +44,18 @@ foo() ->
%% Module attributes should be highlighted
-export([t/1]).
--record(record1, {a,
- b,
+-record(record1, {a,
+ b,
c
}).
-record(record2, {
a,
b
}).
-
+
-record(record3, {a = 8#42423 bor
8#4234,
- b = 8#5432
+ b = 8#5432
bor 2#1010101
c = 123 +
234,
@@ -64,7 +64,7 @@ foo() ->
-record(record4, {
a = 8#42423 bor
8#4234,
- b = 8#5432
+ b = 8#5432
bor 2#1010101
c = 123 +
234,
@@ -79,31 +79,31 @@ foo() ->
-spec t(integer()) -> any().
--type ann() :: Var :: integer().
--type ann2() :: Var ::
- 'return'
- | 'return_white_spaces'
+-type ann() :: Var :: integer().
+-type ann2() :: Var ::
+ 'return'
+ | 'return_white_spaces'
| 'return_comments'
- | 'text' | ann().
--type paren() ::
- (ann2()).
--type t1() :: atom().
--type t2() :: [t1()].
--type t3(Atom) :: integer(Atom).
--type t4() :: t3(foobar).
--type t5() :: {t1(), t3(foo)}.
--type t6() :: 1 | 2 | 3 |
- 'foo' | 'bar'.
--type t7() :: [].
--type t71() :: [_].
+ | 'text' | ann().
+-type paren() ::
+ (ann2()).
+-type t1() :: atom().
+-type t2() :: [t1()].
+-type t3(Atom) :: integer(Atom).
+-type t4() :: t3(foobar).
+-type t5() :: {t1(), t3(foo)}.
+-type t6() :: 1 | 2 | 3 |
+ 'foo' | 'bar'.
+-type t7() :: [].
+-type t71() :: [_].
-type t8() :: {any(),none(),pid(),port(),
- reference(),float()}.
--type t9() :: [1|2|3|foo|bar] |
- list(a | b | c) | t71().
--type t10() :: {1|2|3|foo|t9()} | {}.
--type t11() :: 1..2.
--type t13() :: maybe_improper_list(integer(), t11()).
--type t14() :: [erl_scan:foo() |
+ reference(),float()}.
+-type t9() :: [1|2|3|foo|bar] |
+ list(a | b | c) | t71().
+-type t10() :: {1|2|3|foo|t9()} | {}.
+-type t11() :: 1..2.
+-type t13() :: maybe_improper_list(integer(), t11()).
+-type t14() :: [erl_scan:foo() |
%% Should be highlighted
term() |
bool() |
@@ -122,31 +122,31 @@ foo() ->
timeout() |
no_return() |
%% Should not be highlighted
- nonempty_() | nonlist() |
+ nonempty_() | nonlist() |
erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)].
-type t15() :: {binary(),<<>>,<<_:34>>,<<_:_*42>>,
<<_:3,_:_*14>>,<<>>} | [<<>>|<<_:34>>|<<_:16>>|
<<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>|
-<<_:34>>|<<_:34>>|<<_:34>>].
--type t16() :: fun().
--type t17() :: fun((...) -> paren()).
--type t18() :: fun(() -> t17() | t16()).
+<<_:34>>|<<_:34>>|<<_:34>>].
+-type t16() :: fun().
+-type t17() :: fun((...) -> paren()).
+-type t18() :: fun(() -> t17() | t16()).
-type t19() :: fun((t18()) -> t16()) |
fun((nonempty_maybe_improper_list('integer', any())|
1|2|3|a|b|<<_:3,_:_*14>>|integer()) ->
nonempty_maybe_improper_list('integer', any())|
-1|2|3|a|b|<<_:3,_:_*14>>|integer()).
--type t20() :: [t19(), ...].
--type t21() :: tuple().
--type t21(A) :: A.
--type t22() :: t21(integer()).
--type t23() :: #rec1{}.
--type t24() :: #rec2{a :: t23(), b :: [atom()]}.
--type t25() :: #rec3{f123 :: [t24() |
-1|2|3|4|a|b|c|d|
-nonempty_maybe_improper_list(integer, any())]}.
+1|2|3|a|b|<<_:3,_:_*14>>|integer()).
+-type t20() :: [t19(), ...].
+-type t21() :: tuple().
+-type t21(A) :: A.
+-type t22() :: t21(integer()).
+-type t23() :: #rec1{}.
+-type t24() :: #rec2{a :: t23(), b :: [atom()]}.
+-type t25() :: #rec3{f123 :: [t24() |
+1|2|3|4|a|b|c|d|
+nonempty_maybe_improper_list(integer, any())]}.
-type t26() :: #rec4{ a :: integer()
, b :: any()
}.
@@ -155,7 +155,7 @@ nonempty_maybe_improper_list(integer, any())]}.
}.
-type t99() ::
{t2(),t4(),t5(),t6(),t7(),t8(),t10(),t14(),
-t15(),t20(),t21(), t22(),t25()}.
+t15(),t20(),t21(), t22(),t25()}.
-spec t1(FooBar :: t99()) -> t99();
(t2()) -> t2();
(t4()) -> t4() when is_subtype(t4(), t24);
@@ -169,21 +169,21 @@ t15(),t20(),t21(), t22(),t25()}.
(A :: atom()) -> R2 :: foo:atomen();
(T :: tuple()) -> R3 :: bar:typen().
--spec mod:t2() -> any().
+-spec mod:t2() -> any().
--spec handle_cast(Cast :: {'exchange', node(), [[name(),...]]}
+-spec handle_cast(Cast :: {'exchange', node(), [[name(),...]]}
| {'del_member', name(), pid()},
#state{}) -> {'noreply', #state{}}.
--spec handle_cast(Cast ::
- {'exchange', node(), [[name(),...]]}
+-spec handle_cast(Cast ::
+ {'exchange', node(), [[name(),...]]}
| {'del_member', name(), pid()},
#state{}) -> {'noreply', #state{}}.
-spec all(fun((T) -> boolean()), List :: [T]) ->
boolean() when is_subtype(T, term()). % (*)
--spec get_closest_pid(term()) ->
+-spec get_closest_pid(term()) ->
Return :: pid()
| {'error', {'no_process', term()}
| {'no_such_group', term()}}.
@@ -192,23 +192,23 @@ t15(),t20(),t21(), t22(),t25()}.
, Y :: integer()
) -> integer().
--opaque attributes_data() ::
+-opaque attributes_data() ::
[{'column', column()} | {'line', info_line()} |
- {'text', string()}] | {line(),column()}.
+ {'text', string()}] | {line(),column()}.
-record(r,{
f1 :: attributes_data(),
-f222 = foo:bar(34, #rec3{}, 234234234423,
- aassdsfsdfsdf, 2234242323) ::
-[t24() | 1|2|3|4|a|b|c|d|
+f222 = foo:bar(34, #rec3{}, 234234234423,
+ aassdsfsdfsdf, 2234242323) ::
+[t24() | 1|2|3|4|a|b|c|d|
nonempty_maybe_improper_list(integer, any())],
-f333 :: [t24() | 1|2|3|4|a|b|c|d|
+f333 :: [t24() | 1|2|3|4|a|b|c|d|
nonempty_maybe_improper_list(integer, any())],
f3 = x:y(),
f4 = x:z() :: t99(),
f17 :: 'undefined',
f18 :: 1 | 2 | 'undefined',
f19 = 3 :: integer()|undefined,
-f5 = 3 :: undefined|integer()}).
+f5 = 3 :: undefined|integer()}).
-record(state, {
sequence_number = 1 :: integer()
@@ -230,12 +230,12 @@ highlighting(X) % Function definitions should be highlighted
'#1',atom,
$", atom, % atom should be ok
- $', atom,
-
+ $', atom,
+
"string$", atom, "string$", atom, % currently buggy I know...
"string\$", atom, % workaround for bug above
-
- "char $in string", atom,
+
+ "char $in string", atom,
'atom$', atom, 'atom$', atom,
'atom\$', atom,
@@ -270,18 +270,18 @@ highlighting(X) % Function definitions should be highlighted
erlang:anything(lists),
%% Guards
is_atom(foo), is_float(2.3), is_integer(32), is_number(4323.3),
- is_function(Fun), is_pid(self()),
+ is_function(Fun), is_pid(self()),
not_a_guard:is_list([]),
%% Other Types
atom, % not (currently) hightlighted
- 234234,
+ 234234,
234.43,
- [list, are, not, higlighted],
+ [list, are, not, higlighted],
{nor, is, tuple},
ok.
-
+
%%%
%%% Indentation
%%%
@@ -293,32 +293,32 @@ highlighting(X) % Function definitions should be highlighted
% Right
-indent_basics(X, Y, Z)
+indent_basics(X, Y, Z)
when X > 42,
Z < 13;
Y =:= 4711 ->
%% comments
% right comments
- case lists:filter(fun(_, AlongName,
- B,
+ case lists:filter(fun(_, AlongName,
+ B,
C) ->
true
- end,
+ end,
[a,v,b])
of
[] ->
Y = 5 * 43,
ok;
- [_|_] ->
+ [_|_] ->
Y = 5 * 43,
ok
end,
Y,
%% List, tuples and binaries
- [a,
+ [a,
b, c
],
- [ a,
+ [ a,
b, c
],
@@ -326,10 +326,10 @@ Y =:= 4711 ->
a,
b
],
- {a,
+ {a,
b,c
},
- { a,
+ { a,
b,c
},
@@ -337,7 +337,7 @@ Y =:= 4711 ->
a,
b
},
-
+
<<1:8,
2:8
>>,
@@ -359,21 +359,21 @@ Y =:= 4711 ->
c
),
-
+
(
a,
b,
c
),
- call(2#42423 bor
+ call(2#42423 bor
#4234,
2#5432,
other_arg),
ok;
-indent_basics(Xlongname,
+indent_basics(Xlongname,
#struct{a=Foo,
- b=Bar},
+ b=Bar},
[X|
Y]) ->
testing_next_clause,
@@ -451,13 +451,13 @@ indent_icr(Z) -> % icr = if case receive
%% receive
- receive
+ receive
{Z,_,_} ->
X = 43 div 4,
foo(X);
Z ->
X = 43 div 4,
- foo(X)
+ foo(X)
end,
receive
{Z,_,_} ->
@@ -473,33 +473,33 @@ indent_icr(Z) -> % icr = if case receive
foo(X);
Z ->
X = 43 div 4,
- foo(X)
+ foo(X)
after infinity ->
foo(X),
asd(X),
5*43
end,
receive
- after 10 ->
+ after 10 ->
foo(X),
asd(X),
5*43
end,
ok.
-
+
indent_fun() ->
%% Changed fun to one indention level
-Var = spawn(fun(X)
+Var = spawn(fun(X)
when X == 2;
- X > 10 ->
+ X > 10 ->
hello,
- case Hello() of
- true when is_atom(X) ->
+ case Hello() of
+ true when is_atom(X) ->
foo;
false ->
bar
end;
- (Foo) when is_atom(Foo),
+ (Foo) when is_atom(Foo),
is_integer(X) ->
X = 6* 45,
Y = true andalso
@@ -522,14 +522,14 @@ Fact(0) ->
indent_try_catch() ->
try
- io:format(stdout, "Parsing file ~s, ",
+ io:format(stdout, "Parsing file ~s, ",
[St0#leex.xfile]),
- {ok,Line3,REAs,Actions,St3} =
+ {ok,Line3,REAs,Actions,St3} =
parse_rules(Xfile, Line2, Macs, St2)
catch
exit:{badarg,R} ->
foo(R),
- io:format(stdout,
+ io:format(stdout,
"ERROR reason ~p~n",
R);
error:R % AD added clause
@@ -544,7 +544,7 @@ indent_try_catch() ->
foo(R);
error:R ->
foo(R),
- io:format(stdout,
+ io:format(stdout,
"ERROR reason ~p~n",
R)
after
@@ -577,12 +577,12 @@ indent_try_catch() ->
catch
exit:{badarg,R} ->
foo(R),
- io:format(stdout,
+ io:format(stdout,
"ERROR reason ~p~n",
R);
error:R ->
foo(R),
- io:format(stdout,
+ io:format(stdout,
"ERROR reason ~p~n",
R)
after
@@ -593,7 +593,7 @@ indent_try_catch() ->
end;
indent_try_catch() ->
try foo()
- after
+ after
foo(),
bar(with_long_arg,
with_second_arg)
@@ -602,16 +602,16 @@ indent_try_catch() ->
indent_catch() ->
D = B +
float(43.1),
-
+
B = catch oskar(X),
-
- A = catch (baz +
+
+ A = catch (baz +
bax),
catch foo(),
- C = catch B +
+ C = catch B +
float(43.1),
-
+
case catch foo(X) of
A ->
B
@@ -673,9 +673,9 @@ indent_binary() ->
indent_comprehensions() ->
-%% I don't have a good idea how we want to handle this
+%% I don't have a good idea how we want to handle this
%% but they are here to show how they are indented today.
-Result1 = [X ||
+Result1 = [X ||
#record{a=X} <- lists:seq(1, 10),
true = (X rem 2)
],
@@ -683,7 +683,7 @@ Result2 = [X || <<X:32,_:32>> <= <<0:512>>,
true = (X rem 2)
],
-Binary1 = << <<X:8>> ||
+Binary1 = << <<X:8>> ||
#record{a=X} <- lists:seq(1, 10),
true = (X rem 2)
>>,
diff --git a/lib/tools/examples/xref_examples.erl b/lib/tools/examples/xref_examples.erl
index 4c082195a2..f7e71c9708 100644
--- a/lib/tools/examples/xref_examples.erl
+++ b/lib/tools/examples/xref_examples.erl
@@ -7,7 +7,7 @@
%% ${HOME}/unused_locals.txt.
script() ->
Root = code:root_dir(),
- Dir = os:getenv("HOME"),
+ {ok,[[Dir]]} = init:get_argument(home),
Server = s,
xref:start(Server),
{ok, _Relname} = xref:add_release(Server, code:lib_dir(), {name,otp}),
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index 8db23dd151..d1a4624419 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -1636,6 +1636,11 @@ trace_handler({trace_ts, Pid, gc_major_start, _Func, TS} = Trace, Table, _, Dump
dump_stack(Dump, get(Pid), Trace),
trace_gc_start(Table, Pid, TS),
TS;
+
+trace_handler({trace_ts, Pid, gc_start, _Func, TS} = Trace, Table, _, Dump) ->
+ dump_stack(Dump, get(Pid), Trace),
+ trace_gc_start(Table, Pid, TS),
+ TS;
%%
%% gc_end
@@ -1648,6 +1653,12 @@ trace_handler({trace_ts, Pid, gc_major_end, _Func, TS} = Trace, Table, _, Dump)
dump_stack(Dump, get(Pid), Trace),
trace_gc_end(Table, Pid, TS),
TS;
+
+trace_handler({trace_ts, Pid, gc_end, _Func, TS} = Trace, Table, _, Dump) ->
+ dump_stack(Dump, get(Pid), Trace),
+ trace_gc_end(Table, Pid, TS),
+ TS;
+
%%
%% link
trace_handler({trace_ts, Pid, link, _OtherPid, TS} = Trace,
@@ -1691,6 +1702,12 @@ trace_handler({trace_ts, Pid, send, _OtherPid, _Msg, TS} = Trace,
dump_stack(Dump, get(Pid), Trace),
TS;
%%
+%% send_to_non_existing_process
+trace_handler({trace_ts, Pid, send_to_non_existing_process, _OtherPid, _Msg, TS} = Trace,
+ _Table, _, Dump) ->
+ dump_stack(Dump, get(Pid), Trace),
+ TS;
+%%
%% 'receive'
trace_handler({trace_ts, Pid, 'receive', _Msg, TS} = Trace,
_Table, _, Dump) ->
diff --git a/lib/tools/src/make.erl b/lib/tools/src/make.erl
index 26378f28a0..37e67cbe34 100644
--- a/lib/tools/src/make.erl
+++ b/lib/tools/src/make.erl
@@ -317,5 +317,7 @@ check_includes2(Epp, File, ObjMTime) ->
epp:close(Epp),
false;
{error, _Error} ->
+ check_includes2(Epp, File, ObjMTime);
+ {warning, _Warning} ->
check_includes2(Epp, File, ObjMTime)
end.
diff --git a/lib/tools/src/tags.erl b/lib/tools/src/tags.erl
index b833d96c19..fff67eb0fd 100644
--- a/lib/tools/src/tags.erl
+++ b/lib/tools/src/tags.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src
index a00969eabe..4c7dd24006 100644
--- a/lib/tools/src/tools.app.src
+++ b/lib/tools/src/tools.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@
{env, [{file_util_search_methods,[{"", ""}, {"ebin", "esrc"}, {"ebin", "src"}]}
]
},
- {runtime_dependencies, ["stdlib-2.5","runtime_tools-1.8.14",
+ {runtime_dependencies, ["stdlib-3.1","runtime_tools-1.8.14",
"kernel-3.0","inets-5.10","erts-7.0",
"compiler-5.0"]}
]
diff --git a/lib/tools/src/xref_base.erl b/lib/tools/src/xref_base.erl
index bb9815f9b0..f298a1ce81 100644
--- a/lib/tools/src/xref_base.erl
+++ b/lib/tools/src/xref_base.erl
@@ -746,7 +746,7 @@ read_a_module({Dir, BaseName}, AppName, Builtins, Verbose, Warnings, Mode) ->
message(Warnings, no_debug_info, [File]),
no;
{ok, M, Data, UnresCalls0} ->
- message(Verbose, done, [File]),
+ message(Verbose, done_file, [File]),
%% Remove duplicates. Identical unresolved calls on the
%% same line are counted as _one_ unresolved call.
UnresCalls = usort(UnresCalls0),
@@ -1842,6 +1842,8 @@ message(true, What, Arg) ->
set_up ->
io:format("Setting up...", Arg);
done ->
+ io:format("done~n", Arg);
+ done_file ->
io:format("done reading ~ts~n", Arg);
error ->
io:format("error~n", Arg);
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index b4c9264b30..90e113c178 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -1001,41 +1001,40 @@ otp_6115(Config) when is_list(Config) ->
%% Cover compile f1, but not f2
{ok, f1} = cover:compile(f1),
+ %% This test used to ensure that a process containing a
+ %% fun refering to cover compiled code was killed.
+ %% check_process_code may however ignore funs as of ERTS
+ %% version 8.1. The test has therefore been rewritten to
+ %% check that a process with a direct reference (in this
+ %% case a return address) to the code is killed.
+ %%
%% If f1 is cover compiled, a process P is started with a
- %% reference to the fun created in start_fail/0, and cover:stop() is
- %% called, then P should be killed.
- %% This is because (the fun held by P) references the cover
+ %% direct reference to the f1, and cover:stop() is called,
+ %% then P should be killed.
+ %% This is because of the return address to the cover
%% compiled code which should be *unloaded* when cover:stop() is
%% called -- running cover compiled code when there is no cover
%% server and thus no ets tables to bump counters in, makes no
%% sense.
- Pid1 = f1:start_a(),
- Pid2 = f1:start_b(),
+ Pid = spawn(fun () -> f1:non_tail_call_f2_wait() end),
%% Now stop cover
cover:stop(),
%% Ensure that f1 is loaded (and not cover compiled), and that
- %% both Pid1 and Pid2 are dead.
+ %% both Pid is dead.
case code:which(f1) of
Beam when is_list(Beam) ->
ok;
Other ->
ct:fail({"f1 is not reloaded", Other})
end,
- case process_info(Pid1) of
+ case process_info(Pid) of
undefined ->
ok;
- _PI1 ->
- RefToOldP1 = erlang:check_process_code(Pid1, f1),
- ct:fail({"Pid1 still alive", RefToOldP1})
- end,
- case process_info(Pid2) of
- undefined ->
- ok;
- _PI2 ->
- RefToOldP2 = erlang:check_process_code(Pid1, f2),
- ct:fail({"Pid2 still alive", RefToOldP2})
+ _PI ->
+ RefToOldP = erlang:check_process_code(Pid, f1),
+ ct:fail({"Pid still alive", RefToOldP})
end,
file:set_cwd(CWD),
diff --git a/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl b/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl
index 5399b33f19..fc4a62e70e 100644
--- a/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl
+++ b/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl
@@ -1,13 +1,6 @@
-module(f1).
--export([start_a/0, start_b/0]).
+-export([non_tail_call_f2_wait/0]).
-start_a() ->
- f2:start(fun() ->
- ok
- end).
-
-start_b() ->
- f2:start(fun fun1/0).
-
-fun1() ->
- ok.
+non_tail_call_f2_wait() ->
+ f2:wait(),
+ im_back.
diff --git a/lib/tools/test/cover_SUITE_data/otp_6115/f2.erl b/lib/tools/test/cover_SUITE_data/otp_6115/f2.erl
index 72a6a64c4d..4bc88035c7 100644
--- a/lib/tools/test/cover_SUITE_data/otp_6115/f2.erl
+++ b/lib/tools/test/cover_SUITE_data/otp_6115/f2.erl
@@ -1,13 +1,5 @@
-module(f2).
--export([start/1]).
+-export([wait/0]).
-start(Fun) ->
- spawn(fun() ->
- wait(Fun)
- end).
-
-wait(Fun) ->
- receive
- go ->
- Fun()
- end.
+wait() ->
+ receive after infinity -> ok end.
diff --git a/lib/tools/test/make_SUITE_data/test1.erl b/lib/tools/test/make_SUITE_data/test1.erl
index f4a133008e..9e21bdc767 100644
--- a/lib/tools/test/make_SUITE_data/test1.erl
+++ b/lib/tools/test/make_SUITE_data/test1.erl
@@ -3,6 +3,8 @@
-vsn('$Revision: /main/release/2 $').
-compile(export_all).
+-warning("a warning").
+
f1() ->
true.
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index ce30fb711a..01dbac6ecb 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -50,7 +50,7 @@
-export([analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1]).
--export([format_error/1, otp_7423/1, otp_7831/1, otp_10192/1]).
+-export([format_error/1, otp_7423/1, otp_7831/1, otp_10192/1, otp_13708/1]).
-import(lists, [append/2, flatten/1, keysearch/3, member/2, sort/1, usort/1]).
@@ -82,7 +82,7 @@ groups() ->
fun_mfa_r14, fun_mfa_vars, qlc]},
{analyses, [],
[analyze, basic, md, q, variables, unused_locals]},
- {misc, [], [format_error, otp_7423, otp_7831, otp_10192]}].
+ {misc, [], [format_error, otp_7423, otp_7831, otp_10192, otp_13708]}].
init_per_suite(Conf) when is_list(Conf) ->
@@ -2393,6 +2393,19 @@ otp_10192(Conf) when is_list(Conf) ->
xref:stop(s),
ok.
+%% OTP-10192. Allow filenames with character codes greater than 126.
+otp_13708(Conf) when is_list(Conf) ->
+ {ok, _} = start(s),
+ ok = xref:set_default(s, [{verbose, true}]),
+ {ok, []} = xref:q(s,"E"),
+ xref:stop(s),
+
+ CopyDir = ?copydir,
+ Dir = fname(CopyDir,"lib_test"),
+ {ok, _} = start(s),
+ ok = xref:set_library_path(s, [Dir], [{verbose, true}]),
+ xref:stop(s).
+
%%%
%%% Utilities
%%%
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 8c889cbe4e..f60da27c44 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.8.4
+TOOLS_VSN = 2.9.1
diff --git a/lib/typer/doc/src/notes.xml b/lib/typer/doc/src/notes.xml
index 9ef5ca1c70..077219dcbc 100644
--- a/lib/typer/doc/src/notes.xml
+++ b/lib/typer/doc/src/notes.xml
@@ -31,6 +31,20 @@
</header>
<p>This document describes the changes made to TypEr.</p>
+<section><title>TypEr 0.9.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug concerning parameterized opaque types. </p>
+ <p>
+ Own Id: OTP-14130</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>TypEr 0.9.11</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/typer/src/typer.app.src b/lib/typer/src/typer.app.src
index 974091b44c..e0be937cc3 100644
--- a/lib/typer/src/typer.app.src
+++ b/lib/typer/src/typer.app.src
@@ -7,5 +7,5 @@
{registered, []},
{applications, [compiler, dialyzer, hipe, kernel, stdlib]},
{env, []},
- {runtime_dependencies, ["stdlib-2.0","kernel-3.0","hipe-3.10.3","erts-6.0",
- "dialyzer-2.7","compiler-5.0"]}]}.
+ {runtime_dependencies, ["stdlib-3.0","kernel-5.0","hipe-3.15.4","erts-8.0",
+ "dialyzer-3.1","compiler-7.0"]}]}.
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index 5c82750a21..4aad0b4347 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -143,8 +143,9 @@ extract(#analysis{macros = Macros,
MergedRecords = dialyzer_utils:merge_records(NewRecords, OldRecords),
CodeServer2 = dialyzer_codeserver:set_temp_records(MergedRecords, CodeServer1),
CodeServer3 = dialyzer_codeserver:finalize_exported_types(NewExpTypes, CodeServer2),
- CodeServer4 = dialyzer_utils:process_record_remote_types(CodeServer3),
- dialyzer_contracts:process_contract_remote_types(CodeServer4)
+ {CodeServer4, RecordDict} =
+ dialyzer_utils:process_record_remote_types(CodeServer3),
+ dialyzer_contracts:process_contract_remote_types(CodeServer4, RecordDict)
catch
throw:{error, ErrorMsg} ->
compile_error(ErrorMsg)
@@ -156,7 +157,7 @@ extract(#analysis{macros = Macros,
fun(Module, TmpPlt) ->
{ok, ModuleContracts} = dict:find(Module, Contracts),
SpecList = [{MFA, Contract}
- || {MFA, {_FileLine, Contract}} <- dict:to_list(ModuleContracts)],
+ || {MFA, {_FileLine, Contract}} <- maps:to_list(ModuleContracts)],
dialyzer_plt:insert_contract_list(TmpPlt, SpecList)
end,
NewTrustPLT = lists:foldl(FoldFun, TrustPLT, Modules),
@@ -172,8 +173,10 @@ get_type_info(#analysis{callgraph = CallGraph,
StrippedCallGraph = remove_external(CallGraph, TrustPLT),
%% io:format("--- Analyzing callgraph... "),
try
- NewPlt = dialyzer_succ_typings:analyze_callgraph(StrippedCallGraph,
- TrustPLT, CodeServer),
+ NewMiniPlt = dialyzer_succ_typings:analyze_callgraph(StrippedCallGraph,
+ TrustPLT,
+ CodeServer),
+ NewPlt = dialyzer_plt:restore_full_plt(NewMiniPlt),
Analysis#analysis{callgraph = StrippedCallGraph, trust_plt = NewPlt}
catch
error:What ->
@@ -224,7 +227,7 @@ get_external(Exts, Plt) ->
-type fa() :: {atom(), arity()}.
-type func_info() :: {line(), atom(), arity()}.
--record(info, {records = map__new() :: map_dict(),
+-record(info, {records = maps:new() :: erl_types:type_table(),
functions = [] :: [func_info()],
types = map__new() :: map_dict(),
edoc = false :: boolean()}).
@@ -267,7 +270,7 @@ write_inc_files(Inc) ->
Functions = [Key || {Key, _} <- Val],
Val1 = [{{F,A},Type} || {{_Line,F,A},Type} <- Val],
Info = #info{types = map__from_list(Val1),
- records = map__new(),
+ records = maps:new(),
%% Note we need to sort functions here!
functions = lists:keysort(1, Functions)},
%% io:format("Types ~p\n", [Info#info.types]),
@@ -849,8 +852,9 @@ collect_info(Analysis) ->
TmpCServer1 = dialyzer_codeserver:set_temp_records(MergedRecords, TmpCServer),
TmpCServer2 =
dialyzer_codeserver:finalize_exported_types(MergedExpTypes, TmpCServer1),
- TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2),
- dialyzer_contracts:process_contract_remote_types(TmpCServer3)
+ {TmpCServer3, RecordDict} =
+ dialyzer_utils:process_record_remote_types(TmpCServer2),
+ dialyzer_contracts:process_contract_remote_types(TmpCServer3, RecordDict)
catch
throw:{error, ErrorMsg} ->
fatal_error(ErrorMsg)
diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk
index ed12e067c1..fe8f0446a5 100644
--- a/lib/typer/vsn.mk
+++ b/lib/typer/vsn.mk
@@ -1 +1 @@
-TYPER_VSN = 0.9.11
+TYPER_VSN = 0.9.12
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 54635bdd2e..7e3766a43b 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -354,6 +354,7 @@ handle_arg_opt({single,Opt},P=#arg{type=T}) -> P#arg{type=T#type{single=Opt}};
handle_arg_opt({base,{Opt, Sz}}, P=#arg{type=T}) -> P#arg{type=T#type{base=Opt, size=Sz}};
handle_arg_opt({base,Opt}, P=#arg{type=T}) -> P#arg{type=T#type{base=Opt}};
handle_arg_opt({c_only,Opt},P) -> P#arg{where=c, alt=Opt};
+handle_arg_opt(list_binary, P) -> P#arg{alt=list_binary};
handle_arg_opt(string, P=#arg{type=T}) -> P#arg{type=T#type{base=string}};
handle_arg_opt({string,Max,Sz}, P=#arg{type=T}) ->
P#arg{type=T#type{base=string, size={Max,Sz}}}.
@@ -588,7 +589,7 @@ lookup(Name,[_|R],Def) ->
lookup(Name,R,Def);
lookup(_,[], Def) -> Def.
-setup_idx_binary(Name,Ext,_Opts) ->
+setup_idx_binary(Name,Ext, Opts) ->
FuncName = Name ++ Ext,
Func = #func{params=Args} = get(FuncName),
Id = next_id(function),
@@ -607,8 +608,7 @@ setup_idx_binary(Name,Ext,_Opts) ->
ok;
(_) -> ok
end, Args),
-
- case setup_idx_binary(Args, []) of
+ case setup_idx_binary_1(Args, []) of
ignore ->
put(FuncName, Func#func{id=Id}),
Name++Ext;
@@ -624,30 +624,41 @@ setup_idx_binary(Name,Ext,_Opts) ->
[FuncName,Extra]
end.
-setup_idx_binary([A=#arg{in=true,type=T=#type{base=idx_binary}}|R], Acc) ->
+setup_idx_binary_1([A=#arg{in=true,type=T=#type{base=idx_binary}}|R], Acc) ->
A1 = A#arg{type=T#type{base=guard_int,size=4}},
A2 = A#arg{type=T#type{base=binary}},
Head = reverse(Acc),
- case setup_idx_binary(R, []) of
+ case setup_idx_binary_1(R, []) of
ignore ->
{bin, Head ++ [A1|R], Head ++ [A2|R]};
{bin, R1,R2} ->
{bin, Head ++ [A1|R1], Head ++ [A2|R2]}
end;
-setup_idx_binary([A=#arg{in=true,type=T=#type{single={tuple,matrix}}}|R], Acc) ->
+setup_idx_binary_1([A=#arg{in=true,type=T=#type{base=int,size=4},alt=list_binary}|R], Acc) ->
+ A1 = A#arg{type=T#type{base=guard_int}},
+ A2 = A#arg{type=T#type{base=binary}},
+ Head = reverse(Acc),
+ case setup_idx_binary_1(R, []) of
+ ignore ->
+ {bin, Head ++ [A1|R], Head ++ [A2|R]};
+ {bin, R1,R2} ->
+ {bin, Head ++ [A1|R1], Head ++ [A2|R2]}
+ end;
+
+setup_idx_binary_1([A=#arg{in=true,type=T=#type{single={tuple,matrix}}}|R], Acc) ->
A1 = A#arg{type=T#type{single={tuple, matrix12}}},
A2 = A#arg{type=T#type{single={tuple, 16}}},
Head = reverse(Acc),
- case setup_idx_binary(R, []) of
+ case setup_idx_binary_1(R, []) of
ignore ->
{matrix, Head ++ [A1|R], Head ++ [A2|R]};
{matrix, R1,R2} ->
{matrix, Head ++ [A1|R1], Head ++ [A2|R2]}
end;
-setup_idx_binary([H|R],Acc) ->
- setup_idx_binary(R,[H|Acc]);
-setup_idx_binary([],_) -> ignore.
-
+setup_idx_binary_1([H|R],Acc) ->
+ setup_idx_binary_1(R,[H|Acc]);
+setup_idx_binary_1([],_) -> ignore.
+
is_equal(F1=#func{type=T1,params=A1},F2=#func{type=T2,params=A2}) ->
Equal = is_equal_type(T1,T2) andalso is_equal_args(A1,A2),
case Equal of
diff --git a/lib/wx/api_gen/gl_gen_c.erl b/lib/wx/api_gen/gl_gen_c.erl
index c6d4f3a520..53c194a315 100644
--- a/lib/wx/api_gen/gl_gen_c.erl
+++ b/lib/wx/api_gen/gl_gen_c.erl
@@ -123,20 +123,14 @@ declare_var(A=#arg{name=N,in=false,type=#type{name=T,base=B,single={list,Sz}}})
when is_number(Sz) ->
w(" ~s ~s[~p] = {~s};~n", [T,N,Sz,args(fun zero/1,",",lists:duplicate(Sz,B))]),
A;
-declare_var(A=#arg{name=N,in=false,type=#type{name=T,base=string,size={Max,_}, single=Single}}) ->
+declare_var(A=#arg{name=N,in=false,type=#type{name=T,base=string,size={Max,_}}}) ->
case is_integer(Max) of
- true ->
+ true ->
w(" ~s ~s[~p];~n", [T,N,Max]);
false ->
- %% w(" ~s ~s[*~s];~n", [T,N,Max]),
- w(" ~s *~s;~n", [T,N]),
+ w(" ~s *~s;~n", [T,N]),
w(" ~s = (~s *) driver_alloc(sizeof(~s) * *~s);~n", [N,T,T,Max]),
- store_free(N)
- %% case Single of
- %% {list, _, _} ->
- %% w(" ~s *~s_p = ~s;~n", [T,N,N]);
- %% _ -> ok
- %% end
+ store_free(N)
end,
A;
declare_var(A=#arg{name=N,in=false,type=#type{base=binary,size={MaxSz, _}}}) ->
@@ -163,9 +157,9 @@ declare_var(A=#arg{name=N,in=false,
type=#type{name=T,base=B,by_val=false,single=true}}) ->
w(" ~s ~s[1] = {~s};~n", [T,N,zero(B)]),
A;
-declare_var(A=#arg{where=c, type=#type{name=T}, alt={size,Var}}) ->
+declare_var(A=#arg{where=c, type=#type{name=T}, alt={size,Var}}) ->
w(" ~s ~s_size = bins_sz[~p];~n", [T, Var, get(bin_count)]),
- A;
+ A;
declare_var(A=#arg{where=_}) ->
A.
@@ -194,9 +188,16 @@ decode_arg(P=#arg{where=erl},A) -> {P,A};
decode_arg(P=#arg{where=c},A) -> {P,A};
decode_arg(P=#arg{in=false},A) -> {P,A};
-decode_arg(P=#arg{name=Name,type=#type{name=Type,base=binary}},A0) ->
+decode_arg(P=#arg{name=Name,alt=Alt,type=#type{name=Type,base=binary}},A0) ->
w(" ~s *~s = (~s *) bins[~p];~n", [Type,Name,Type,next_id(bin_count)]),
- {P, A0};
+ case Alt of
+ list_binary ->
+ A = align(4, A0),
+ w(" int * ~sLen = (int *) bp; bp += 4; (void) ~sLen;~n", [Name, Name]),
+ {P, A};
+ _ ->
+ {P, A0}
+ end;
decode_arg(P=#arg{name=Name,type=#type{name=Type,base=memory}},A0) ->
w(" ~s *~s = (~s *) bins[~p];~n", [Type,Name,Type,next_id(bin_count)]),
{P, A0};
@@ -217,7 +218,7 @@ decode_arg(P=#arg{name=Name,type=#type{size=Sz,single=list,name=Type}},A0) ->
A = align(max([Sz,4]),A0),
w(" int * ~sLen = (int *) bp; bp += ~p;~n", [Name, max([4,Sz])]),
w(" ~s * ~s = (~s *) bp; ", [Type,Name,Type]),
- w(" bp += (8-((*~sLen*~p+~p)%8))%8;~n", [Name,Sz,A]),
+ w(" bp += *~sLen*~p + (8-((*~sLen*~p+~p)%8))%8;~n", [Name,Sz,Name,Sz,A]),
{P, 0};
decode_arg(P=#arg{name=Name,type=#type{size=TSz,name=Type,single={tuple,undefined}}},A0) ->
A = align(TSz,A0),
diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl
index 1be8d775be..3ad14825dd 100644
--- a/lib/wx/api_gen/gl_gen_erl.erl
+++ b/lib/wx/api_gen/gl_gen_erl.erl
@@ -116,7 +116,7 @@ gl_api(Fs) ->
w("call(Op, Args) ->~n", []),
w(" Port = get(opengl_port), ~n", []),
w(" _ = erlang:port_control(Port,Op,Args),~n", []),
- w(" rec().~n", []),
+ w(" rec(Op).~n", []),
w(" ~n", []),
w("%% @hidden~n", []),
w("cast(Op, Args) ->~n", []),
@@ -125,11 +125,15 @@ gl_api(Fs) ->
w(" ok.~n", []),
w(" ~n", []),
w("%% @hidden~n", []),
- w("rec() ->~n", []),
- w(" receive ~n", []),
+ w("rec(Op) ->~n", []),
+ w(" receive~n", []),
w(" {'_egl_result_', Res} -> Res;~n", []),
- w(" {'_egl_error_', Op, Res} -> error({error,Res,Op})~n", []),
- w(" end. ~n", []),
+ w(" {'_egl_error_', Op, Res} -> error({error,Res,Op});~n", []),
+ w(" {'_egl_error_', Other, Res} ->~n ", []),
+ w(" Err = io_lib:format(\"~~p in op: ~~p\", [Res, Other]),~n", []),
+ w(" error_logger:error_report([{gl, error}, {message, lists:flatten(Err)}]),~n", []),
+ w(" rec(Op)~n", []),
+ w(" end.~n", []),
w("~n", []),
w("%% @hidden~n", []),
w("send_bin(Bin) when is_binary(Bin) ->~n", []),
@@ -492,6 +496,8 @@ doc_arg_type2(#type{base=string, single=list}) ->
"iolist()";
doc_arg_type2(T=#type{single={tuple,Sz}}) ->
"{" ++ args(fun doc_arg_type3/1, ",", lists:duplicate(Sz,T)) ++ "}";
+doc_arg_type2(#type{base=guard_int, single=list}) ->
+ "[integer()]|mem()";
doc_arg_type2(T=#type{single=list}) ->
"[" ++ doc_arg_type3(T) ++ "]";
doc_arg_type2(T=#type{single={list, _Max}}) ->
@@ -512,7 +518,9 @@ doc_arg_type3(#type{base=binary}) -> "binary()";
doc_arg_type3(#type{base=memory}) -> "mem()".
guard_test(As) ->
- Str = args(fun(#arg{name=N,type=#type{base=guard_int}}) ->
+ Str = args(fun(#arg{name=N,type=#type{base=guard_int, single=list}}) ->
+ " is_list("++erl_arg_name(N)++")";
+ (#arg{name=N,type=#type{base=guard_int}}) ->
" is_integer("++erl_arg_name(N)++")";
(_) ->
skip
@@ -522,6 +530,13 @@ guard_test(As) ->
Other -> " when " ++ Other
end.
+pre_marshal([#arg{name=N,in=true, type=#type{base=binary, single=list}=T, alt=list_binary}=A|R]) ->
+ w(" send_bin(~s),~n", [erl_arg_name(N)]),
+ w(" ~sLen = byte_size(if is_binary(~s) -> ~s; is_tuple(~s) -> element(2, ~s) end) div 4,~n",
+ [erl_arg_name(N),erl_arg_name(N), erl_arg_name(N), erl_arg_name(N), erl_arg_name(N)]),
+ Type = T#type{base=int, by_val=true, single=true, ref=undefined},
+ Arg=A#arg{name=N++"Len", where=both, type=Type},
+ [Arg|pre_marshal(R)];
pre_marshal([#arg{name=N,in=true,type=#type{base=binary}}|R]) ->
w(" send_bin(~s),~n", [erl_arg_name(N)]),
pre_marshal(R);
@@ -530,8 +545,18 @@ pre_marshal([#arg{name=N,type=#type{base=memory}}|R]) ->
pre_marshal(R);
pre_marshal([A=#arg{name=N,type=#type{base=string,single=list}}|R]) ->
%% With null terminations
- w(" ~sTemp = list_to_binary([[Str|[0]] || Str <- ~s ]),~n",
+ w(" ~sTemp = list_to_binary([[Str|[0]] || Str <- ~s ]),~n",
[erl_arg_name(N), erl_arg_name(N)]),
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
+ [A|pre_marshal(R)];
+pre_marshal([A=#arg{name=N,type=#type{base=string,single=true,ref={pointer,1}}}|R]) ->
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
+ [A|pre_marshal(R)];
+pre_marshal([A=#arg{name=N,type=#type{single=list}}|R]) ->
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
+ [A|pre_marshal(R)];
+pre_marshal([A=#arg{name=N,type=#type{single={tuple_list,_}}}|R]) ->
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
[A|pre_marshal(R)];
pre_marshal([A|R]) ->
[A|pre_marshal(R)];
@@ -583,9 +608,9 @@ marshal_arg(#type{size=BSz,name=Type,single={tuple,matrix12}},Name,A0) ->
align(BSz,16,A0,All);
marshal_arg(#type{size=Sz,name=Type,base=Base,single=list},Name,A0)
- when Base =:= float; Base =:= int ->
+ when Base =:= float; Base =:= int; Base =:= guard_int ->
KeepA = case Sz of 8 -> "0:32,"; _ -> "" end,
- Str0 = "(length("++Name++")):?GLuint,"++KeepA++"\n"
+ Str0 = Name++"Len:?GLuint,"++KeepA++"\n"
" (<< <<C:?"++Type++">> || C <- "++Name++">>)/binary",
{Str,Align} = align(max([Sz,4]),A0,Str0),
align_after(Sz,Align,0,1,Name,Str);
@@ -606,7 +631,7 @@ marshal_arg(#type{base=string,single=true,ref={pointer,1}},Name,A0) ->
marshal_arg(#type{base=string,single=list,ref={pointer,2}},Name,A0) ->
Str0 =
- "(length("++Name++")):?GLuint,"
+ Name++"Len:?GLuint,"
"(size("++Name ++ "Temp)):?GLuint,"
"(" ++ Name ++ "Temp)/binary",
{Str,A} = align(4,A0,Str0),
@@ -620,7 +645,7 @@ marshal_arg(#type{size=Sz,name=Type,single={tuple_list,TSz}},Name,A0) ->
TBin = args(fun(ElName) -> ElName ++ ":?" ++ Type end, ",", Names),
KeepA = case Sz of 8 -> "0:32,"; 4 -> "" end,
- Str0 = "(length("++Name++")):?GLuint,"++KeepA++"\n"
+ Str0 = Name++"Len:?GLuint,"++KeepA++"\n"
" (<< <<"++TBin++">> || {"++TTup++"} <- "++Name++">>)/binary",
align(Sz,A0,Str0);
@@ -656,19 +681,19 @@ align(8,_,7,Str) -> {"0:8," ++Str, 0}.
align_after(8,0,_Add,_Multiplier,_Name,Str) -> {Str,0};
align_after(4,0,Add,Mult,Name,Str) ->
Extra = extra_align(Add,Mult),
- Align = ",0:(((length("++Name++")"++Extra++") rem 2)*32)",
+ Align = ",0:((("++Name++"Len"++Extra++") rem 2)*32)",
{Str ++ Align,0};
align_after(4,4,Add,Mult,Name,Str) ->
Extra = extra_align(Add,Mult),
- Align = ",0:(((1+length("++Name++")"++Extra++") rem 2)*32)",
+ Align = ",0:(((1+"++Name++"Len"++Extra++") rem 2)*32)",
{Str ++ Align,0};
align_after(2,A,Add,Mult,Name,Str) when (A rem 2) =:= 0 ->
Extra = extra_align(A+Add*2,Mult),
- Align = ",0:((8-((length("++Name++")*2"++Extra++") rem 8)) rem 8)",
+ Align = ",0:((8-(("++Name++"Len*2"++Extra++") rem 8)) rem 8)",
{Str ++ Align,0};
align_after(1,A,Add,Mult,Name,Str) ->
Extra = extra_align(A+Add,Mult),
- Align = ",0:((8-((length("++Name++")"++Extra++") rem 8)) rem 8)",
+ Align = ",0:((8-(("++Name++"Len"++Extra++") rem 8)) rem 8)",
{Str ++ Align,0};
align_after(Sz,A,Add,Mult,Name,Str) ->
io:format("~p ~p with ~p ~p ~s~n, ~p", [Sz,A,Add,Mult,Name,Str]),
diff --git a/lib/wx/api_gen/glapi.conf b/lib/wx/api_gen/glapi.conf
index 59fa8f7727..57f30a3f7e 100644
--- a/lib/wx/api_gen/glapi.conf
+++ b/lib/wx/api_gen/glapi.conf
@@ -181,9 +181,9 @@
{"glLoadTransposeMatrix", {"m", {single,{tuple,matrix}}}}.
{"glMultTransposeMatrix", {"m",{single,{tuple,matrix}}}}.
-{"glMultiDrawArrays", [{"first", [in,{single,list}]},
- {"count", [in,{single,list}]},
- {"primcount", {c_only, {length,"first"}}}]}.
+{"glMultiDrawArrays", [{"first", [in,{single,list}, list_binary]},
+ {"count", [in,{single,list}, list_binary]},
+ {"primcount", {c_only, {length,"count"}}}]}.
{"glGenQueries", {"ids", {single,{list, "n", "n"}}}}.
{"glGetQueryiv", {"params", {single, true}}}.
diff --git a/lib/wx/api_gen/wx_doxygen.conf b/lib/wx/api_gen/wx_doxygen.conf
index f4d3c99ec0..a96db00254 100644
--- a/lib/wx/api_gen/wx_doxygen.conf
+++ b/lib/wx/api_gen/wx_doxygen.conf
@@ -252,7 +252,7 @@ PREDEFINED = \
wxUSE_POPUPWIN=1 \
wxUSE_SYSTEM_OPTIONS=1 \
wxUSE_INTL=1 \
- wxABI_VERSION=20809 \
+ wxABI_VERSION=20812 \
__WXGTK24__=1 \
__WXGTK20__=1 \
__WXGTK__=1 \
diff --git a/lib/wx/api_gen/wx_extra/added_func.h b/lib/wx/api_gen/wx_extra/added_func.h
index 417188cc8a..bffe391140 100644
--- a/lib/wx/api_gen/wx_extra/added_func.h
+++ b/lib/wx/api_gen/wx_extra/added_func.h
@@ -34,8 +34,13 @@ class wxToolBar {
};
-class wxWindow {
+/* class wxWindow { */
+/* public: */
+/* bool IsDoubleBuffered(); */
+/* void SetDoubleBuffered(bool on); */
+/* }; */
+
+class wxWindowGTK {
public:
- bool IsDoubleBuffered();
- void SetDoubleBuffered(bool on);
+ double GetContentScaleFactor();
};
diff --git a/lib/wx/api_gen/wx_extra/wxListCtrl.erl b/lib/wx/api_gen/wx_extra/wxListCtrl.erl
index acdb69fdeb..355a4cdfd1 100644
--- a/lib/wx/api_gen/wx_extra/wxListCtrl.erl
+++ b/lib/wx/api_gen/wx_extra/wxListCtrl.erl
@@ -43,33 +43,36 @@ SortItems>>
<<EXPORT:wxListCtrl new/0, new/1, new/2 wxListCtrl:EXPORT>>
<<wxListCtrl_new_0
-%% @spec () -> wxListCtrl()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>.
+-spec new() -> wxListCtrl().
new() ->
wxe_util:construct(~s, <<>>).
wxListCtrl_new_0>>
<<wxListCtrl_new_2
-%% @spec (Parent::wxWindow:wxWindow()) -> wxListCtrl()
-%% @equiv new(Parent, [])
+-spec new(Parent) -> wxListCtrl() when
+ Parent::wxWindow:wxWindow().
new(Parent)
when is_record(Parent, wx_ref) ->
new(Parent, []).
-%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxListCtrl()
-%% Option = {winid, integer()} |
-%% {pos, {X::integer(),Y::integer()}} |
-%% {size, {W::integer(),H::integer()}} |
-%% {style, integer()} |
-%% {validator, wx:wx()} |
-%% {onGetItemText, OnGetItemText} |
-%% {onGetItemAttr, OnGetItemAttr} |
-%% {onGetItemColumnImage, OnGetItemColumnImage}
+%% @doc Creates a listctrl with optional callback functions:
%%
-%% OnGetItemText = (This, Item, Column) -> wxString()
-%% OnGetItemAttr = (This, Item) -> wxListItemAttr()
+%% OnGetItemText = (This, Item, Column) -> unicode:charlist()
+%% OnGetItemAttr = (This, Item) -> wxListItemAttr:wxListItemAttr()
%% OnGetItemColumnImage = (This, Item, Column) -> integer()
-%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>.
+%%
+%% See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>.
+-spec new(Parent, [Option]) -> wxListCtrl() when
+ Parent::wxWindow:wxWindow(),
+ Option::{winid, integer()} |
+ {pos, {X::integer(),Y::integer()}} |
+ {size, {W::integer(),H::integer()}} |
+ {style, integer()} |
+ {validator, wx:wx_object()} |
+ {onGetItemText, function()} |
+ {onGetItemAttr, function()} |
+ {onGetItemColumnImage, function()}.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options)->
@@ -101,26 +104,27 @@ wxListCtrl_new_2>>
<<EXPORT:Create create/2, create/3 Create:EXPORT>>
<<Create
-%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow()) -> bool()
%% @equiv create(This,Parent, [])
+-spec create(This, Parent) -> wxListCtrl() when
+ This::wxWindow:wxWindow(),
+ Parent::wxWindow:wxWindow().
create(This,Parent)
when is_record(This, wx_ref),is_record(Parent, wx_ref) ->
create(This,Parent, []).
-%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {winid, integer()} |
-%% {pos, {X::integer(),Y::integer()}} |
-%% {size, {W::integer(),H::integer()}} |
-%% {style, integer()} |
-%% {validator, wx:wx()} |
-%% {onGetItemText, OnGetItemText} |
-%% {onGetItemAttr, OnGetItemAttr} |
-%% {onGetItemColumnImage, OnGetItemColumnImage}
-%%
-%% OnGetItemText = (This, Item, Column) -> wxString()
-%% OnGetItemAttr = (This, Item) -> wxListItemAttr()
-%% OnGetItemColumnImage = (This, Item, Column) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlcreate">external documentation</a>.
+-spec create(This, Parent, [Option]) -> wxListCtrl() when
+ This::wxWindow:wxWindow(),
+ Parent::wxWindow:wxWindow(),
+ Option::{winid, integer()} |
+ {pos, {X::integer(),Y::integer()}} |
+ {size, {W::integer(),H::integer()}} |
+ {style, integer()} |
+ {validator, wx:wx_object()} |
+ {onGetItemText, function()} |
+ {onGetItemAttr, function()} |
+ {onGetItemColumnImage, function()}.
+
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
?CLASS(ThisT,wxListCtrl),
diff --git a/lib/wx/api_gen/wx_extra/wxXmlResource.erl b/lib/wx/api_gen/wx_extra/wxXmlResource.erl
index 7700e2333e..b29ffba7c6 100644
--- a/lib/wx/api_gen/wx_extra/wxXmlResource.erl
+++ b/lib/wx/api_gen/wx_extra/wxXmlResource.erl
@@ -21,8 +21,6 @@
<<EXPORT:xrcctrl xrcctrl/3 xrcctrl:EXPORT>>
<<xrcctrl
-%% @spec (Window::wxWindow:wxWindow(),Name::string(), Type::atom()) -> wx:wxObject()
-
%% @doc Looks up a control with Name in a window created with XML
%% resources. You can use it to set/get values from controls.
%% The object is type casted to <b>Type</b>.
@@ -32,6 +30,10 @@
%% true = wxXmlResource:loadDialog(Xrc, Dlg, Frame, "controls_dialog"), <br />
%% LCtrl = xrcctrl(Dlg, "controls_listctrl", wxListCtrl), <br />
%% wxListCtrl:insertColumn(LCtrl, 0, "Name", [{width, 200}]), <br />
+-spec xrcctrl(Window, Name, Type) -> wx:wx_object() when
+ Window::wxWindow:wxWindow(),
+ Name::string(),
+ Type::atom().
xrcctrl(Window = #wx_ref{}, Name, Type) when is_list(Name), is_atom(Type) ->
%% Func Id ~s
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index cfae2197f8..6979a600f3 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -271,33 +271,31 @@ parse_attr1([{{attr,_}, #xmlElement{content=C, attributes=Attrs}}|R], AttrList0,
#param{where=nowhere} ->
parse_attr1(R,AttrList0,Opts,Res);
_ ->
- case keysearch(prot, #xmlAttribute.name, Attrs) of
- {value, #xmlAttribute{value = "public"}} ->
- {Acc,AttrList} = attr_acc(Param0, AttrList0),
- parse_attr1(R,AttrList,Opts,
- [Param0#param{in=false,prot=public,acc=Acc}|Res]);
- {value, #xmlAttribute{value = "protected"}} ->
- {Acc,AttrList} = attr_acc(Param0, AttrList0),
- parse_attr1(R,AttrList,Opts,
- [Param0#param{in=false,prot=protected,acc=Acc}|Res]);
- {value, #xmlAttribute{value = "private"}} ->
- {Acc,AttrList} = attr_acc(Param0, AttrList0),
- parse_attr1(R,AttrList,Opts,
- [Param0#param{in=false,prot=private,acc=Acc}|Res])
- end
+ {value, #xmlAttribute{value=Type}} =
+ keysearch(prot, #xmlAttribute.name, Attrs),
+ {Param,AttrList} = attr_acc(Param0, list_to_atom(Type), AttrList0),
+ parse_attr1(R,AttrList,Opts,[Param|Res])
end;
parse_attr1([{_Id,_}|R],AttrList,Info, Res) ->
parse_attr1(R,AttrList,Info, Res);
parse_attr1([],Left,_, Res) ->
{reverse(Res), Left}.
-attr_acc(#param{name=N}, List) ->
+attr_acc(#param{name=N}=P, Type, List) ->
Name = list_to_atom(N),
case get_value(Name, List, undefined) of
- undefined -> {undefined, List};
- Val -> {Val, lists:keydelete(Name,1,List)}
+ undefined -> {P#param{in=false,prot=Type,acc=undefined}, List};
+ Val when is_list(Val), is_integer(hd(Val)) ->
+ %% Function String
+ {P#param{in=false,prot=Type,acc=Val}, lists:keydelete(Name,1,List)};
+ OptList when is_list(OptList) ->
+ Param = foldl(fun handle_param_opt/2,P,OptList),
+ {Param#param{in=false,prot=Type,acc=undefined},
+ lists:keydelete(Name,1,List)};
+ Val ->
+ {P#param{in=false,prot=Type,acc=Val}, lists:keydelete(Name,1,List)}
end.
-
+
load_members(FileName, Class, Defs, Tab, Type,Opts) ->
File = filename:join(["wx_xml",FileName ++ ".xml"]),
put({loaded, FileName}, true),
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 84d3990786..d4b6db8153 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -1079,6 +1079,13 @@ build_ret(Name,_,#type{base=string,single=true}) ->
w(" rt.add(~s);~n",[Name]);
build_ret(Name,_,#type{name="wxArrayString", single=array}) ->
w(" rt.add(~s);~n", [Name]);
+build_ret(Name,_,#type{name="wxString", single={list,Variable}}) ->
+ Obj = case Name of
+ "ev->" ++ _ -> "ev";
+ _ -> "This"
+ end,
+ w(" wxArrayString tmpArrayStr(~s->~s, ~s);~n", [Obj,Variable,Name]),
+ w(" rt.add(tmpArrayStr);~n", []);
build_ret(Name,In,T) ->
?error({nyi, Name,In, T}).
@@ -1309,7 +1316,8 @@ encode_events(Evs) ->
w(" } else {~n"),
w(" send_res = rt.send();~n"),
w(" if(cb->skip) event->Skip();~n"),
- w(" if(app->recurse_level < 1) {~n"),
+ #class{id=MouseId} = lists:keyfind("wxMouseEvent", #class.name, Evs),
+ w(" if(app->recurse_level < 1 && Etype->cID != ~p) {~n", [MouseId]),
w(" app->recurse_level++;~n"),
w(" app->dispatch_cmds();~n"),
w(" app->recurse_level--;~n"),
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
index 794de25002..e272c08d90 100644
--- a/lib/wx/api_gen/wx_gen_erl.erl
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -649,7 +649,7 @@ guard_test(#param{def=Def}) when Def =/= none -> skip;
guard_test(#param{where=c}) -> skip;
guard_test(#param{in=In}) when In == false -> skip;
guard_test(#param{name=N, type=#type{base=string}}) ->
- "is_list(" ++ erl_arg_name(N) ++")";
+ "?is_chardata(" ++ erl_arg_name(N) ++")";
guard_test(#param{name=N, type=#type{name="wxArtClient"}}) ->
"is_list(" ++ erl_arg_name(N) ++")";
guard_test(#param{name=N, type=#type{name="wxArrayString"}}) ->
@@ -801,8 +801,13 @@ doc_arg_type(_, _) -> skip.
doc_arg_type2(T) ->
doc_arg_type2(T, in).
-doc_arg_type2(T=#type{single=Single}, Out) when Single =:= array; Single =:= list ->
- "[" ++ doc_arg_type3(T, Out) ++ "]";
+doc_arg_type2(T=#type{single=Single}, Out) ->
+ case Single of
+ array -> "[" ++ doc_arg_type3(T, Out) ++ "]";
+ list -> "[" ++ doc_arg_type3(T, Out) ++ "]";
+ {list, _} -> "[" ++ doc_arg_type3(T, Out) ++ "]";
+ true -> doc_arg_type3(T, Out)
+ end;
doc_arg_type2(T, Out) ->
doc_arg_type3(T, Out).
@@ -1207,7 +1212,7 @@ gen_event_recs() ->
w("-type wx() :: #wx{}. %% wx event record ~n",[]),
w("%% Here comes the definitions of all event records.~n"
"%% they contain the event type and possible some extra information.~n~n",[]),
- Events = [build_event_rec(C) || {_,C=#class{event=Evs}} <- get(), Evs =/= false],
+ Events = [build_event_rec(C) || {_,C=#class{event=Evs}} <- lists:sort(get()), Evs =/= false],
EventSubTypes = [Type || {_Rec, Type} <- Events],
EventRecs = [Rec || {Rec, _Type} <- Events],
w("-type event() :: ~s.~n",
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 786e536f93..a0dfa61dd1 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -104,7 +104,8 @@
'Center','CenterOnParent','Centre','CentreOnParent','ClearBackground',
{'ClientToScreen',[{"x",both},{"y",both}]}, 'Close',
'ConvertDialogToPixels','ConvertPixelsToDialog','Destroy','DestroyChildren',
- 'Disable',%%'DoGetBestSize','DoUpdateWindowUI', 'DragAcceptFiles',
+ 'Disable',%%'DoGetBestSize','DoUpdateWindowUI',
+ {'DragAcceptFiles', [{test_if, "wxCHECK_VERSION(2,8,10)"}]},
'Enable',
'FindFocus','FindWindow','FindWindowById','FindWindowByName','FindWindowByLabel',
'Fit','FitInside','Freeze', 'GetAcceleratorTable', % 'GetAccessible',
@@ -154,7 +155,8 @@
{'SetTransparent', [{test_if, "wxCHECK_VERSION(2,8,12)"}]},
{'CanSetTransparent', [{test_if, "wxCHECK_VERSION(2,8,12)"}]},
{'IsDoubleBuffered', [{test_if, "wxCHECK_VERSION(3,0,0)"}]},
- {'SetDoubleBuffered', [{test_if, "wxCHECK_VERSION(3,0,0) && !defined(__WXMAC__)"}]}
+ {'SetDoubleBuffered', [{test_if, "wxCHECK_VERSION(3,0,0) && !defined(__WXMAC__)"}]},
+ {'GetContentScaleFactor', [{test_if, "wxCHECK_VERSION(2,9,5)"}]}
]}.
{class, wxTopLevelWindowGTK, wxWindow,
@@ -1490,8 +1492,6 @@
['ButtonDown','ButtonIsDown','ButtonUp','GetButtonChange','GetButtonState',
'GetJoystick','GetPosition','GetZPosition','IsButton','IsMove','IsZMove']}.
-%% {class, wxDropFilesEvent, wxEvent, [{event,[wxEVT_DROP_FILES]}],[]}. %FIXME
-
{enum, wxUpdateUIMode, "wxUPDATE_UI_"}.
{class, wxUpdateUIEvent, wxCommandEvent,
@@ -1988,3 +1988,10 @@
{class, wxDCOverlay, root, [],
['wxDCOverlay', '~wxDCOverlay', 'Clear']}.
+
+{class, wxDropFilesEvent, wxEvent,
+ [{acc, [{m_files, [{single, {list, 'm_noFiles'}}]}]},
+ {event,[wxEVT_DROP_FILES]}],
+ ['GetPosition', 'GetNumberOfFiles',
+ {'GetFiles', [{return, [{single, {list, 'm_noFiles'}}]}]}
+ ]}.
diff --git a/lib/wx/c_src/gen/gl_funcs.cpp b/lib/wx/c_src/gen/gl_funcs.cpp
index 4dd3ad44ef..bc8d5bbdca 100644
--- a/lib/wx/c_src/gen/gl_funcs.cpp
+++ b/lib/wx/c_src/gen/gl_funcs.cpp
@@ -815,7 +815,7 @@ case 5107: { // glCallList
}; break;
case 5108: { // glCallLists
int * listsLen = (int *) bp; bp += 4;
- GLuint * lists = (GLuint *) bp; bp += (8-((*listsLen*4+4)%8))%8;
+ GLuint * lists = (GLuint *) bp; bp += *listsLen*4 + (8-((*listsLen*4+4)%8))%8;
weglCallLists(*listsLen,GL_UNSIGNED_INT,lists);
}; break;
case 5109: { // glListBase
@@ -1866,7 +1866,7 @@ case 5271: { // glGenTextures
}; break;
case 5272: { // glDeleteTextures
int * texturesLen = (int *) bp; bp += 4;
- GLuint * textures = (GLuint *) bp; bp += (8-((*texturesLen*4+4)%8))%8;
+ GLuint * textures = (GLuint *) bp; bp += *texturesLen*4 + (8-((*texturesLen*4+4)%8))%8;
weglDeleteTextures(*texturesLen,textures);
}; break;
case 5273: { // glBindTexture
@@ -1876,14 +1876,14 @@ case 5273: { // glBindTexture
}; break;
case 5274: { // glPrioritizeTextures
int * texturesLen = (int *) bp; bp += 4;
- GLuint * textures = (GLuint *) bp; bp += (8-((*texturesLen*4+4)%8))%8;
+ GLuint * textures = (GLuint *) bp; bp += *texturesLen*4 + (8-((*texturesLen*4+4)%8))%8;
int * prioritiesLen = (int *) bp; bp += 4;
- GLclampf * priorities = (GLclampf *) bp; bp += (8-((*prioritiesLen*4+4)%8))%8;
+ GLclampf * priorities = (GLclampf *) bp; bp += *prioritiesLen*4 + (8-((*prioritiesLen*4+4)%8))%8;
weglPrioritizeTextures(*texturesLen,textures,priorities);
}; break;
case 5275: { // glAreTexturesResident
int * texturesLen = (int *) bp; bp += 4;
- GLuint * textures = (GLuint *) bp; bp += (8-((*texturesLen*4+4)%8))%8;
+ GLuint * textures = (GLuint *) bp; bp += *texturesLen*4 + (8-((*texturesLen*4+4)%8))%8;
GLboolean *residences;
residences = (GLboolean *) driver_alloc(sizeof(GLboolean) * *texturesLen);
GLboolean result = weglAreTexturesResident(*texturesLen,textures,residences);
@@ -2921,132 +2921,140 @@ case 5394: { // glBlendFuncSeparate
case 5395: { // glMultiDrawArrays
GLenum *mode = (GLenum *) bp; bp += 4;
int * firstLen = (int *) bp; bp += 4;
- GLint * first = (GLint *) bp; bp += (8-((*firstLen*4+0)%8))%8;
+ GLint * first = (GLint *) bp; bp += *firstLen*4 + (8-((*firstLen*4+0)%8))%8;
int * countLen = (int *) bp; bp += 4;
- GLsizei * count = (GLsizei *) bp; bp += (8-((*countLen*4+4)%8))%8;
- weglMultiDrawArrays(*mode,first,count,*firstLen);
+ GLsizei * count = (GLsizei *) bp; bp += *countLen*4 + (8-((*countLen*4+4)%8))%8;
+ weglMultiDrawArrays(*mode,first,count,*countLen);
}; break;
-case 5396: { // glPointParameterf
+case 5396: { // glMultiDrawArrays
+ GLenum *mode = (GLenum *) bp; bp += 4;
+ GLint *first = (GLint *) bins[0];
+ int * firstLen = (int *) bp; bp += 4; (void) firstLen;
+ GLsizei *count = (GLsizei *) bins[1];
+ int * countLen = (int *) bp; bp += 4; (void) countLen;
+ weglMultiDrawArrays(*mode,first,count,*countLen);
+}; break;
+case 5397: { // glPointParameterf
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat *param = (GLfloat *) bp; bp += 4;
weglPointParameterf(*pname,*param);
}; break;
-case 5397: { // glPointParameterfv
+case 5398: { // glPointParameterfv
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLfloat *params = (GLfloat *) bp; bp += *paramsLen*4+((*paramsLen)+0)%2*4;
weglPointParameterfv(*pname,params);
}; break;
-case 5398: { // glPointParameteri
+case 5399: { // glPointParameteri
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *param = (GLint *) bp; bp += 4;
weglPointParameteri(*pname,*param);
}; break;
-case 5399: { // glPointParameteriv
+case 5400: { // glPointParameteriv
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLint *params = (GLint *) bp; bp += *paramsLen*4+((*paramsLen)+0)%2*4;
weglPointParameteriv(*pname,params);
}; break;
-case 5400: { // glFogCoordfv
+case 5401: { // glFogCoordfv
GLfloat *coord = (GLfloat *) bp; bp += 4;
weglFogCoordfv(coord);
}; break;
-case 5401: { // glFogCoorddv
+case 5402: { // glFogCoorddv
GLdouble *coord = (GLdouble *) bp; bp += 8;
weglFogCoorddv(coord);
}; break;
-case 5402: { // glFogCoordPointer
+case 5403: { // glFogCoordPointer
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglFogCoordPointer(*type,*stride,pointer);
}; break;
-case 5403: { // glFogCoordPointer
+case 5404: { // glFogCoordPointer
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) bins[0];
weglFogCoordPointer(*type,*stride,pointer);
}; break;
-case 5404: { // glSecondaryColor3bv
+case 5405: { // glSecondaryColor3bv
GLbyte *v = (GLbyte *) bp; bp += 1;
weglSecondaryColor3bv(v);
}; break;
-case 5405: { // glSecondaryColor3dv
+case 5406: { // glSecondaryColor3dv
GLdouble *v = (GLdouble *) bp; bp += 8;
weglSecondaryColor3dv(v);
}; break;
-case 5406: { // glSecondaryColor3fv
+case 5407: { // glSecondaryColor3fv
GLfloat *v = (GLfloat *) bp; bp += 4;
weglSecondaryColor3fv(v);
}; break;
-case 5407: { // glSecondaryColor3iv
+case 5408: { // glSecondaryColor3iv
GLint *v = (GLint *) bp; bp += 4;
weglSecondaryColor3iv(v);
}; break;
-case 5408: { // glSecondaryColor3sv
+case 5409: { // glSecondaryColor3sv
GLshort *v = (GLshort *) bp; bp += 2;
weglSecondaryColor3sv(v);
}; break;
-case 5409: { // glSecondaryColor3ubv
+case 5410: { // glSecondaryColor3ubv
GLubyte *v = (GLubyte *) bp; bp += 1;
weglSecondaryColor3ubv(v);
}; break;
-case 5410: { // glSecondaryColor3uiv
+case 5411: { // glSecondaryColor3uiv
GLuint *v = (GLuint *) bp; bp += 4;
weglSecondaryColor3uiv(v);
}; break;
-case 5411: { // glSecondaryColor3usv
+case 5412: { // glSecondaryColor3usv
GLushort *v = (GLushort *) bp; bp += 2;
weglSecondaryColor3usv(v);
}; break;
-case 5412: { // glSecondaryColorPointer
+case 5413: { // glSecondaryColorPointer
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglSecondaryColorPointer(*size,*type,*stride,pointer);
}; break;
-case 5413: { // glSecondaryColorPointer
+case 5414: { // glSecondaryColorPointer
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) bins[0];
weglSecondaryColorPointer(*size,*type,*stride,pointer);
}; break;
-case 5414: { // glWindowPos2dv
+case 5415: { // glWindowPos2dv
GLdouble *v = (GLdouble *) bp; bp += 8;
weglWindowPos2dv(v);
}; break;
-case 5415: { // glWindowPos2fv
+case 5416: { // glWindowPos2fv
GLfloat *v = (GLfloat *) bp; bp += 4;
weglWindowPos2fv(v);
}; break;
-case 5416: { // glWindowPos2iv
+case 5417: { // glWindowPos2iv
GLint *v = (GLint *) bp; bp += 4;
weglWindowPos2iv(v);
}; break;
-case 5417: { // glWindowPos2sv
+case 5418: { // glWindowPos2sv
GLshort *v = (GLshort *) bp; bp += 2;
weglWindowPos2sv(v);
}; break;
-case 5418: { // glWindowPos3dv
+case 5419: { // glWindowPos3dv
GLdouble *v = (GLdouble *) bp; bp += 8;
weglWindowPos3dv(v);
}; break;
-case 5419: { // glWindowPos3fv
+case 5420: { // glWindowPos3fv
GLfloat *v = (GLfloat *) bp; bp += 4;
weglWindowPos3fv(v);
}; break;
-case 5420: { // glWindowPos3iv
+case 5421: { // glWindowPos3iv
GLint *v = (GLint *) bp; bp += 4;
weglWindowPos3iv(v);
}; break;
-case 5421: { // glWindowPos3sv
+case 5422: { // glWindowPos3sv
GLshort *v = (GLshort *) bp; bp += 2;
weglWindowPos3sv(v);
}; break;
-case 5422: { // glGenQueries
+case 5423: { // glGenQueries
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *ids;
ids = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -3062,12 +3070,12 @@ case 5422: { // glGenQueries
driver_free(rt);
driver_free(ids);
}; break;
-case 5423: { // glDeleteQueries
+case 5424: { // glDeleteQueries
int * idsLen = (int *) bp; bp += 4;
- GLuint * ids = (GLuint *) bp; bp += (8-((*idsLen*4+4)%8))%8;
+ GLuint * ids = (GLuint *) bp; bp += *idsLen*4 + (8-((*idsLen*4+4)%8))%8;
weglDeleteQueries(*idsLen,ids);
}; break;
-case 5424: { // glIsQuery
+case 5425: { // glIsQuery
GLuint *id = (GLuint *) bp; bp += 4;
GLboolean result = weglIsQuery(*id);
int AP = 0; ErlDrvTermData rt[6];
@@ -3076,16 +3084,16 @@ case 5424: { // glIsQuery
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5425: { // glBeginQuery
+case 5426: { // glBeginQuery
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglBeginQuery(*target,*id);
}; break;
-case 5426: { // glEndQuery
+case 5427: { // glEndQuery
GLenum *target = (GLenum *) bp; bp += 4;
weglEndQuery(*target);
}; break;
-case 5427: { // glGetQueryiv
+case 5428: { // glGetQueryiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3096,7 +3104,7 @@ case 5427: { // glGetQueryiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5428: { // glGetQueryObjectiv
+case 5429: { // glGetQueryObjectiv
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3107,7 +3115,7 @@ case 5428: { // glGetQueryObjectiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5429: { // glGetQueryObjectuiv
+case 5430: { // glGetQueryObjectuiv
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[1] = {0};
@@ -3118,17 +3126,17 @@ case 5429: { // glGetQueryObjectuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5430: { // glBindBuffer
+case 5431: { // glBindBuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
weglBindBuffer(*target,*buffer);
}; break;
-case 5431: { // glDeleteBuffers
+case 5432: { // glDeleteBuffers
int * buffersLen = (int *) bp; bp += 4;
- GLuint * buffers = (GLuint *) bp; bp += (8-((*buffersLen*4+4)%8))%8;
+ GLuint * buffers = (GLuint *) bp; bp += *buffersLen*4 + (8-((*buffersLen*4+4)%8))%8;
weglDeleteBuffers(*buffersLen,buffers);
}; break;
-case 5432: { // glGenBuffers
+case 5433: { // glGenBuffers
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *buffers;
buffers = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -3144,7 +3152,7 @@ case 5432: { // glGenBuffers
driver_free(rt);
driver_free(buffers);
}; break;
-case 5433: { // glIsBuffer
+case 5434: { // glIsBuffer
GLuint *buffer = (GLuint *) bp; bp += 4;
GLboolean result = weglIsBuffer(*buffer);
int AP = 0; ErlDrvTermData rt[6];
@@ -3153,7 +3161,7 @@ case 5433: { // glIsBuffer
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5434: { // glBufferData
+case 5435: { // glBufferData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3161,7 +3169,7 @@ case 5434: { // glBufferData
GLenum *usage = (GLenum *) bp; bp += 4;
weglBufferData(*target,size,data,*usage);
}; break;
-case 5435: { // glBufferData
+case 5436: { // glBufferData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3169,7 +3177,7 @@ case 5435: { // glBufferData
GLenum *usage = (GLenum *) bp; bp += 4;
weglBufferData(*target,size,data,*usage);
}; break;
-case 5436: { // glBufferSubData
+case 5437: { // glBufferSubData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3177,7 +3185,7 @@ case 5436: { // glBufferSubData
GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglBufferSubData(*target,offset,size,data);
}; break;
-case 5437: { // glBufferSubData
+case 5438: { // glBufferSubData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3185,7 +3193,7 @@ case 5437: { // glBufferSubData
GLvoid *data = (GLvoid *) bins[0];
weglBufferSubData(*target,offset,size,data);
}; break;
-case 5438: { // glGetBufferSubData
+case 5439: { // glGetBufferSubData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3198,7 +3206,7 @@ case 5438: { // glGetBufferSubData
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5439: { // glGetBufferParameteriv
+case 5440: { // glGetBufferParameteriv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3209,52 +3217,52 @@ case 5439: { // glGetBufferParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5440: { // glBlendEquationSeparate
+case 5441: { // glBlendEquationSeparate
GLenum *modeRGB = (GLenum *) bp; bp += 4;
GLenum *modeAlpha = (GLenum *) bp; bp += 4;
weglBlendEquationSeparate(*modeRGB,*modeAlpha);
}; break;
-case 5441: { // glDrawBuffers
+case 5442: { // glDrawBuffers
int * bufsLen = (int *) bp; bp += 4;
- GLenum * bufs = (GLenum *) bp; bp += (8-((*bufsLen*4+4)%8))%8;
+ GLenum * bufs = (GLenum *) bp; bp += *bufsLen*4 + (8-((*bufsLen*4+4)%8))%8;
weglDrawBuffers(*bufsLen,bufs);
}; break;
-case 5442: { // glStencilOpSeparate
+case 5443: { // glStencilOpSeparate
GLenum *face = (GLenum *) bp; bp += 4;
GLenum *sfail = (GLenum *) bp; bp += 4;
GLenum *dpfail = (GLenum *) bp; bp += 4;
GLenum *dppass = (GLenum *) bp; bp += 4;
weglStencilOpSeparate(*face,*sfail,*dpfail,*dppass);
}; break;
-case 5443: { // glStencilFuncSeparate
+case 5444: { // glStencilFuncSeparate
GLenum *face = (GLenum *) bp; bp += 4;
GLenum *func = (GLenum *) bp; bp += 4;
GLint *ref = (GLint *) bp; bp += 4;
GLuint *mask = (GLuint *) bp; bp += 4;
weglStencilFuncSeparate(*face,*func,*ref,*mask);
}; break;
-case 5444: { // glStencilMaskSeparate
+case 5445: { // glStencilMaskSeparate
GLenum *face = (GLenum *) bp; bp += 4;
GLuint *mask = (GLuint *) bp; bp += 4;
weglStencilMaskSeparate(*face,*mask);
}; break;
-case 5445: { // glAttachShader
+case 5446: { // glAttachShader
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *shader = (GLuint *) bp; bp += 4;
weglAttachShader(*program,*shader);
}; break;
-case 5446: { // glBindAttribLocation
+case 5447: { // glBindAttribLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
weglBindAttribLocation(*program,*index,name);
}; break;
-case 5447: { // glCompileShader
+case 5448: { // glCompileShader
GLuint *shader = (GLuint *) bp; bp += 4;
weglCompileShader(*shader);
}; break;
-case 5448: { // glCreateProgram
+case 5449: { // glCreateProgram
GLuint result = weglCreateProgram();
int AP = 0; ErlDrvTermData rt[6];
rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
@@ -3262,7 +3270,7 @@ case 5448: { // glCreateProgram
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5449: { // glCreateShader
+case 5450: { // glCreateShader
GLenum *type = (GLenum *) bp; bp += 4;
GLuint result = weglCreateShader(*type);
int AP = 0; ErlDrvTermData rt[6];
@@ -3271,28 +3279,28 @@ case 5449: { // glCreateShader
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5450: { // glDeleteProgram
+case 5451: { // glDeleteProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglDeleteProgram(*program);
}; break;
-case 5451: { // glDeleteShader
+case 5452: { // glDeleteShader
GLuint *shader = (GLuint *) bp; bp += 4;
weglDeleteShader(*shader);
}; break;
-case 5452: { // glDetachShader
+case 5453: { // glDetachShader
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *shader = (GLuint *) bp; bp += 4;
weglDetachShader(*program,*shader);
}; break;
-case 5453: { // glDisableVertexAttribArray
+case 5454: { // glDisableVertexAttribArray
GLuint *index = (GLuint *) bp; bp += 4;
weglDisableVertexAttribArray(*index);
}; break;
-case 5454: { // glEnableVertexAttribArray
+case 5455: { // glEnableVertexAttribArray
GLuint *index = (GLuint *) bp; bp += 4;
weglEnableVertexAttribArray(*index);
}; break;
-case 5455: { // glGetActiveAttrib
+case 5456: { // glGetActiveAttrib
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -3312,7 +3320,7 @@ case 5455: { // glGetActiveAttrib
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5456: { // glGetActiveUniform
+case 5457: { // glGetActiveUniform
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -3332,7 +3340,7 @@ case 5456: { // glGetActiveUniform
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5457: { // glGetAttachedShaders
+case 5458: { // glGetAttachedShaders
GLuint *program = (GLuint *) bp; bp += 4;
GLsizei *maxCount = (GLsizei *) bp; bp += 4;
GLsizei count[1] = {0};
@@ -3350,7 +3358,7 @@ case 5457: { // glGetAttachedShaders
driver_free(rt);
driver_free(obj);
}; break;
-case 5458: { // glGetAttribLocation
+case 5459: { // glGetAttribLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -3361,7 +3369,7 @@ case 5458: { // glGetAttribLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5459: { // glGetProgramiv
+case 5460: { // glGetProgramiv
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3372,7 +3380,7 @@ case 5459: { // glGetProgramiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5460: { // glGetProgramInfoLog
+case 5461: { // glGetProgramInfoLog
GLuint *program = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -3386,7 +3394,7 @@ case 5460: { // glGetProgramInfoLog
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5461: { // glGetShaderiv
+case 5462: { // glGetShaderiv
GLuint *shader = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3397,7 +3405,7 @@ case 5461: { // glGetShaderiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5462: { // glGetShaderInfoLog
+case 5463: { // glGetShaderInfoLog
GLuint *shader = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -3411,7 +3419,7 @@ case 5462: { // glGetShaderInfoLog
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5463: { // glGetShaderSource
+case 5464: { // glGetShaderSource
GLuint *shader = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -3425,7 +3433,7 @@ case 5463: { // glGetShaderSource
driver_send_term(port,caller,rt,AP);
driver_free(source);
}; break;
-case 5464: { // glGetUniformLocation
+case 5465: { // glGetUniformLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -3436,7 +3444,7 @@ case 5464: { // glGetUniformLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5465: { // glGetUniformfv
+case 5466: { // glGetUniformfv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat params[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -3465,7 +3473,7 @@ case 5465: { // glGetUniformfv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5466: { // glGetUniformiv
+case 5467: { // glGetUniformiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -3493,7 +3501,7 @@ case 5466: { // glGetUniformiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5467: { // glGetVertexAttribdv
+case 5468: { // glGetVertexAttribdv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -3509,7 +3517,7 @@ case 5467: { // glGetVertexAttribdv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5468: { // glGetVertexAttribfv
+case 5469: { // glGetVertexAttribfv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -3526,7 +3534,7 @@ case 5468: { // glGetVertexAttribfv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5469: { // glGetVertexAttribiv
+case 5470: { // glGetVertexAttribiv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -3542,7 +3550,7 @@ case 5469: { // glGetVertexAttribiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5470: { // glIsProgram
+case 5471: { // glIsProgram
GLuint *program = (GLuint *) bp; bp += 4;
GLboolean result = weglIsProgram(*program);
int AP = 0; ErlDrvTermData rt[6];
@@ -3551,7 +3559,7 @@ case 5470: { // glIsProgram
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5471: { // glIsShader
+case 5472: { // glIsShader
GLuint *shader = (GLuint *) bp; bp += 4;
GLboolean result = weglIsShader(*shader);
int AP = 0; ErlDrvTermData rt[6];
@@ -3560,11 +3568,11 @@ case 5471: { // glIsShader
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5472: { // glLinkProgram
+case 5473: { // glLinkProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglLinkProgram(*program);
}; break;
-case 5473: { // glShaderSource
+case 5474: { // glShaderSource
GLuint *shader = (GLuint *) bp; bp += 4;
int * stringLen = (int *) bp; bp += 4;
int * stringTotSize = (int *) bp; bp += 4;
@@ -3576,29 +3584,29 @@ case 5473: { // glShaderSource
weglShaderSource(*shader,*stringLen,(const GLchar **) string,NULL);
driver_free(string);
}; break;
-case 5474: { // glUseProgram
+case 5475: { // glUseProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglUseProgram(*program);
}; break;
-case 5475: { // glUniform1f
+case 5476: { // glUniform1f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
weglUniform1f(*location,*v0);
}; break;
-case 5476: { // glUniform2f
+case 5477: { // glUniform2f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
weglUniform2f(*location,*v0,*v1);
}; break;
-case 5477: { // glUniform3f
+case 5478: { // glUniform3f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
GLfloat *v2 = (GLfloat *) bp; bp += 4;
weglUniform3f(*location,*v0,*v1,*v2);
}; break;
-case 5478: { // glUniform4f
+case 5479: { // glUniform4f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
@@ -3606,25 +3614,25 @@ case 5478: { // glUniform4f
GLfloat *v3 = (GLfloat *) bp; bp += 4;
weglUniform4f(*location,*v0,*v1,*v2,*v3);
}; break;
-case 5479: { // glUniform1i
+case 5480: { // glUniform1i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
weglUniform1i(*location,*v0);
}; break;
-case 5480: { // glUniform2i
+case 5481: { // glUniform2i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
weglUniform2i(*location,*v0,*v1);
}; break;
-case 5481: { // glUniform3i
+case 5482: { // glUniform3i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
GLint *v2 = (GLint *) bp; bp += 4;
weglUniform3i(*location,*v0,*v1,*v2);
}; break;
-case 5482: { // glUniform4i
+case 5483: { // glUniform4i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
@@ -3632,55 +3640,55 @@ case 5482: { // glUniform4i
GLint *v3 = (GLint *) bp; bp += 4;
weglUniform4i(*location,*v0,*v1,*v2,*v3);
}; break;
-case 5483: { // glUniform1fv
+case 5484: { // glUniform1fv
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLfloat * value = (GLfloat *) bp; bp += (8-((*valueLen*4+0)%8))%8;
+ GLfloat * value = (GLfloat *) bp; bp += *valueLen*4 + (8-((*valueLen*4+0)%8))%8;
weglUniform1fv(*location,*valueLen,value);
}; break;
-case 5484: { // glUniform2fv
+case 5485: { // glUniform2fv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*8;
weglUniform2fv(*location,*valueLen,value);
}; break;
-case 5485: { // glUniform3fv
+case 5486: { // glUniform3fv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*12;
weglUniform3fv(*location,*valueLen,value);
}; break;
-case 5486: { // glUniform4fv
+case 5487: { // glUniform4fv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglUniform4fv(*location,*valueLen,value);
}; break;
-case 5487: { // glUniform1iv
+case 5488: { // glUniform1iv
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLint * value = (GLint *) bp; bp += (8-((*valueLen*4+0)%8))%8;
+ GLint * value = (GLint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+0)%8))%8;
weglUniform1iv(*location,*valueLen,value);
}; break;
-case 5488: { // glUniform2iv
+case 5489: { // glUniform2iv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*8;
weglUniform2iv(*location,*valueLen,value);
}; break;
-case 5489: { // glUniform3iv
+case 5490: { // glUniform3iv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*12;
weglUniform3iv(*location,*valueLen,value);
}; break;
-case 5490: { // glUniform4iv
+case 5491: { // glUniform4iv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*16;
weglUniform4iv(*location,*valueLen,value);
}; break;
-case 5491: { // glUniformMatrix2fv
+case 5492: { // glUniformMatrix2fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3688,7 +3696,7 @@ case 5491: { // glUniformMatrix2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglUniformMatrix2fv(*location,*valueLen,*transpose,value);
}; break;
-case 5492: { // glUniformMatrix3fv
+case 5493: { // glUniformMatrix3fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3696,7 +3704,7 @@ case 5492: { // glUniformMatrix3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*36;
weglUniformMatrix3fv(*location,*valueLen,*transpose,value);
}; break;
-case 5493: { // glUniformMatrix4fv
+case 5494: { // glUniformMatrix4fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3704,130 +3712,130 @@ case 5493: { // glUniformMatrix4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*64;
weglUniformMatrix4fv(*location,*valueLen,*transpose,value);
}; break;
-case 5494: { // glValidateProgram
+case 5495: { // glValidateProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglValidateProgram(*program);
}; break;
-case 5495: { // glVertexAttrib1dv
+case 5496: { // glVertexAttrib1dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttrib1dv(*index,v);
}; break;
-case 5496: { // glVertexAttrib1fv
+case 5497: { // glVertexAttrib1fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *v = (GLfloat *) bp; bp += 4;
weglVertexAttrib1fv(*index,v);
}; break;
-case 5497: { // glVertexAttrib1sv
+case 5498: { // glVertexAttrib1sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort *v = (GLshort *) bp; bp += 2;
weglVertexAttrib1sv(*index,v);
}; break;
-case 5498: { // glVertexAttrib2dv
+case 5499: { // glVertexAttrib2dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttrib2dv(*index,v);
}; break;
-case 5499: { // glVertexAttrib2fv
+case 5500: { // glVertexAttrib2fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *v = (GLfloat *) bp; bp += 4;
weglVertexAttrib2fv(*index,v);
}; break;
-case 5500: { // glVertexAttrib2sv
+case 5501: { // glVertexAttrib2sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort *v = (GLshort *) bp; bp += 2;
weglVertexAttrib2sv(*index,v);
}; break;
-case 5501: { // glVertexAttrib3dv
+case 5502: { // glVertexAttrib3dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttrib3dv(*index,v);
}; break;
-case 5502: { // glVertexAttrib3fv
+case 5503: { // glVertexAttrib3fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *v = (GLfloat *) bp; bp += 4;
weglVertexAttrib3fv(*index,v);
}; break;
-case 5503: { // glVertexAttrib3sv
+case 5504: { // glVertexAttrib3sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort *v = (GLshort *) bp; bp += 2;
weglVertexAttrib3sv(*index,v);
}; break;
-case 5504: { // glVertexAttrib4Nbv
+case 5505: { // glVertexAttrib4Nbv
GLuint *index = (GLuint *) bp; bp += 4;
GLbyte * v = (GLbyte *) bp; bp += 4;
weglVertexAttrib4Nbv(*index,v);
}; break;
-case 5505: { // glVertexAttrib4Niv
+case 5506: { // glVertexAttrib4Niv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglVertexAttrib4Niv(*index,v);
}; break;
-case 5506: { // glVertexAttrib4Nsv
+case 5507: { // glVertexAttrib4Nsv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort * v = (GLshort *) bp; bp += 8;
weglVertexAttrib4Nsv(*index,v);
}; break;
-case 5507: { // glVertexAttrib4Nubv
+case 5508: { // glVertexAttrib4Nubv
GLuint *index = (GLuint *) bp; bp += 4;
GLubyte * v = (GLubyte *) bp; bp += 4;
weglVertexAttrib4Nubv(*index,v);
}; break;
-case 5508: { // glVertexAttrib4Nuiv
+case 5509: { // glVertexAttrib4Nuiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint * v = (GLuint *) bp; bp += 16;
weglVertexAttrib4Nuiv(*index,v);
}; break;
-case 5509: { // glVertexAttrib4Nusv
+case 5510: { // glVertexAttrib4Nusv
GLuint *index = (GLuint *) bp; bp += 4;
GLushort * v = (GLushort *) bp; bp += 8;
weglVertexAttrib4Nusv(*index,v);
}; break;
-case 5510: { // glVertexAttrib4bv
+case 5511: { // glVertexAttrib4bv
GLuint *index = (GLuint *) bp; bp += 4;
GLbyte * v = (GLbyte *) bp; bp += 4;
weglVertexAttrib4bv(*index,v);
}; break;
-case 5511: { // glVertexAttrib4dv
+case 5512: { // glVertexAttrib4dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble * v = (GLdouble *) bp; bp += 32;
weglVertexAttrib4dv(*index,v);
}; break;
-case 5512: { // glVertexAttrib4fv
+case 5513: { // glVertexAttrib4fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * v = (GLfloat *) bp; bp += 16;
weglVertexAttrib4fv(*index,v);
}; break;
-case 5513: { // glVertexAttrib4iv
+case 5514: { // glVertexAttrib4iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglVertexAttrib4iv(*index,v);
}; break;
-case 5514: { // glVertexAttrib4sv
+case 5515: { // glVertexAttrib4sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort * v = (GLshort *) bp; bp += 8;
weglVertexAttrib4sv(*index,v);
}; break;
-case 5515: { // glVertexAttrib4ubv
+case 5516: { // glVertexAttrib4ubv
GLuint *index = (GLuint *) bp; bp += 4;
GLubyte * v = (GLubyte *) bp; bp += 4;
weglVertexAttrib4ubv(*index,v);
}; break;
-case 5516: { // glVertexAttrib4uiv
+case 5517: { // glVertexAttrib4uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint * v = (GLuint *) bp; bp += 16;
weglVertexAttrib4uiv(*index,v);
}; break;
-case 5517: { // glVertexAttrib4usv
+case 5518: { // glVertexAttrib4usv
GLuint *index = (GLuint *) bp; bp += 4;
GLushort * v = (GLushort *) bp; bp += 8;
weglVertexAttrib4usv(*index,v);
}; break;
-case 5518: { // glVertexAttribPointer
+case 5519: { // glVertexAttribPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -3837,7 +3845,7 @@ case 5518: { // glVertexAttribPointer
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglVertexAttribPointer(*index,*size,*type,*normalized,*stride,pointer);
}; break;
-case 5519: { // glVertexAttribPointer
+case 5520: { // glVertexAttribPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -3847,7 +3855,7 @@ case 5519: { // glVertexAttribPointer
GLvoid *pointer = (GLvoid *) bins[0];
weglVertexAttribPointer(*index,*size,*type,*normalized,*stride,pointer);
}; break;
-case 5520: { // glUniformMatrix2x3fv
+case 5521: { // glUniformMatrix2x3fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3855,7 +3863,7 @@ case 5520: { // glUniformMatrix2x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglUniformMatrix2x3fv(*location,*valueLen,*transpose,value);
}; break;
-case 5521: { // glUniformMatrix3x2fv
+case 5522: { // glUniformMatrix3x2fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3863,7 +3871,7 @@ case 5521: { // glUniformMatrix3x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglUniformMatrix3x2fv(*location,*valueLen,*transpose,value);
}; break;
-case 5522: { // glUniformMatrix2x4fv
+case 5523: { // glUniformMatrix2x4fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3871,7 +3879,7 @@ case 5522: { // glUniformMatrix2x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglUniformMatrix2x4fv(*location,*valueLen,*transpose,value);
}; break;
-case 5523: { // glUniformMatrix4x2fv
+case 5524: { // glUniformMatrix4x2fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3879,7 +3887,7 @@ case 5523: { // glUniformMatrix4x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglUniformMatrix4x2fv(*location,*valueLen,*transpose,value);
}; break;
-case 5524: { // glUniformMatrix3x4fv
+case 5525: { // glUniformMatrix3x4fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3887,7 +3895,7 @@ case 5524: { // glUniformMatrix3x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglUniformMatrix3x4fv(*location,*valueLen,*transpose,value);
}; break;
-case 5525: { // glUniformMatrix4x3fv
+case 5526: { // glUniformMatrix4x3fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3895,7 +3903,7 @@ case 5525: { // glUniformMatrix4x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglUniformMatrix4x3fv(*location,*valueLen,*transpose,value);
}; break;
-case 5526: { // glColorMaski
+case 5527: { // glColorMaski
GLuint *index = (GLuint *) bp; bp += 4;
GLboolean *r = (GLboolean *) bp; bp += 1;
GLboolean *g = (GLboolean *) bp; bp += 1;
@@ -3903,7 +3911,7 @@ case 5526: { // glColorMaski
GLboolean *a = (GLboolean *) bp; bp += 1;
weglColorMaski(*index,*r,*g,*b,*a);
}; break;
-case 5527: { // glGetBooleani_v
+case 5528: { // glGetBooleani_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLboolean data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -3931,7 +3939,7 @@ case 5527: { // glGetBooleani_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5528: { // glGetIntegeri_v
+case 5529: { // glGetIntegeri_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLint data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -3959,17 +3967,17 @@ case 5528: { // glGetIntegeri_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5529: { // glEnablei
+case 5530: { // glEnablei
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
weglEnablei(*target,*index);
}; break;
-case 5530: { // glDisablei
+case 5531: { // glDisablei
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
weglDisablei(*target,*index);
}; break;
-case 5531: { // glIsEnabledi
+case 5532: { // glIsEnabledi
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLboolean result = weglIsEnabledi(*target,*index);
@@ -3979,14 +3987,14 @@ case 5531: { // glIsEnabledi
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5532: { // glBeginTransformFeedback
+case 5533: { // glBeginTransformFeedback
GLenum *primitiveMode = (GLenum *) bp; bp += 4;
weglBeginTransformFeedback(*primitiveMode);
}; break;
-case 5533: { // glEndTransformFeedback
+case 5534: { // glEndTransformFeedback
weglEndTransformFeedback();
}; break;
-case 5534: { // glBindBufferRange
+case 5535: { // glBindBufferRange
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
@@ -3995,13 +4003,13 @@ case 5534: { // glBindBufferRange
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
weglBindBufferRange(*target,*index,*buffer,offset,size);
}; break;
-case 5535: { // glBindBufferBase
+case 5536: { // glBindBufferBase
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
weglBindBufferBase(*target,*index,*buffer);
}; break;
-case 5536: { // glTransformFeedbackVaryings
+case 5537: { // glTransformFeedbackVaryings
GLuint *program = (GLuint *) bp; bp += 4;
int * varyingsLen = (int *) bp; bp += 4;
int * varyingsTotSize = (int *) bp; bp += 4;
@@ -4014,7 +4022,7 @@ case 5536: { // glTransformFeedbackVaryings
weglTransformFeedbackVaryings(*program,*varyingsLen,(const GLchar **) varyings,*bufferMode);
driver_free(varyings);
}; break;
-case 5537: { // glGetTransformFeedbackVarying
+case 5538: { // glGetTransformFeedbackVarying
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -4034,20 +4042,20 @@ case 5537: { // glGetTransformFeedbackVarying
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5538: { // glClampColor
+case 5539: { // glClampColor
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *clamp = (GLenum *) bp; bp += 4;
weglClampColor(*target,*clamp);
}; break;
-case 5539: { // glBeginConditionalRender
+case 5540: { // glBeginConditionalRender
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *mode = (GLenum *) bp; bp += 4;
weglBeginConditionalRender(*id,*mode);
}; break;
-case 5540: { // glEndConditionalRender
+case 5541: { // glEndConditionalRender
weglEndConditionalRender();
}; break;
-case 5541: { // glVertexAttribIPointer
+case 5542: { // glVertexAttribIPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4055,7 +4063,7 @@ case 5541: { // glVertexAttribIPointer
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglVertexAttribIPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5542: { // glVertexAttribIPointer
+case 5543: { // glVertexAttribIPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4063,7 +4071,7 @@ case 5542: { // glVertexAttribIPointer
GLvoid *pointer = (GLvoid *) bins[0];
weglVertexAttribIPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5543: { // glGetVertexAttribIiv
+case 5544: { // glGetVertexAttribIiv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -4079,7 +4087,7 @@ case 5543: { // glGetVertexAttribIiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5544: { // glGetVertexAttribIuiv
+case 5545: { // glGetVertexAttribIuiv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[4] = {0,0,0,0};
@@ -4095,67 +4103,67 @@ case 5544: { // glGetVertexAttribIuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5545: { // glVertexAttribI1iv
+case 5546: { // glVertexAttribI1iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint *v = (GLint *) bp; bp += 4;
weglVertexAttribI1iv(*index,v);
}; break;
-case 5546: { // glVertexAttribI2iv
+case 5547: { // glVertexAttribI2iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint *v = (GLint *) bp; bp += 4;
weglVertexAttribI2iv(*index,v);
}; break;
-case 5547: { // glVertexAttribI3iv
+case 5548: { // glVertexAttribI3iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint *v = (GLint *) bp; bp += 4;
weglVertexAttribI3iv(*index,v);
}; break;
-case 5548: { // glVertexAttribI4iv
+case 5549: { // glVertexAttribI4iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglVertexAttribI4iv(*index,v);
}; break;
-case 5549: { // glVertexAttribI1uiv
+case 5550: { // glVertexAttribI1uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *v = (GLuint *) bp; bp += 4;
weglVertexAttribI1uiv(*index,v);
}; break;
-case 5550: { // glVertexAttribI2uiv
+case 5551: { // glVertexAttribI2uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *v = (GLuint *) bp; bp += 4;
weglVertexAttribI2uiv(*index,v);
}; break;
-case 5551: { // glVertexAttribI3uiv
+case 5552: { // glVertexAttribI3uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *v = (GLuint *) bp; bp += 4;
weglVertexAttribI3uiv(*index,v);
}; break;
-case 5552: { // glVertexAttribI4uiv
+case 5553: { // glVertexAttribI4uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint * v = (GLuint *) bp; bp += 16;
weglVertexAttribI4uiv(*index,v);
}; break;
-case 5553: { // glVertexAttribI4bv
+case 5554: { // glVertexAttribI4bv
GLuint *index = (GLuint *) bp; bp += 4;
GLbyte * v = (GLbyte *) bp; bp += 4;
weglVertexAttribI4bv(*index,v);
}; break;
-case 5554: { // glVertexAttribI4sv
+case 5555: { // glVertexAttribI4sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort * v = (GLshort *) bp; bp += 8;
weglVertexAttribI4sv(*index,v);
}; break;
-case 5555: { // glVertexAttribI4ubv
+case 5556: { // glVertexAttribI4ubv
GLuint *index = (GLuint *) bp; bp += 4;
GLubyte * v = (GLubyte *) bp; bp += 4;
weglVertexAttribI4ubv(*index,v);
}; break;
-case 5556: { // glVertexAttribI4usv
+case 5557: { // glVertexAttribI4usv
GLuint *index = (GLuint *) bp; bp += 4;
GLushort * v = (GLushort *) bp; bp += 8;
weglVertexAttribI4usv(*index,v);
}; break;
-case 5557: { // glGetUniformuiv
+case 5558: { // glGetUniformuiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4183,14 +4191,14 @@ case 5557: { // glGetUniformuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5558: { // glBindFragDataLocation
+case 5559: { // glBindFragDataLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *color = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
weglBindFragDataLocation(*program,*color,name);
}; break;
-case 5559: { // glGetFragDataLocation
+case 5560: { // glGetFragDataLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -4201,25 +4209,25 @@ case 5559: { // glGetFragDataLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5560: { // glUniform1ui
+case 5561: { // glUniform1ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
weglUniform1ui(*location,*v0);
}; break;
-case 5561: { // glUniform2ui
+case 5562: { // glUniform2ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
weglUniform2ui(*location,*v0,*v1);
}; break;
-case 5562: { // glUniform3ui
+case 5563: { // glUniform3ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
GLuint *v2 = (GLuint *) bp; bp += 4;
weglUniform3ui(*location,*v0,*v1,*v2);
}; break;
-case 5563: { // glUniform4ui
+case 5564: { // glUniform4ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
@@ -4227,45 +4235,45 @@ case 5563: { // glUniform4ui
GLuint *v3 = (GLuint *) bp; bp += 4;
weglUniform4ui(*location,*v0,*v1,*v2,*v3);
}; break;
-case 5564: { // glUniform1uiv
+case 5565: { // glUniform1uiv
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLuint * value = (GLuint *) bp; bp += (8-((*valueLen*4+0)%8))%8;
+ GLuint * value = (GLuint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+0)%8))%8;
weglUniform1uiv(*location,*valueLen,value);
}; break;
-case 5565: { // glUniform2uiv
+case 5566: { // glUniform2uiv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*8;
weglUniform2uiv(*location,*valueLen,value);
}; break;
-case 5566: { // glUniform3uiv
+case 5567: { // glUniform3uiv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*12;
weglUniform3uiv(*location,*valueLen,value);
}; break;
-case 5567: { // glUniform4uiv
+case 5568: { // glUniform4uiv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*16;
weglUniform4uiv(*location,*valueLen,value);
}; break;
-case 5568: { // glTexParameterIiv
+case 5569: { // glTexParameterIiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLint *params = (GLint *) bp; bp += *paramsLen*4+((*paramsLen)+1)%2*4;
weglTexParameterIiv(*target,*pname,params);
}; break;
-case 5569: { // glTexParameterIuiv
+case 5570: { // glTexParameterIuiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLuint *params = (GLuint *) bp; bp += *paramsLen*4+((*paramsLen)+1)%2*4;
weglTexParameterIuiv(*target,*pname,params);
}; break;
-case 5570: { // glGetTexParameterIiv
+case 5571: { // glGetTexParameterIiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -4281,7 +4289,7 @@ case 5570: { // glGetTexParameterIiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5571: { // glGetTexParameterIuiv
+case 5572: { // glGetTexParameterIuiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[4] = {0,0,0,0};
@@ -4297,35 +4305,35 @@ case 5571: { // glGetTexParameterIuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5572: { // glClearBufferiv
+case 5573: { // glClearBufferiv
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint *value = (GLint *) bp; bp += *valueLen*4+((*valueLen)+1)%2*4;
weglClearBufferiv(*buffer,*drawbuffer,value);
}; break;
-case 5573: { // glClearBufferuiv
+case 5574: { // glClearBufferuiv
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint *value = (GLuint *) bp; bp += *valueLen*4+((*valueLen)+1)%2*4;
weglClearBufferuiv(*buffer,*drawbuffer,value);
}; break;
-case 5574: { // glClearBufferfv
+case 5575: { // glClearBufferfv
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat *value = (GLfloat *) bp; bp += *valueLen*4+((*valueLen)+1)%2*4;
weglClearBufferfv(*buffer,*drawbuffer,value);
}; break;
-case 5575: { // glClearBufferfi
+case 5576: { // glClearBufferfi
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
GLfloat *depth = (GLfloat *) bp; bp += 4;
GLint *stencil = (GLint *) bp; bp += 4;
weglClearBufferfi(*buffer,*drawbuffer,*depth,*stencil);
}; break;
-case 5576: { // glGetStringi
+case 5577: { // glGetStringi
GLenum *name = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
const GLubyte * result = weglGetStringi(*name,*index);
@@ -4335,14 +4343,14 @@ case 5576: { // glGetStringi
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5577: { // glDrawArraysInstanced
+case 5578: { // glDrawArraysInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLint *first = (GLint *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawArraysInstanced(*mode,*first,*count,*primcount);
}; break;
-case 5578: { // glDrawElementsInstanced
+case 5579: { // glDrawElementsInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4350,7 +4358,7 @@ case 5578: { // glDrawElementsInstanced
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawElementsInstanced(*mode,*count,*type,indices,*primcount);
}; break;
-case 5579: { // glDrawElementsInstanced
+case 5580: { // glDrawElementsInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4358,17 +4366,17 @@ case 5579: { // glDrawElementsInstanced
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawElementsInstanced(*mode,*count,*type,indices,*primcount);
}; break;
-case 5580: { // glTexBuffer
+case 5581: { // glTexBuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
weglTexBuffer(*target,*internalformat,*buffer);
}; break;
-case 5581: { // glPrimitiveRestartIndex
+case 5582: { // glPrimitiveRestartIndex
GLuint *index = (GLuint *) bp; bp += 4;
weglPrimitiveRestartIndex(*index);
}; break;
-case 5582: { // glGetInteger64i_v
+case 5583: { // glGetInteger64i_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLint64 data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4396,7 +4404,7 @@ case 5582: { // glGetInteger64i_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5583: { // glGetBufferParameteri64v
+case 5584: { // glGetBufferParameteri64v
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint64 params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4424,40 +4432,40 @@ case 5583: { // glGetBufferParameteri64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5584: { // glFramebufferTexture
+case 5585: { // glFramebufferTexture
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
GLint *level = (GLint *) bp; bp += 4;
weglFramebufferTexture(*target,*attachment,*texture,*level);
}; break;
-case 5585: { // glVertexAttribDivisor
+case 5586: { // glVertexAttribDivisor
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *divisor = (GLuint *) bp; bp += 4;
weglVertexAttribDivisor(*index,*divisor);
}; break;
-case 5586: { // glMinSampleShading
+case 5587: { // glMinSampleShading
GLclampf *value = (GLclampf *) bp; bp += 4;
weglMinSampleShading(*value);
}; break;
-case 5587: { // glBlendEquationi
+case 5588: { // glBlendEquationi
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *mode = (GLenum *) bp; bp += 4;
weglBlendEquationi(*buf,*mode);
}; break;
-case 5588: { // glBlendEquationSeparatei
+case 5589: { // glBlendEquationSeparatei
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *modeRGB = (GLenum *) bp; bp += 4;
GLenum *modeAlpha = (GLenum *) bp; bp += 4;
weglBlendEquationSeparatei(*buf,*modeRGB,*modeAlpha);
}; break;
-case 5589: { // glBlendFunci
+case 5590: { // glBlendFunci
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *src = (GLenum *) bp; bp += 4;
GLenum *dst = (GLenum *) bp; bp += 4;
weglBlendFunci(*buf,*src,*dst);
}; break;
-case 5590: { // glBlendFuncSeparatei
+case 5591: { // glBlendFuncSeparatei
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *srcRGB = (GLenum *) bp; bp += 4;
GLenum *dstRGB = (GLenum *) bp; bp += 4;
@@ -4465,103 +4473,103 @@ case 5590: { // glBlendFuncSeparatei
GLenum *dstAlpha = (GLenum *) bp; bp += 4;
weglBlendFuncSeparatei(*buf,*srcRGB,*dstRGB,*srcAlpha,*dstAlpha);
}; break;
-case 5591: { // glLoadTransposeMatrixfARB
+case 5592: { // glLoadTransposeMatrixfARB
GLfloat * m = (GLfloat *) bp; bp += 64;
weglLoadTransposeMatrixfARB(m);
}; break;
-case 5592: { // glLoadTransposeMatrixdARB
+case 5593: { // glLoadTransposeMatrixdARB
GLdouble * m = (GLdouble *) bp; bp += 128;
weglLoadTransposeMatrixdARB(m);
}; break;
-case 5593: { // glMultTransposeMatrixfARB
+case 5594: { // glMultTransposeMatrixfARB
GLfloat * m = (GLfloat *) bp; bp += 64;
weglMultTransposeMatrixfARB(m);
}; break;
-case 5594: { // glMultTransposeMatrixdARB
+case 5595: { // glMultTransposeMatrixdARB
GLdouble * m = (GLdouble *) bp; bp += 128;
weglMultTransposeMatrixdARB(m);
}; break;
-case 5595: { // glWeightbvARB
+case 5596: { // glWeightbvARB
int * weightsLen = (int *) bp; bp += 4;
- GLbyte * weights = (GLbyte *) bp; bp += (8-((*weightsLen*1+4)%8))%8;
+ GLbyte * weights = (GLbyte *) bp; bp += *weightsLen*1 + (8-((*weightsLen*1+4)%8))%8;
weglWeightbvARB(*weightsLen,weights);
}; break;
-case 5596: { // glWeightsvARB
+case 5597: { // glWeightsvARB
int * weightsLen = (int *) bp; bp += 4;
- GLshort * weights = (GLshort *) bp; bp += (8-((*weightsLen*2+4)%8))%8;
+ GLshort * weights = (GLshort *) bp; bp += *weightsLen*2 + (8-((*weightsLen*2+4)%8))%8;
weglWeightsvARB(*weightsLen,weights);
}; break;
-case 5597: { // glWeightivARB
+case 5598: { // glWeightivARB
int * weightsLen = (int *) bp; bp += 4;
- GLint * weights = (GLint *) bp; bp += (8-((*weightsLen*4+4)%8))%8;
+ GLint * weights = (GLint *) bp; bp += *weightsLen*4 + (8-((*weightsLen*4+4)%8))%8;
weglWeightivARB(*weightsLen,weights);
}; break;
-case 5598: { // glWeightfvARB
+case 5599: { // glWeightfvARB
int * weightsLen = (int *) bp; bp += 4;
- GLfloat * weights = (GLfloat *) bp; bp += (8-((*weightsLen*4+4)%8))%8;
+ GLfloat * weights = (GLfloat *) bp; bp += *weightsLen*4 + (8-((*weightsLen*4+4)%8))%8;
weglWeightfvARB(*weightsLen,weights);
}; break;
-case 5599: { // glWeightdvARB
+case 5600: { // glWeightdvARB
int * weightsLen = (int *) bp; bp += 8;
- GLdouble * weights = (GLdouble *) bp; bp += (8-((*weightsLen*8+0)%8))%8;
+ GLdouble * weights = (GLdouble *) bp; bp += *weightsLen*8 + (8-((*weightsLen*8+0)%8))%8;
weglWeightdvARB(*weightsLen,weights);
}; break;
-case 5600: { // glWeightubvARB
+case 5601: { // glWeightubvARB
int * weightsLen = (int *) bp; bp += 4;
- GLubyte * weights = (GLubyte *) bp; bp += (8-((*weightsLen*1+4)%8))%8;
+ GLubyte * weights = (GLubyte *) bp; bp += *weightsLen*1 + (8-((*weightsLen*1+4)%8))%8;
weglWeightubvARB(*weightsLen,weights);
}; break;
-case 5601: { // glWeightusvARB
+case 5602: { // glWeightusvARB
int * weightsLen = (int *) bp; bp += 4;
- GLushort * weights = (GLushort *) bp; bp += (8-((*weightsLen*2+4)%8))%8;
+ GLushort * weights = (GLushort *) bp; bp += *weightsLen*2 + (8-((*weightsLen*2+4)%8))%8;
weglWeightusvARB(*weightsLen,weights);
}; break;
-case 5602: { // glWeightuivARB
+case 5603: { // glWeightuivARB
int * weightsLen = (int *) bp; bp += 4;
- GLuint * weights = (GLuint *) bp; bp += (8-((*weightsLen*4+4)%8))%8;
+ GLuint * weights = (GLuint *) bp; bp += *weightsLen*4 + (8-((*weightsLen*4+4)%8))%8;
weglWeightuivARB(*weightsLen,weights);
}; break;
-case 5603: { // glVertexBlendARB
+case 5604: { // glVertexBlendARB
GLint *count = (GLint *) bp; bp += 4;
weglVertexBlendARB(*count);
}; break;
-case 5604: { // glCurrentPaletteMatrixARB
+case 5605: { // glCurrentPaletteMatrixARB
GLint *index = (GLint *) bp; bp += 4;
weglCurrentPaletteMatrixARB(*index);
}; break;
-case 5605: { // glMatrixIndexubvARB
+case 5606: { // glMatrixIndexubvARB
int * indicesLen = (int *) bp; bp += 4;
- GLubyte * indices = (GLubyte *) bp; bp += (8-((*indicesLen*1+4)%8))%8;
+ GLubyte * indices = (GLubyte *) bp; bp += *indicesLen*1 + (8-((*indicesLen*1+4)%8))%8;
weglMatrixIndexubvARB(*indicesLen,indices);
}; break;
-case 5606: { // glMatrixIndexusvARB
+case 5607: { // glMatrixIndexusvARB
int * indicesLen = (int *) bp; bp += 4;
- GLushort * indices = (GLushort *) bp; bp += (8-((*indicesLen*2+4)%8))%8;
+ GLushort * indices = (GLushort *) bp; bp += *indicesLen*2 + (8-((*indicesLen*2+4)%8))%8;
weglMatrixIndexusvARB(*indicesLen,indices);
}; break;
-case 5607: { // glMatrixIndexuivARB
+case 5608: { // glMatrixIndexuivARB
int * indicesLen = (int *) bp; bp += 4;
- GLuint * indices = (GLuint *) bp; bp += (8-((*indicesLen*4+4)%8))%8;
+ GLuint * indices = (GLuint *) bp; bp += *indicesLen*4 + (8-((*indicesLen*4+4)%8))%8;
weglMatrixIndexuivARB(*indicesLen,indices);
}; break;
-case 5608: { // glProgramStringARB
+case 5609: { // glProgramStringARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *format = (GLenum *) bp; bp += 4;
GLvoid *string = (GLvoid *) bp;
int stringLen[1] = {(int)strlen((char *)string)}; bp += stringLen[0]+1+((8-((1+stringLen[0]+0)%8))%8);
weglProgramStringARB(*target,*format,*stringLen,string);
}; break;
-case 5609: { // glBindProgramARB
+case 5610: { // glBindProgramARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *program = (GLuint *) bp; bp += 4;
weglBindProgramARB(*target,*program);
}; break;
-case 5610: { // glDeleteProgramsARB
+case 5611: { // glDeleteProgramsARB
int * programsLen = (int *) bp; bp += 4;
- GLuint * programs = (GLuint *) bp; bp += (8-((*programsLen*4+4)%8))%8;
+ GLuint * programs = (GLuint *) bp; bp += *programsLen*4 + (8-((*programsLen*4+4)%8))%8;
weglDeleteProgramsARB(*programsLen,programs);
}; break;
-case 5611: { // glGenProgramsARB
+case 5612: { // glGenProgramsARB
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *programs;
programs = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -4577,7 +4585,7 @@ case 5611: { // glGenProgramsARB
driver_free(rt);
driver_free(programs);
}; break;
-case 5612: { // glProgramEnvParameter4dARB
+case 5613: { // glProgramEnvParameter4dARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -4586,13 +4594,13 @@ case 5612: { // glProgramEnvParameter4dARB
GLdouble *w = (GLdouble *) bp; bp += 8;
weglProgramEnvParameter4dARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5613: { // glProgramEnvParameter4dvARB
+case 5614: { // glProgramEnvParameter4dvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble * params = (GLdouble *) bp; bp += 32;
weglProgramEnvParameter4dvARB(*target,*index,params);
}; break;
-case 5614: { // glProgramEnvParameter4fARB
+case 5615: { // glProgramEnvParameter4fARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *x = (GLfloat *) bp; bp += 4;
@@ -4601,13 +4609,13 @@ case 5614: { // glProgramEnvParameter4fARB
GLfloat *w = (GLfloat *) bp; bp += 4;
weglProgramEnvParameter4fARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5615: { // glProgramEnvParameter4fvARB
+case 5616: { // glProgramEnvParameter4fvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * params = (GLfloat *) bp; bp += 16;
weglProgramEnvParameter4fvARB(*target,*index,params);
}; break;
-case 5616: { // glProgramLocalParameter4dARB
+case 5617: { // glProgramLocalParameter4dARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -4616,13 +4624,13 @@ case 5616: { // glProgramLocalParameter4dARB
GLdouble *w = (GLdouble *) bp; bp += 8;
weglProgramLocalParameter4dARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5617: { // glProgramLocalParameter4dvARB
+case 5618: { // glProgramLocalParameter4dvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble * params = (GLdouble *) bp; bp += 32;
weglProgramLocalParameter4dvARB(*target,*index,params);
}; break;
-case 5618: { // glProgramLocalParameter4fARB
+case 5619: { // glProgramLocalParameter4fARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *x = (GLfloat *) bp; bp += 4;
@@ -4631,13 +4639,13 @@ case 5618: { // glProgramLocalParameter4fARB
GLfloat *w = (GLfloat *) bp; bp += 4;
weglProgramLocalParameter4fARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5619: { // glProgramLocalParameter4fvARB
+case 5620: { // glProgramLocalParameter4fvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * params = (GLfloat *) bp; bp += 16;
weglProgramLocalParameter4fvARB(*target,*index,params);
}; break;
-case 5620: { // glGetProgramEnvParameterdvARB
+case 5621: { // glGetProgramEnvParameterdvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -4653,7 +4661,7 @@ case 5620: { // glGetProgramEnvParameterdvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5621: { // glGetProgramEnvParameterfvARB
+case 5622: { // glGetProgramEnvParameterfvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -4670,7 +4678,7 @@ case 5621: { // glGetProgramEnvParameterfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5622: { // glGetProgramLocalParameterdvARB
+case 5623: { // glGetProgramLocalParameterdvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -4686,7 +4694,7 @@ case 5622: { // glGetProgramLocalParameterdvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5623: { // glGetProgramLocalParameterfvARB
+case 5624: { // glGetProgramLocalParameterfvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -4703,7 +4711,7 @@ case 5623: { // glGetProgramLocalParameterfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5624: { // glGetProgramStringARB
+case 5625: { // glGetProgramStringARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLvoid *string = (GLvoid *) bins[0];
@@ -4714,7 +4722,7 @@ case 5624: { // glGetProgramStringARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5625: { // glGetBufferParameterivARB
+case 5626: { // glGetBufferParameterivARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4742,11 +4750,11 @@ case 5625: { // glGetBufferParameterivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5626: { // glDeleteObjectARB
+case 5627: { // glDeleteObjectARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglDeleteObjectARB(obj);
}; break;
-case 5627: { // glGetHandleARB
+case 5628: { // glGetHandleARB
GLenum *pname = (GLenum *) bp; bp += 4;
GLhandleARB result = weglGetHandleARB(*pname);
int AP = 0; ErlDrvTermData rt[6];
@@ -4755,12 +4763,12 @@ case 5627: { // glGetHandleARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5628: { // glDetachObjectARB
+case 5629: { // glDetachObjectARB
GLhandleARB containerObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLhandleARB attachedObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglDetachObjectARB(containerObj,attachedObj);
}; break;
-case 5629: { // glCreateShaderObjectARB
+case 5630: { // glCreateShaderObjectARB
GLenum *shaderType = (GLenum *) bp; bp += 4;
GLhandleARB result = weglCreateShaderObjectARB(*shaderType);
int AP = 0; ErlDrvTermData rt[6];
@@ -4769,7 +4777,7 @@ case 5629: { // glCreateShaderObjectARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5630: { // glShaderSourceARB
+case 5631: { // glShaderSourceARB
GLhandleARB shaderObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
int * stringLen = (int *) bp; bp += 4;
int * stringTotSize = (int *) bp; bp += 4;
@@ -4781,11 +4789,11 @@ case 5630: { // glShaderSourceARB
weglShaderSourceARB(shaderObj,*stringLen,(const GLchar **) string,NULL);
driver_free(string);
}; break;
-case 5631: { // glCompileShaderARB
+case 5632: { // glCompileShaderARB
GLhandleARB shaderObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglCompileShaderARB(shaderObj);
}; break;
-case 5632: { // glCreateProgramObjectARB
+case 5633: { // glCreateProgramObjectARB
GLhandleARB result = weglCreateProgramObjectARB();
int AP = 0; ErlDrvTermData rt[6];
rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
@@ -4793,24 +4801,24 @@ case 5632: { // glCreateProgramObjectARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5633: { // glAttachObjectARB
+case 5634: { // glAttachObjectARB
GLhandleARB containerObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglAttachObjectARB(containerObj,obj);
}; break;
-case 5634: { // glLinkProgramARB
+case 5635: { // glLinkProgramARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglLinkProgramARB(programObj);
}; break;
-case 5635: { // glUseProgramObjectARB
+case 5636: { // glUseProgramObjectARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglUseProgramObjectARB(programObj);
}; break;
-case 5636: { // glValidateProgramARB
+case 5637: { // glValidateProgramARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglValidateProgramARB(programObj);
}; break;
-case 5637: { // glGetObjectParameterfvARB
+case 5638: { // glGetObjectParameterfvARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat params[1] = {0.0};
@@ -4822,7 +4830,7 @@ case 5637: { // glGetObjectParameterfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5638: { // glGetObjectParameterivARB
+case 5639: { // glGetObjectParameterivARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -4833,7 +4841,7 @@ case 5638: { // glGetObjectParameterivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5639: { // glGetInfoLogARB
+case 5640: { // glGetInfoLogARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -4847,7 +4855,7 @@ case 5639: { // glGetInfoLogARB
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5640: { // glGetAttachedObjectsARB
+case 5641: { // glGetAttachedObjectsARB
GLhandleARB containerObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLsizei *maxCount = (GLsizei *) bp; bp += 4;
GLsizei count[1] = {0};
@@ -4865,7 +4873,7 @@ case 5640: { // glGetAttachedObjectsARB
driver_free(rt);
driver_free(obj);
}; break;
-case 5641: { // glGetUniformLocationARB
+case 5642: { // glGetUniformLocationARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
@@ -4876,7 +4884,7 @@ case 5641: { // glGetUniformLocationARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5642: { // glGetActiveUniformARB
+case 5643: { // glGetActiveUniformARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
@@ -4896,7 +4904,7 @@ case 5642: { // glGetActiveUniformARB
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5643: { // glGetUniformfvARB
+case 5644: { // glGetUniformfvARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLint *location = (GLint *) bp; bp += 4;
GLfloat params[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -4925,7 +4933,7 @@ case 5643: { // glGetUniformfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5644: { // glGetUniformivARB
+case 5645: { // glGetUniformivARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLint *location = (GLint *) bp; bp += 4;
GLint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4953,7 +4961,7 @@ case 5644: { // glGetUniformivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5645: { // glGetShaderSourceARB
+case 5646: { // glGetShaderSourceARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -4967,14 +4975,14 @@ case 5645: { // glGetShaderSourceARB
driver_send_term(port,caller,rt,AP);
driver_free(source);
}; break;
-case 5646: { // glBindAttribLocationARB
+case 5647: { // glBindAttribLocationARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLuint *index = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
weglBindAttribLocationARB(programObj,*index,name);
}; break;
-case 5647: { // glGetActiveAttribARB
+case 5648: { // glGetActiveAttribARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
@@ -4994,7 +5002,7 @@ case 5647: { // glGetActiveAttribARB
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5648: { // glGetAttribLocationARB
+case 5649: { // glGetAttribLocationARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
@@ -5005,7 +5013,7 @@ case 5648: { // glGetAttribLocationARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5649: { // glIsRenderbuffer
+case 5650: { // glIsRenderbuffer
GLuint *renderbuffer = (GLuint *) bp; bp += 4;
GLboolean result = weglIsRenderbuffer(*renderbuffer);
int AP = 0; ErlDrvTermData rt[6];
@@ -5014,17 +5022,17 @@ case 5649: { // glIsRenderbuffer
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5650: { // glBindRenderbuffer
+case 5651: { // glBindRenderbuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *renderbuffer = (GLuint *) bp; bp += 4;
weglBindRenderbuffer(*target,*renderbuffer);
}; break;
-case 5651: { // glDeleteRenderbuffers
+case 5652: { // glDeleteRenderbuffers
int * renderbuffersLen = (int *) bp; bp += 4;
- GLuint * renderbuffers = (GLuint *) bp; bp += (8-((*renderbuffersLen*4+4)%8))%8;
+ GLuint * renderbuffers = (GLuint *) bp; bp += *renderbuffersLen*4 + (8-((*renderbuffersLen*4+4)%8))%8;
weglDeleteRenderbuffers(*renderbuffersLen,renderbuffers);
}; break;
-case 5652: { // glGenRenderbuffers
+case 5653: { // glGenRenderbuffers
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *renderbuffers;
renderbuffers = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -5040,14 +5048,14 @@ case 5652: { // glGenRenderbuffers
driver_free(rt);
driver_free(renderbuffers);
}; break;
-case 5653: { // glRenderbufferStorage
+case 5654: { // glRenderbufferStorage
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLsizei *width = (GLsizei *) bp; bp += 4;
GLsizei *height = (GLsizei *) bp; bp += 4;
weglRenderbufferStorage(*target,*internalformat,*width,*height);
}; break;
-case 5654: { // glGetRenderbufferParameteriv
+case 5655: { // glGetRenderbufferParameteriv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -5058,7 +5066,7 @@ case 5654: { // glGetRenderbufferParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5655: { // glIsFramebuffer
+case 5656: { // glIsFramebuffer
GLuint *framebuffer = (GLuint *) bp; bp += 4;
GLboolean result = weglIsFramebuffer(*framebuffer);
int AP = 0; ErlDrvTermData rt[6];
@@ -5067,17 +5075,17 @@ case 5655: { // glIsFramebuffer
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5656: { // glBindFramebuffer
+case 5657: { // glBindFramebuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *framebuffer = (GLuint *) bp; bp += 4;
weglBindFramebuffer(*target,*framebuffer);
}; break;
-case 5657: { // glDeleteFramebuffers
+case 5658: { // glDeleteFramebuffers
int * framebuffersLen = (int *) bp; bp += 4;
- GLuint * framebuffers = (GLuint *) bp; bp += (8-((*framebuffersLen*4+4)%8))%8;
+ GLuint * framebuffers = (GLuint *) bp; bp += *framebuffersLen*4 + (8-((*framebuffersLen*4+4)%8))%8;
weglDeleteFramebuffers(*framebuffersLen,framebuffers);
}; break;
-case 5658: { // glGenFramebuffers
+case 5659: { // glGenFramebuffers
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *framebuffers;
framebuffers = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -5093,7 +5101,7 @@ case 5658: { // glGenFramebuffers
driver_free(rt);
driver_free(framebuffers);
}; break;
-case 5659: { // glCheckFramebufferStatus
+case 5660: { // glCheckFramebufferStatus
GLenum *target = (GLenum *) bp; bp += 4;
GLenum result = weglCheckFramebufferStatus(*target);
int AP = 0; ErlDrvTermData rt[6];
@@ -5102,7 +5110,7 @@ case 5659: { // glCheckFramebufferStatus
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5660: { // glFramebufferTexture1D
+case 5661: { // glFramebufferTexture1D
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *textarget = (GLenum *) bp; bp += 4;
@@ -5110,7 +5118,7 @@ case 5660: { // glFramebufferTexture1D
GLint *level = (GLint *) bp; bp += 4;
weglFramebufferTexture1D(*target,*attachment,*textarget,*texture,*level);
}; break;
-case 5661: { // glFramebufferTexture2D
+case 5662: { // glFramebufferTexture2D
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *textarget = (GLenum *) bp; bp += 4;
@@ -5118,7 +5126,7 @@ case 5661: { // glFramebufferTexture2D
GLint *level = (GLint *) bp; bp += 4;
weglFramebufferTexture2D(*target,*attachment,*textarget,*texture,*level);
}; break;
-case 5662: { // glFramebufferTexture3D
+case 5663: { // glFramebufferTexture3D
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *textarget = (GLenum *) bp; bp += 4;
@@ -5127,14 +5135,14 @@ case 5662: { // glFramebufferTexture3D
GLint *zoffset = (GLint *) bp; bp += 4;
weglFramebufferTexture3D(*target,*attachment,*textarget,*texture,*level,*zoffset);
}; break;
-case 5663: { // glFramebufferRenderbuffer
+case 5664: { // glFramebufferRenderbuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *renderbuffertarget = (GLenum *) bp; bp += 4;
GLuint *renderbuffer = (GLuint *) bp; bp += 4;
weglFramebufferRenderbuffer(*target,*attachment,*renderbuffertarget,*renderbuffer);
}; break;
-case 5664: { // glGetFramebufferAttachmentParameteriv
+case 5665: { // glGetFramebufferAttachmentParameteriv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -5146,11 +5154,11 @@ case 5664: { // glGetFramebufferAttachmentParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5665: { // glGenerateMipmap
+case 5666: { // glGenerateMipmap
GLenum *target = (GLenum *) bp; bp += 4;
weglGenerateMipmap(*target);
}; break;
-case 5666: { // glBlitFramebuffer
+case 5667: { // glBlitFramebuffer
GLint *srcX0 = (GLint *) bp; bp += 4;
GLint *srcY0 = (GLint *) bp; bp += 4;
GLint *srcX1 = (GLint *) bp; bp += 4;
@@ -5163,7 +5171,7 @@ case 5666: { // glBlitFramebuffer
GLenum *filter = (GLenum *) bp; bp += 4;
weglBlitFramebuffer(*srcX0,*srcY0,*srcX1,*srcY1,*dstX0,*dstY0,*dstX1,*dstY1,*mask,*filter);
}; break;
-case 5667: { // glRenderbufferStorageMultisample
+case 5668: { // glRenderbufferStorageMultisample
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *samples = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
@@ -5171,7 +5179,7 @@ case 5667: { // glRenderbufferStorageMultisample
GLsizei *height = (GLsizei *) bp; bp += 4;
weglRenderbufferStorageMultisample(*target,*samples,*internalformat,*width,*height);
}; break;
-case 5668: { // glFramebufferTextureLayer
+case 5669: { // glFramebufferTextureLayer
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
@@ -5179,7 +5187,7 @@ case 5668: { // glFramebufferTextureLayer
GLint *layer = (GLint *) bp; bp += 4;
weglFramebufferTextureLayer(*target,*attachment,*texture,*level,*layer);
}; break;
-case 5669: { // glFramebufferTextureFaceARB
+case 5670: { // glFramebufferTextureFaceARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
@@ -5187,23 +5195,23 @@ case 5669: { // glFramebufferTextureFaceARB
GLenum *face = (GLenum *) bp; bp += 4;
weglFramebufferTextureFaceARB(*target,*attachment,*texture,*level,*face);
}; break;
-case 5670: { // glFlushMappedBufferRange
+case 5671: { // glFlushMappedBufferRange
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
GLsizeiptr length = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
weglFlushMappedBufferRange(*target,offset,length);
}; break;
-case 5671: { // glBindVertexArray
+case 5672: { // glBindVertexArray
GLuint *array = (GLuint *) bp; bp += 4;
weglBindVertexArray(*array);
}; break;
-case 5672: { // glDeleteVertexArrays
+case 5673: { // glDeleteVertexArrays
int * arraysLen = (int *) bp; bp += 4;
- GLuint * arrays = (GLuint *) bp; bp += (8-((*arraysLen*4+4)%8))%8;
+ GLuint * arrays = (GLuint *) bp; bp += *arraysLen*4 + (8-((*arraysLen*4+4)%8))%8;
weglDeleteVertexArrays(*arraysLen,arrays);
}; break;
-case 5673: { // glGenVertexArrays
+case 5674: { // glGenVertexArrays
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *arrays;
arrays = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -5219,7 +5227,7 @@ case 5673: { // glGenVertexArrays
driver_free(rt);
driver_free(arrays);
}; break;
-case 5674: { // glIsVertexArray
+case 5675: { // glIsVertexArray
GLuint *array = (GLuint *) bp; bp += 4;
GLboolean result = weglIsVertexArray(*array);
int AP = 0; ErlDrvTermData rt[6];
@@ -5228,7 +5236,7 @@ case 5674: { // glIsVertexArray
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5675: { // glGetUniformIndices
+case 5676: { // glGetUniformIndices
GLuint *program = (GLuint *) bp; bp += 4;
int * uniformNamesLen = (int *) bp; bp += 4;
int * uniformNamesTotSize = (int *) bp; bp += 4;
@@ -5252,10 +5260,10 @@ case 5675: { // glGetUniformIndices
driver_free(uniformIndices);
driver_free(uniformNames);
}; break;
-case 5676: { // glGetActiveUniformsiv
+case 5677: { // glGetActiveUniformsiv
GLuint *program = (GLuint *) bp; bp += 4;
int * uniformIndicesLen = (int *) bp; bp += 4;
- GLuint * uniformIndices = (GLuint *) bp; bp += (8-((*uniformIndicesLen*4+0)%8))%8;
+ GLuint * uniformIndices = (GLuint *) bp; bp += *uniformIndicesLen*4 + (8-((*uniformIndicesLen*4+0)%8))%8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *params;
params = (GLint *) driver_alloc(sizeof(GLint) * *uniformIndicesLen);
@@ -5271,7 +5279,7 @@ case 5676: { // glGetActiveUniformsiv
driver_free(rt);
driver_free(params);
}; break;
-case 5677: { // glGetActiveUniformName
+case 5678: { // glGetActiveUniformName
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformIndex = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5286,7 +5294,7 @@ case 5677: { // glGetActiveUniformName
driver_send_term(port,caller,rt,AP);
driver_free(uniformName);
}; break;
-case 5678: { // glGetUniformBlockIndex
+case 5679: { // glGetUniformBlockIndex
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *uniformBlockName = (GLchar *) bp;
int uniformBlockNameLen[1] = {(int)strlen((char *)uniformBlockName)}; bp += uniformBlockNameLen[0]+1+((8-((1+uniformBlockNameLen[0]+4)%8))%8);
@@ -5297,7 +5305,7 @@ case 5678: { // glGetUniformBlockIndex
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5679: { // glGetActiveUniformBlockiv
+case 5680: { // glGetActiveUniformBlockiv
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformBlockIndex = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -5309,7 +5317,7 @@ case 5679: { // glGetActiveUniformBlockiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5680: { // glGetActiveUniformBlockName
+case 5681: { // glGetActiveUniformBlockName
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformBlockIndex = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5324,13 +5332,13 @@ case 5680: { // glGetActiveUniformBlockName
driver_send_term(port,caller,rt,AP);
driver_free(uniformBlockName);
}; break;
-case 5681: { // glUniformBlockBinding
+case 5682: { // glUniformBlockBinding
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformBlockIndex = (GLuint *) bp; bp += 4;
GLuint *uniformBlockBinding = (GLuint *) bp; bp += 4;
weglUniformBlockBinding(*program,*uniformBlockIndex,*uniformBlockBinding);
}; break;
-case 5682: { // glCopyBufferSubData
+case 5683: { // glCopyBufferSubData
GLenum *readTarget = (GLenum *) bp; bp += 4;
GLenum *writeTarget = (GLenum *) bp; bp += 4;
GLintptr readOffset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -5338,7 +5346,7 @@ case 5682: { // glCopyBufferSubData
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
weglCopyBufferSubData(*readTarget,*writeTarget,readOffset,writeOffset,size);
}; break;
-case 5683: { // glDrawElementsBaseVertex
+case 5684: { // glDrawElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5346,7 +5354,7 @@ case 5683: { // glDrawElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsBaseVertex(*mode,*count,*type,indices,*basevertex);
}; break;
-case 5684: { // glDrawElementsBaseVertex
+case 5685: { // glDrawElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5354,7 +5362,7 @@ case 5684: { // glDrawElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsBaseVertex(*mode,*count,*type,indices,*basevertex);
}; break;
-case 5685: { // glDrawRangeElementsBaseVertex
+case 5686: { // glDrawRangeElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *start = (GLuint *) bp; bp += 4;
GLuint *end = (GLuint *) bp; bp += 4;
@@ -5364,7 +5372,7 @@ case 5685: { // glDrawRangeElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawRangeElementsBaseVertex(*mode,*start,*end,*count,*type,indices,*basevertex);
}; break;
-case 5686: { // glDrawRangeElementsBaseVertex
+case 5687: { // glDrawRangeElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *start = (GLuint *) bp; bp += 4;
GLuint *end = (GLuint *) bp; bp += 4;
@@ -5374,7 +5382,7 @@ case 5686: { // glDrawRangeElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawRangeElementsBaseVertex(*mode,*start,*end,*count,*type,indices,*basevertex);
}; break;
-case 5687: { // glDrawElementsInstancedBaseVertex
+case 5688: { // glDrawElementsInstancedBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5383,7 +5391,7 @@ case 5687: { // glDrawElementsInstancedBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertex(*mode,*count,*type,indices,*primcount,*basevertex);
}; break;
-case 5688: { // glDrawElementsInstancedBaseVertex
+case 5689: { // glDrawElementsInstancedBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5392,11 +5400,11 @@ case 5688: { // glDrawElementsInstancedBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertex(*mode,*count,*type,indices,*primcount,*basevertex);
}; break;
-case 5689: { // glProvokingVertex
+case 5690: { // glProvokingVertex
GLenum *mode = (GLenum *) bp; bp += 4;
weglProvokingVertex(*mode);
}; break;
-case 5690: { // glFenceSync
+case 5691: { // glFenceSync
GLenum *condition = (GLenum *) bp; bp += 4;
GLbitfield *flags = (GLbitfield *) bp; bp += 4;
GLsync result = weglFenceSync(*condition,*flags);
@@ -5406,7 +5414,7 @@ case 5690: { // glFenceSync
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5691: { // glIsSync
+case 5692: { // glIsSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLboolean result = weglIsSync(sync);
int AP = 0; ErlDrvTermData rt[6];
@@ -5415,11 +5423,11 @@ case 5691: { // glIsSync
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5692: { // glDeleteSync
+case 5693: { // glDeleteSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
weglDeleteSync(sync);
}; break;
-case 5693: { // glClientWaitSync
+case 5694: { // glClientWaitSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLbitfield *flags = (GLbitfield *) bp; bp += 4;
bp += 4;
@@ -5431,14 +5439,14 @@ case 5693: { // glClientWaitSync
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5694: { // glWaitSync
+case 5695: { // glWaitSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLbitfield *flags = (GLbitfield *) bp; bp += 4;
bp += 4;
GLuint64 timeout = (GLuint64) * (GLuint64EXT *) bp; bp += 8;
weglWaitSync(sync,*flags,timeout);
}; break;
-case 5695: { // glGetInteger64v
+case 5696: { // glGetInteger64v
GLenum *pname = (GLenum *) bp; bp += 4;
GLint64 params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
weglGetInteger64v(*pname,params);
@@ -5465,7 +5473,7 @@ case 5695: { // glGetInteger64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5696: { // glGetSynciv
+case 5697: { // glGetSynciv
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5484,7 +5492,7 @@ case 5696: { // glGetSynciv
driver_free(rt);
driver_free(values);
}; break;
-case 5697: { // glTexImage2DMultisample
+case 5698: { // glTexImage2DMultisample
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *samples = (GLsizei *) bp; bp += 4;
GLint *internalformat = (GLint *) bp; bp += 4;
@@ -5493,7 +5501,7 @@ case 5697: { // glTexImage2DMultisample
GLboolean *fixedsamplelocations = (GLboolean *) bp; bp += 1;
weglTexImage2DMultisample(*target,*samples,*internalformat,*width,*height,*fixedsamplelocations);
}; break;
-case 5698: { // glTexImage3DMultisample
+case 5699: { // glTexImage3DMultisample
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *samples = (GLsizei *) bp; bp += 4;
GLint *internalformat = (GLint *) bp; bp += 4;
@@ -5503,7 +5511,7 @@ case 5698: { // glTexImage3DMultisample
GLboolean *fixedsamplelocations = (GLboolean *) bp; bp += 1;
weglTexImage3DMultisample(*target,*samples,*internalformat,*width,*height,*depth,*fixedsamplelocations);
}; break;
-case 5699: { // glGetMultisamplefv
+case 5700: { // glGetMultisamplefv
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat val[2] = {0.0,0.0};
@@ -5518,12 +5526,12 @@ case 5699: { // glGetMultisamplefv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5700: { // glSampleMaski
+case 5701: { // glSampleMaski
GLuint *index = (GLuint *) bp; bp += 4;
GLbitfield *mask = (GLbitfield *) bp; bp += 4;
weglSampleMaski(*index,*mask);
}; break;
-case 5701: { // glNamedStringARB
+case 5702: { // glNamedStringARB
GLenum *type = (GLenum *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -5531,12 +5539,12 @@ case 5701: { // glNamedStringARB
int stringLen[1] = {(int)strlen((char *)string)}; bp += stringLen[0]+1+((8-((1+stringLen[0]+0)%8))%8);
weglNamedStringARB(*type,*nameLen,name,*stringLen,string);
}; break;
-case 5702: { // glDeleteNamedStringARB
+case 5703: { // glDeleteNamedStringARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
weglDeleteNamedStringARB(*nameLen,name);
}; break;
-case 5703: { // glCompileShaderIncludeARB
+case 5704: { // glCompileShaderIncludeARB
GLuint *shader = (GLuint *) bp; bp += 4;
int * pathLen = (int *) bp; bp += 4;
int * pathTotSize = (int *) bp; bp += 4;
@@ -5548,7 +5556,7 @@ case 5703: { // glCompileShaderIncludeARB
weglCompileShaderIncludeARB(*shader,*pathLen,(const GLchar **) path,NULL);
driver_free(path);
}; break;
-case 5704: { // glIsNamedStringARB
+case 5705: { // glIsNamedStringARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
GLboolean result = weglIsNamedStringARB(*nameLen,name);
@@ -5558,7 +5566,7 @@ case 5704: { // glIsNamedStringARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5705: { // glGetNamedStringARB
+case 5706: { // glGetNamedStringARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5573,7 +5581,7 @@ case 5705: { // glGetNamedStringARB
driver_send_term(port,caller,rt,AP);
driver_free(string);
}; break;
-case 5706: { // glGetNamedStringivARB
+case 5707: { // glGetNamedStringivARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -5585,7 +5593,7 @@ case 5706: { // glGetNamedStringivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5707: { // glBindFragDataLocationIndexed
+case 5708: { // glBindFragDataLocationIndexed
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *colorNumber = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
@@ -5593,7 +5601,7 @@ case 5707: { // glBindFragDataLocationIndexed
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
weglBindFragDataLocationIndexed(*program,*colorNumber,*index,name);
}; break;
-case 5708: { // glGetFragDataIndex
+case 5709: { // glGetFragDataIndex
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -5604,7 +5612,7 @@ case 5708: { // glGetFragDataIndex
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5709: { // glGenSamplers
+case 5710: { // glGenSamplers
GLsizei *count = (GLsizei *) bp; bp += 4;
GLuint *samplers;
samplers = (GLuint *) driver_alloc(sizeof(GLuint) * *count);
@@ -5620,12 +5628,12 @@ case 5709: { // glGenSamplers
driver_free(rt);
driver_free(samplers);
}; break;
-case 5710: { // glDeleteSamplers
+case 5711: { // glDeleteSamplers
int * samplersLen = (int *) bp; bp += 4;
- GLuint * samplers = (GLuint *) bp; bp += (8-((*samplersLen*4+4)%8))%8;
+ GLuint * samplers = (GLuint *) bp; bp += *samplersLen*4 + (8-((*samplersLen*4+4)%8))%8;
weglDeleteSamplers(*samplersLen,samplers);
}; break;
-case 5711: { // glIsSampler
+case 5712: { // glIsSampler
GLuint *sampler = (GLuint *) bp; bp += 4;
GLboolean result = weglIsSampler(*sampler);
int AP = 0; ErlDrvTermData rt[6];
@@ -5634,52 +5642,52 @@ case 5711: { // glIsSampler
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5712: { // glBindSampler
+case 5713: { // glBindSampler
GLuint *unit = (GLuint *) bp; bp += 4;
GLuint *sampler = (GLuint *) bp; bp += 4;
weglBindSampler(*unit,*sampler);
}; break;
-case 5713: { // glSamplerParameteri
+case 5714: { // glSamplerParameteri
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *param = (GLint *) bp; bp += 4;
weglSamplerParameteri(*sampler,*pname,*param);
}; break;
-case 5714: { // glSamplerParameteriv
+case 5715: { // glSamplerParameteriv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLint * param = (GLint *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLint * param = (GLint *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameteriv(*sampler,*pname,param);
}; break;
-case 5715: { // glSamplerParameterf
+case 5716: { // glSamplerParameterf
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat *param = (GLfloat *) bp; bp += 4;
weglSamplerParameterf(*sampler,*pname,*param);
}; break;
-case 5716: { // glSamplerParameterfv
+case 5717: { // glSamplerParameterfv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLfloat * param = (GLfloat *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLfloat * param = (GLfloat *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameterfv(*sampler,*pname,param);
}; break;
-case 5717: { // glSamplerParameterIiv
+case 5718: { // glSamplerParameterIiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLint * param = (GLint *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLint * param = (GLint *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameterIiv(*sampler,*pname,param);
}; break;
-case 5718: { // glSamplerParameterIuiv
+case 5719: { // glSamplerParameterIuiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLuint * param = (GLuint *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLuint * param = (GLuint *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameterIuiv(*sampler,*pname,param);
}; break;
-case 5719: { // glGetSamplerParameteriv
+case 5720: { // glGetSamplerParameteriv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -5695,7 +5703,7 @@ case 5719: { // glGetSamplerParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5720: { // glGetSamplerParameterIiv
+case 5721: { // glGetSamplerParameterIiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -5711,7 +5719,7 @@ case 5720: { // glGetSamplerParameterIiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5721: { // glGetSamplerParameterfv
+case 5722: { // glGetSamplerParameterfv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -5728,7 +5736,7 @@ case 5721: { // glGetSamplerParameterfv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5722: { // glGetSamplerParameterIuiv
+case 5723: { // glGetSamplerParameterIuiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[4] = {0,0,0,0};
@@ -5744,12 +5752,12 @@ case 5722: { // glGetSamplerParameterIuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5723: { // glQueryCounter
+case 5724: { // glQueryCounter
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *target = (GLenum *) bp; bp += 4;
weglQueryCounter(*id,*target);
}; break;
-case 5724: { // glGetQueryObjecti64v
+case 5725: { // glGetQueryObjecti64v
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint64 params[1] = {0};
@@ -5760,7 +5768,7 @@ case 5724: { // glGetQueryObjecti64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5725: { // glGetQueryObjectui64v
+case 5726: { // glGetQueryObjectui64v
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint64 params[1] = {0};
@@ -5771,42 +5779,42 @@ case 5725: { // glGetQueryObjectui64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5726: { // glDrawArraysIndirect
+case 5727: { // glDrawArraysIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglDrawArraysIndirect(*mode,indirect);
}; break;
-case 5727: { // glDrawArraysIndirect
+case 5728: { // glDrawArraysIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) bins[0];
weglDrawArraysIndirect(*mode,indirect);
}; break;
-case 5728: { // glDrawElementsIndirect
+case 5729: { // glDrawElementsIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglDrawElementsIndirect(*mode,*type,indirect);
}; break;
-case 5729: { // glDrawElementsIndirect
+case 5730: { // glDrawElementsIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) bins[0];
weglDrawElementsIndirect(*mode,*type,indirect);
}; break;
-case 5730: { // glUniform1d
+case 5731: { // glUniform1d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
weglUniform1d(*location,*x);
}; break;
-case 5731: { // glUniform2d
+case 5732: { // glUniform2d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
GLdouble *y = (GLdouble *) bp; bp += 8;
weglUniform2d(*location,*x,*y);
}; break;
-case 5732: { // glUniform3d
+case 5733: { // glUniform3d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -5814,7 +5822,7 @@ case 5732: { // glUniform3d
GLdouble *z = (GLdouble *) bp; bp += 8;
weglUniform3d(*location,*x,*y,*z);
}; break;
-case 5733: { // glUniform4d
+case 5734: { // glUniform4d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -5823,35 +5831,35 @@ case 5733: { // glUniform4d
GLdouble *w = (GLdouble *) bp; bp += 8;
weglUniform4d(*location,*x,*y,*z,*w);
}; break;
-case 5734: { // glUniform1dv
+case 5735: { // glUniform1dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int * valueLen = (int *) bp; bp += 8;
- GLdouble * value = (GLdouble *) bp; bp += (8-((*valueLen*8+0)%8))%8;
+ GLdouble * value = (GLdouble *) bp; bp += *valueLen*8 + (8-((*valueLen*8+0)%8))%8;
weglUniform1dv(*location,*valueLen,value);
}; break;
-case 5735: { // glUniform2dv
+case 5736: { // glUniform2dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*16;
weglUniform2dv(*location,*valueLen,value);
}; break;
-case 5736: { // glUniform3dv
+case 5737: { // glUniform3dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*24;
weglUniform3dv(*location,*valueLen,value);
}; break;
-case 5737: { // glUniform4dv
+case 5738: { // glUniform4dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglUniform4dv(*location,*valueLen,value);
}; break;
-case 5738: { // glUniformMatrix2dv
+case 5739: { // glUniformMatrix2dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5859,7 +5867,7 @@ case 5738: { // glUniformMatrix2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglUniformMatrix2dv(*location,*valueLen,*transpose,value);
}; break;
-case 5739: { // glUniformMatrix3dv
+case 5740: { // glUniformMatrix3dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5867,7 +5875,7 @@ case 5739: { // glUniformMatrix3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*72;
weglUniformMatrix3dv(*location,*valueLen,*transpose,value);
}; break;
-case 5740: { // glUniformMatrix4dv
+case 5741: { // glUniformMatrix4dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5875,7 +5883,7 @@ case 5740: { // glUniformMatrix4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*128;
weglUniformMatrix4dv(*location,*valueLen,*transpose,value);
}; break;
-case 5741: { // glUniformMatrix2x3dv
+case 5742: { // glUniformMatrix2x3dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5883,7 +5891,7 @@ case 5741: { // glUniformMatrix2x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglUniformMatrix2x3dv(*location,*valueLen,*transpose,value);
}; break;
-case 5742: { // glUniformMatrix2x4dv
+case 5743: { // glUniformMatrix2x4dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5891,7 +5899,7 @@ case 5742: { // glUniformMatrix2x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglUniformMatrix2x4dv(*location,*valueLen,*transpose,value);
}; break;
-case 5743: { // glUniformMatrix3x2dv
+case 5744: { // glUniformMatrix3x2dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5899,7 +5907,7 @@ case 5743: { // glUniformMatrix3x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglUniformMatrix3x2dv(*location,*valueLen,*transpose,value);
}; break;
-case 5744: { // glUniformMatrix3x4dv
+case 5745: { // glUniformMatrix3x4dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5907,7 +5915,7 @@ case 5744: { // glUniformMatrix3x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglUniformMatrix3x4dv(*location,*valueLen,*transpose,value);
}; break;
-case 5745: { // glUniformMatrix4x2dv
+case 5746: { // glUniformMatrix4x2dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5915,7 +5923,7 @@ case 5745: { // glUniformMatrix4x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglUniformMatrix4x2dv(*location,*valueLen,*transpose,value);
}; break;
-case 5746: { // glUniformMatrix4x3dv
+case 5747: { // glUniformMatrix4x3dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5923,7 +5931,7 @@ case 5746: { // glUniformMatrix4x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglUniformMatrix4x3dv(*location,*valueLen,*transpose,value);
}; break;
-case 5747: { // glGetUniformdv
+case 5748: { // glGetUniformdv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble params[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -5951,7 +5959,7 @@ case 5747: { // glGetUniformdv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5748: { // glGetSubroutineUniformLocation
+case 5749: { // glGetSubroutineUniformLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
@@ -5963,7 +5971,7 @@ case 5748: { // glGetSubroutineUniformLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5749: { // glGetSubroutineIndex
+case 5750: { // glGetSubroutineIndex
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
@@ -5975,7 +5983,7 @@ case 5749: { // glGetSubroutineIndex
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5750: { // glGetActiveSubroutineUniformName
+case 5751: { // glGetActiveSubroutineUniformName
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
@@ -5991,7 +5999,7 @@ case 5750: { // glGetActiveSubroutineUniformName
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5751: { // glGetActiveSubroutineName
+case 5752: { // glGetActiveSubroutineName
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
@@ -6007,13 +6015,13 @@ case 5751: { // glGetActiveSubroutineName
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5752: { // glUniformSubroutinesuiv
+case 5753: { // glUniformSubroutinesuiv
GLenum *shadertype = (GLenum *) bp; bp += 4;
int * indicesLen = (int *) bp; bp += 4;
- GLuint * indices = (GLuint *) bp; bp += (8-((*indicesLen*4+0)%8))%8;
+ GLuint * indices = (GLuint *) bp; bp += *indicesLen*4 + (8-((*indicesLen*4+0)%8))%8;
weglUniformSubroutinesuiv(*shadertype,*indicesLen,indices);
}; break;
-case 5753: { // glGetUniformSubroutineuiv
+case 5754: { // glGetUniformSubroutineuiv
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -6041,7 +6049,7 @@ case 5753: { // glGetUniformSubroutineuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5754: { // glGetProgramStageiv
+case 5755: { // glGetProgramStageiv
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -6053,28 +6061,28 @@ case 5754: { // glGetProgramStageiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5755: { // glPatchParameteri
+case 5756: { // glPatchParameteri
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *value = (GLint *) bp; bp += 4;
weglPatchParameteri(*pname,*value);
}; break;
-case 5756: { // glPatchParameterfv
+case 5757: { // glPatchParameterfv
GLenum *pname = (GLenum *) bp; bp += 4;
int * valuesLen = (int *) bp; bp += 4;
- GLfloat * values = (GLfloat *) bp; bp += (8-((*valuesLen*4+0)%8))%8;
+ GLfloat * values = (GLfloat *) bp; bp += *valuesLen*4 + (8-((*valuesLen*4+0)%8))%8;
weglPatchParameterfv(*pname,values);
}; break;
-case 5757: { // glBindTransformFeedback
+case 5758: { // glBindTransformFeedback
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglBindTransformFeedback(*target,*id);
}; break;
-case 5758: { // glDeleteTransformFeedbacks
+case 5759: { // glDeleteTransformFeedbacks
int * idsLen = (int *) bp; bp += 4;
- GLuint * ids = (GLuint *) bp; bp += (8-((*idsLen*4+4)%8))%8;
+ GLuint * ids = (GLuint *) bp; bp += *idsLen*4 + (8-((*idsLen*4+4)%8))%8;
weglDeleteTransformFeedbacks(*idsLen,ids);
}; break;
-case 5759: { // glGenTransformFeedbacks
+case 5760: { // glGenTransformFeedbacks
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *ids;
ids = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -6090,7 +6098,7 @@ case 5759: { // glGenTransformFeedbacks
driver_free(rt);
driver_free(ids);
}; break;
-case 5760: { // glIsTransformFeedback
+case 5761: { // glIsTransformFeedback
GLuint *id = (GLuint *) bp; bp += 4;
GLboolean result = weglIsTransformFeedback(*id);
int AP = 0; ErlDrvTermData rt[6];
@@ -6099,35 +6107,35 @@ case 5760: { // glIsTransformFeedback
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5761: { // glPauseTransformFeedback
+case 5762: { // glPauseTransformFeedback
weglPauseTransformFeedback();
}; break;
-case 5762: { // glResumeTransformFeedback
+case 5763: { // glResumeTransformFeedback
weglResumeTransformFeedback();
}; break;
-case 5763: { // glDrawTransformFeedback
+case 5764: { // glDrawTransformFeedback
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglDrawTransformFeedback(*mode,*id);
}; break;
-case 5764: { // glDrawTransformFeedbackStream
+case 5765: { // glDrawTransformFeedbackStream
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
GLuint *stream = (GLuint *) bp; bp += 4;
weglDrawTransformFeedbackStream(*mode,*id,*stream);
}; break;
-case 5765: { // glBeginQueryIndexed
+case 5766: { // glBeginQueryIndexed
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglBeginQueryIndexed(*target,*index,*id);
}; break;
-case 5766: { // glEndQueryIndexed
+case 5767: { // glEndQueryIndexed
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
weglEndQueryIndexed(*target,*index);
}; break;
-case 5767: { // glGetQueryIndexediv
+case 5768: { // glGetQueryIndexediv
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -6139,18 +6147,18 @@ case 5767: { // glGetQueryIndexediv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5768: { // glReleaseShaderCompiler
+case 5769: { // glReleaseShaderCompiler
weglReleaseShaderCompiler();
}; break;
-case 5769: { // glShaderBinary
+case 5770: { // glShaderBinary
int * shadersLen = (int *) bp; bp += 4;
- GLuint * shaders = (GLuint *) bp; bp += (8-((*shadersLen*4+4)%8))%8;
+ GLuint * shaders = (GLuint *) bp; bp += *shadersLen*4 + (8-((*shadersLen*4+4)%8))%8;
GLenum *binaryformat = (GLenum *) bp; bp += 4;
GLvoid *binary = (GLvoid *) bins[0];
GLsizei binary_size = bins_sz[0];
weglShaderBinary(*shadersLen,shaders,*binaryformat,binary,binary_size);
}; break;
-case 5770: { // glGetShaderPrecisionFormat
+case 5771: { // glGetShaderPrecisionFormat
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLenum *precisiontype = (GLenum *) bp; bp += 4;
GLint range[2] = {0,0};
@@ -6167,16 +6175,16 @@ case 5770: { // glGetShaderPrecisionFormat
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5771: { // glDepthRangef
+case 5772: { // glDepthRangef
GLclampf *n = (GLclampf *) bp; bp += 4;
GLclampf *f = (GLclampf *) bp; bp += 4;
weglDepthRangef(*n,*f);
}; break;
-case 5772: { // glClearDepthf
+case 5773: { // glClearDepthf
GLclampf *d = (GLclampf *) bp; bp += 4;
weglClearDepthf(*d);
}; break;
-case 5773: { // glGetProgramBinary
+case 5774: { // glGetProgramBinary
GLuint *program = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -6192,31 +6200,31 @@ case 5773: { // glGetProgramBinary
driver_send_term(port,caller,rt,AP);
driver_free_binary(binary);
}; break;
-case 5774: { // glProgramBinary
+case 5775: { // glProgramBinary
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *binaryFormat = (GLenum *) bp; bp += 4;
GLvoid *binary = (GLvoid *) bins[0];
GLsizei binary_size = bins_sz[0];
weglProgramBinary(*program,*binaryFormat,binary,binary_size);
}; break;
-case 5775: { // glProgramParameteri
+case 5776: { // glProgramParameteri
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *value = (GLint *) bp; bp += 4;
weglProgramParameteri(*program,*pname,*value);
}; break;
-case 5776: { // glUseProgramStages
+case 5777: { // glUseProgramStages
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLbitfield *stages = (GLbitfield *) bp; bp += 4;
GLuint *program = (GLuint *) bp; bp += 4;
weglUseProgramStages(*pipeline,*stages,*program);
}; break;
-case 5777: { // glActiveShaderProgram
+case 5778: { // glActiveShaderProgram
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLuint *program = (GLuint *) bp; bp += 4;
weglActiveShaderProgram(*pipeline,*program);
}; break;
-case 5778: { // glCreateShaderProgramv
+case 5779: { // glCreateShaderProgramv
GLenum *type = (GLenum *) bp; bp += 4;
int * stringsLen = (int *) bp; bp += 4;
int * stringsTotSize = (int *) bp; bp += 4;
@@ -6233,16 +6241,16 @@ case 5778: { // glCreateShaderProgramv
driver_send_term(port,caller,rt,AP);
driver_free(strings);
}; break;
-case 5779: { // glBindProgramPipeline
+case 5780: { // glBindProgramPipeline
GLuint *pipeline = (GLuint *) bp; bp += 4;
weglBindProgramPipeline(*pipeline);
}; break;
-case 5780: { // glDeleteProgramPipelines
+case 5781: { // glDeleteProgramPipelines
int * pipelinesLen = (int *) bp; bp += 4;
- GLuint * pipelines = (GLuint *) bp; bp += (8-((*pipelinesLen*4+4)%8))%8;
+ GLuint * pipelines = (GLuint *) bp; bp += *pipelinesLen*4 + (8-((*pipelinesLen*4+4)%8))%8;
weglDeleteProgramPipelines(*pipelinesLen,pipelines);
}; break;
-case 5781: { // glGenProgramPipelines
+case 5782: { // glGenProgramPipelines
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *pipelines;
pipelines = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -6258,7 +6266,7 @@ case 5781: { // glGenProgramPipelines
driver_free(rt);
driver_free(pipelines);
}; break;
-case 5782: { // glIsProgramPipeline
+case 5783: { // glIsProgramPipeline
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLboolean result = weglIsProgramPipeline(*pipeline);
int AP = 0; ErlDrvTermData rt[6];
@@ -6267,7 +6275,7 @@ case 5782: { // glIsProgramPipeline
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5783: { // glGetProgramPipelineiv
+case 5784: { // glGetProgramPipelineiv
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -6278,115 +6286,115 @@ case 5783: { // glGetProgramPipelineiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5784: { // glProgramUniform1i
+case 5785: { // glProgramUniform1i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
weglProgramUniform1i(*program,*location,*v0);
}; break;
-case 5785: { // glProgramUniform1iv
+case 5786: { // glProgramUniform1iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLint * value = (GLint *) bp; bp += (8-((*valueLen*4+4)%8))%8;
+ GLint * value = (GLint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+4)%8))%8;
weglProgramUniform1iv(*program,*location,*valueLen,value);
}; break;
-case 5786: { // glProgramUniform1f
+case 5787: { // glProgramUniform1f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
weglProgramUniform1f(*program,*location,*v0);
}; break;
-case 5787: { // glProgramUniform1fv
+case 5788: { // glProgramUniform1fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLfloat * value = (GLfloat *) bp; bp += (8-((*valueLen*4+4)%8))%8;
+ GLfloat * value = (GLfloat *) bp; bp += *valueLen*4 + (8-((*valueLen*4+4)%8))%8;
weglProgramUniform1fv(*program,*location,*valueLen,value);
}; break;
-case 5788: { // glProgramUniform1d
+case 5789: { // glProgramUniform1d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
weglProgramUniform1d(*program,*location,*v0);
}; break;
-case 5789: { // glProgramUniform1dv
+case 5790: { // glProgramUniform1dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 8;
- GLdouble * value = (GLdouble *) bp; bp += (8-((*valueLen*8+0)%8))%8;
+ GLdouble * value = (GLdouble *) bp; bp += *valueLen*8 + (8-((*valueLen*8+0)%8))%8;
weglProgramUniform1dv(*program,*location,*valueLen,value);
}; break;
-case 5790: { // glProgramUniform1ui
+case 5791: { // glProgramUniform1ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
weglProgramUniform1ui(*program,*location,*v0);
}; break;
-case 5791: { // glProgramUniform1uiv
+case 5792: { // glProgramUniform1uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLuint * value = (GLuint *) bp; bp += (8-((*valueLen*4+4)%8))%8;
+ GLuint * value = (GLuint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+4)%8))%8;
weglProgramUniform1uiv(*program,*location,*valueLen,value);
}; break;
-case 5792: { // glProgramUniform2i
+case 5793: { // glProgramUniform2i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
weglProgramUniform2i(*program,*location,*v0,*v1);
}; break;
-case 5793: { // glProgramUniform2iv
+case 5794: { // glProgramUniform2iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*8;
weglProgramUniform2iv(*program,*location,*valueLen,value);
}; break;
-case 5794: { // glProgramUniform2f
+case 5795: { // glProgramUniform2f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
weglProgramUniform2f(*program,*location,*v0,*v1);
}; break;
-case 5795: { // glProgramUniform2fv
+case 5796: { // glProgramUniform2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*8;
weglProgramUniform2fv(*program,*location,*valueLen,value);
}; break;
-case 5796: { // glProgramUniform2d
+case 5797: { // glProgramUniform2d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
GLdouble *v1 = (GLdouble *) bp; bp += 8;
weglProgramUniform2d(*program,*location,*v0,*v1);
}; break;
-case 5797: { // glProgramUniform2dv
+case 5798: { // glProgramUniform2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*16;
weglProgramUniform2dv(*program,*location,*valueLen,value);
}; break;
-case 5798: { // glProgramUniform2ui
+case 5799: { // glProgramUniform2ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
weglProgramUniform2ui(*program,*location,*v0,*v1);
}; break;
-case 5799: { // glProgramUniform2uiv
+case 5800: { // glProgramUniform2uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*8;
weglProgramUniform2uiv(*program,*location,*valueLen,value);
}; break;
-case 5800: { // glProgramUniform3i
+case 5801: { // glProgramUniform3i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
@@ -6394,14 +6402,14 @@ case 5800: { // glProgramUniform3i
GLint *v2 = (GLint *) bp; bp += 4;
weglProgramUniform3i(*program,*location,*v0,*v1,*v2);
}; break;
-case 5801: { // glProgramUniform3iv
+case 5802: { // glProgramUniform3iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*12;
weglProgramUniform3iv(*program,*location,*valueLen,value);
}; break;
-case 5802: { // glProgramUniform3f
+case 5803: { // glProgramUniform3f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
@@ -6409,14 +6417,14 @@ case 5802: { // glProgramUniform3f
GLfloat *v2 = (GLfloat *) bp; bp += 4;
weglProgramUniform3f(*program,*location,*v0,*v1,*v2);
}; break;
-case 5803: { // glProgramUniform3fv
+case 5804: { // glProgramUniform3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*12;
weglProgramUniform3fv(*program,*location,*valueLen,value);
}; break;
-case 5804: { // glProgramUniform3d
+case 5805: { // glProgramUniform3d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
@@ -6424,14 +6432,14 @@ case 5804: { // glProgramUniform3d
GLdouble *v2 = (GLdouble *) bp; bp += 8;
weglProgramUniform3d(*program,*location,*v0,*v1,*v2);
}; break;
-case 5805: { // glProgramUniform3dv
+case 5806: { // glProgramUniform3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*24;
weglProgramUniform3dv(*program,*location,*valueLen,value);
}; break;
-case 5806: { // glProgramUniform3ui
+case 5807: { // glProgramUniform3ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
@@ -6439,14 +6447,14 @@ case 5806: { // glProgramUniform3ui
GLuint *v2 = (GLuint *) bp; bp += 4;
weglProgramUniform3ui(*program,*location,*v0,*v1,*v2);
}; break;
-case 5807: { // glProgramUniform3uiv
+case 5808: { // glProgramUniform3uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*12;
weglProgramUniform3uiv(*program,*location,*valueLen,value);
}; break;
-case 5808: { // glProgramUniform4i
+case 5809: { // glProgramUniform4i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
@@ -6455,14 +6463,14 @@ case 5808: { // glProgramUniform4i
GLint *v3 = (GLint *) bp; bp += 4;
weglProgramUniform4i(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5809: { // glProgramUniform4iv
+case 5810: { // glProgramUniform4iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*16;
weglProgramUniform4iv(*program,*location,*valueLen,value);
}; break;
-case 5810: { // glProgramUniform4f
+case 5811: { // glProgramUniform4f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
@@ -6471,14 +6479,14 @@ case 5810: { // glProgramUniform4f
GLfloat *v3 = (GLfloat *) bp; bp += 4;
weglProgramUniform4f(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5811: { // glProgramUniform4fv
+case 5812: { // glProgramUniform4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglProgramUniform4fv(*program,*location,*valueLen,value);
}; break;
-case 5812: { // glProgramUniform4d
+case 5813: { // glProgramUniform4d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
@@ -6487,14 +6495,14 @@ case 5812: { // glProgramUniform4d
GLdouble *v3 = (GLdouble *) bp; bp += 8;
weglProgramUniform4d(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5813: { // glProgramUniform4dv
+case 5814: { // glProgramUniform4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglProgramUniform4dv(*program,*location,*valueLen,value);
}; break;
-case 5814: { // glProgramUniform4ui
+case 5815: { // glProgramUniform4ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
@@ -6503,14 +6511,14 @@ case 5814: { // glProgramUniform4ui
GLuint *v3 = (GLuint *) bp; bp += 4;
weglProgramUniform4ui(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5815: { // glProgramUniform4uiv
+case 5816: { // glProgramUniform4uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*16;
weglProgramUniform4uiv(*program,*location,*valueLen,value);
}; break;
-case 5816: { // glProgramUniformMatrix2fv
+case 5817: { // glProgramUniformMatrix2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6519,7 +6527,7 @@ case 5816: { // glProgramUniformMatrix2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglProgramUniformMatrix2fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5817: { // glProgramUniformMatrix3fv
+case 5818: { // glProgramUniformMatrix3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6528,7 +6536,7 @@ case 5817: { // glProgramUniformMatrix3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*36;
weglProgramUniformMatrix3fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5818: { // glProgramUniformMatrix4fv
+case 5819: { // glProgramUniformMatrix4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6537,7 +6545,7 @@ case 5818: { // glProgramUniformMatrix4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*64;
weglProgramUniformMatrix4fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5819: { // glProgramUniformMatrix2dv
+case 5820: { // glProgramUniformMatrix2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6546,7 +6554,7 @@ case 5819: { // glProgramUniformMatrix2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglProgramUniformMatrix2dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5820: { // glProgramUniformMatrix3dv
+case 5821: { // glProgramUniformMatrix3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6555,7 +6563,7 @@ case 5820: { // glProgramUniformMatrix3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*72;
weglProgramUniformMatrix3dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5821: { // glProgramUniformMatrix4dv
+case 5822: { // glProgramUniformMatrix4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6564,7 +6572,7 @@ case 5821: { // glProgramUniformMatrix4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*128;
weglProgramUniformMatrix4dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5822: { // glProgramUniformMatrix2x3fv
+case 5823: { // glProgramUniformMatrix2x3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6573,7 +6581,7 @@ case 5822: { // glProgramUniformMatrix2x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglProgramUniformMatrix2x3fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5823: { // glProgramUniformMatrix3x2fv
+case 5824: { // glProgramUniformMatrix3x2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6582,7 +6590,7 @@ case 5823: { // glProgramUniformMatrix3x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglProgramUniformMatrix3x2fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5824: { // glProgramUniformMatrix2x4fv
+case 5825: { // glProgramUniformMatrix2x4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6591,7 +6599,7 @@ case 5824: { // glProgramUniformMatrix2x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglProgramUniformMatrix2x4fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5825: { // glProgramUniformMatrix4x2fv
+case 5826: { // glProgramUniformMatrix4x2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6600,7 +6608,7 @@ case 5825: { // glProgramUniformMatrix4x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglProgramUniformMatrix4x2fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5826: { // glProgramUniformMatrix3x4fv
+case 5827: { // glProgramUniformMatrix3x4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6609,7 +6617,7 @@ case 5826: { // glProgramUniformMatrix3x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglProgramUniformMatrix3x4fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5827: { // glProgramUniformMatrix4x3fv
+case 5828: { // glProgramUniformMatrix4x3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6618,7 +6626,7 @@ case 5827: { // glProgramUniformMatrix4x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglProgramUniformMatrix4x3fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5828: { // glProgramUniformMatrix2x3dv
+case 5829: { // glProgramUniformMatrix2x3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6627,7 +6635,7 @@ case 5828: { // glProgramUniformMatrix2x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglProgramUniformMatrix2x3dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5829: { // glProgramUniformMatrix3x2dv
+case 5830: { // glProgramUniformMatrix3x2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6636,7 +6644,7 @@ case 5829: { // glProgramUniformMatrix3x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglProgramUniformMatrix3x2dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5830: { // glProgramUniformMatrix2x4dv
+case 5831: { // glProgramUniformMatrix2x4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6645,7 +6653,7 @@ case 5830: { // glProgramUniformMatrix2x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglProgramUniformMatrix2x4dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5831: { // glProgramUniformMatrix4x2dv
+case 5832: { // glProgramUniformMatrix4x2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6654,7 +6662,7 @@ case 5831: { // glProgramUniformMatrix4x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglProgramUniformMatrix4x2dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5832: { // glProgramUniformMatrix3x4dv
+case 5833: { // glProgramUniformMatrix3x4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6663,7 +6671,7 @@ case 5832: { // glProgramUniformMatrix3x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglProgramUniformMatrix3x4dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5833: { // glProgramUniformMatrix4x3dv
+case 5834: { // glProgramUniformMatrix4x3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6672,11 +6680,11 @@ case 5833: { // glProgramUniformMatrix4x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglProgramUniformMatrix4x3dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5834: { // glValidateProgramPipeline
+case 5835: { // glValidateProgramPipeline
GLuint *pipeline = (GLuint *) bp; bp += 4;
weglValidateProgramPipeline(*pipeline);
}; break;
-case 5835: { // glGetProgramPipelineInfoLog
+case 5836: { // glGetProgramPipelineInfoLog
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -6690,31 +6698,31 @@ case 5835: { // glGetProgramPipelineInfoLog
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5836: { // glVertexAttribL1dv
+case 5837: { // glVertexAttribL1dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL1dv(*index,v);
}; break;
-case 5837: { // glVertexAttribL2dv
+case 5838: { // glVertexAttribL2dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL2dv(*index,v);
}; break;
-case 5838: { // glVertexAttribL3dv
+case 5839: { // glVertexAttribL3dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL3dv(*index,v);
}; break;
-case 5839: { // glVertexAttribL4dv
+case 5840: { // glVertexAttribL4dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL4dv(*index,v);
}; break;
-case 5840: { // glVertexAttribLPointer
+case 5841: { // glVertexAttribLPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6722,7 +6730,7 @@ case 5840: { // glVertexAttribLPointer
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglVertexAttribLPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5841: { // glVertexAttribLPointer
+case 5842: { // glVertexAttribLPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6730,7 +6738,7 @@ case 5841: { // glVertexAttribLPointer
GLvoid *pointer = (GLvoid *) bins[0];
weglVertexAttribLPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5842: { // glGetVertexAttribLdv
+case 5843: { // glGetVertexAttribLdv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -6746,13 +6754,13 @@ case 5842: { // glGetVertexAttribLdv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5843: { // glViewportArrayv
+case 5844: { // glViewportArrayv
GLuint *first = (GLuint *) bp; bp += 4;
int *vLen = (int *) bp; bp += 4;
GLfloat * v = (GLfloat *) bp; bp += *vLen*16;
weglViewportArrayv(*first,*vLen,v);
}; break;
-case 5844: { // glViewportIndexedf
+case 5845: { // glViewportIndexedf
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *x = (GLfloat *) bp; bp += 4;
GLfloat *y = (GLfloat *) bp; bp += 4;
@@ -6760,18 +6768,18 @@ case 5844: { // glViewportIndexedf
GLfloat *h = (GLfloat *) bp; bp += 4;
weglViewportIndexedf(*index,*x,*y,*w,*h);
}; break;
-case 5845: { // glViewportIndexedfv
+case 5846: { // glViewportIndexedfv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * v = (GLfloat *) bp; bp += 16;
weglViewportIndexedfv(*index,v);
}; break;
-case 5846: { // glScissorArrayv
+case 5847: { // glScissorArrayv
GLuint *first = (GLuint *) bp; bp += 4;
int *vLen = (int *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += *vLen*16;
weglScissorArrayv(*first,*vLen,v);
}; break;
-case 5847: { // glScissorIndexed
+case 5848: { // glScissorIndexed
GLuint *index = (GLuint *) bp; bp += 4;
GLint *left = (GLint *) bp; bp += 4;
GLint *bottom = (GLint *) bp; bp += 4;
@@ -6779,26 +6787,26 @@ case 5847: { // glScissorIndexed
GLsizei *height = (GLsizei *) bp; bp += 4;
weglScissorIndexed(*index,*left,*bottom,*width,*height);
}; break;
-case 5848: { // glScissorIndexedv
+case 5849: { // glScissorIndexedv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglScissorIndexedv(*index,v);
}; break;
-case 5849: { // glDepthRangeArrayv
+case 5850: { // glDepthRangeArrayv
GLuint *first = (GLuint *) bp; bp += 4;
bp += 4;
int *vLen = (int *) bp; bp += 8;
GLclampd * v = (GLclampd *) bp; bp += *vLen*16;
weglDepthRangeArrayv(*first,*vLen,v);
}; break;
-case 5850: { // glDepthRangeIndexed
+case 5851: { // glDepthRangeIndexed
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLclampd *n = (GLclampd *) bp; bp += 8;
GLclampd *f = (GLclampd *) bp; bp += 8;
weglDepthRangeIndexed(*index,*n,*f);
}; break;
-case 5851: { // glGetFloati_v
+case 5852: { // glGetFloati_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat data[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -6827,7 +6835,7 @@ case 5851: { // glGetFloati_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5852: { // glGetDoublei_v
+case 5853: { // glGetDoublei_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble data[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -6855,16 +6863,16 @@ case 5852: { // glGetDoublei_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5853: { // glDebugMessageControlARB
+case 5854: { // glDebugMessageControlARB
GLenum *source = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLenum *severity = (GLenum *) bp; bp += 4;
int * idsLen = (int *) bp; bp += 4;
- GLuint * ids = (GLuint *) bp; bp += (8-((*idsLen*4+0)%8))%8;
+ GLuint * ids = (GLuint *) bp; bp += *idsLen*4 + (8-((*idsLen*4+0)%8))%8;
GLboolean *enabled = (GLboolean *) bp; bp += 1;
weglDebugMessageControlARB(*source,*type,*severity,*idsLen,ids,*enabled);
}; break;
-case 5854: { // glDebugMessageInsertARB
+case 5855: { // glDebugMessageInsertARB
GLenum *source = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
@@ -6873,7 +6881,7 @@ case 5854: { // glDebugMessageInsertARB
int bufLen[1] = {(int)strlen((char *)buf)}; bp += bufLen[0]+1+((8-((1+bufLen[0]+0)%8))%8);
weglDebugMessageInsertARB(*source,*type,*id,*severity,*bufLen,buf);
}; break;
-case 5855: { // glGetDebugMessageLogARB
+case 5856: { // glGetDebugMessageLogARB
GLuint *count = (GLuint *) bp; bp += 4;
GLsizei *bufsize = (GLsizei *) bp; bp += 4;
GLenum *sources;
@@ -6920,7 +6928,7 @@ case 5855: { // glGetDebugMessageLogARB
driver_free(types);
driver_free(sources);
}; break;
-case 5856: { // glGetGraphicsResetStatusARB
+case 5857: { // glGetGraphicsResetStatusARB
GLenum result = weglGetGraphicsResetStatusARB();
int AP = 0; ErlDrvTermData rt[6];
rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
@@ -6928,7 +6936,7 @@ case 5856: { // glGetGraphicsResetStatusARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5857: { // glDrawArraysInstancedBaseInstance
+case 5858: { // glDrawArraysInstancedBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLint *first = (GLint *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
@@ -6936,7 +6944,7 @@ case 5857: { // glDrawArraysInstancedBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawArraysInstancedBaseInstance(*mode,*first,*count,*primcount,*baseinstance);
}; break;
-case 5858: { // glDrawElementsInstancedBaseInstance
+case 5859: { // glDrawElementsInstancedBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6945,7 +6953,7 @@ case 5858: { // glDrawElementsInstancedBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseInstance(*mode,*count,*type,indices,*primcount,*baseinstance);
}; break;
-case 5859: { // glDrawElementsInstancedBaseInstance
+case 5860: { // glDrawElementsInstancedBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6954,7 +6962,7 @@ case 5859: { // glDrawElementsInstancedBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseInstance(*mode,*count,*type,indices,*primcount,*baseinstance);
}; break;
-case 5860: { // glDrawElementsInstancedBaseVertexBaseInstance
+case 5861: { // glDrawElementsInstancedBaseVertexBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6964,7 +6972,7 @@ case 5860: { // glDrawElementsInstancedBaseVertexBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertexBaseInstance(*mode,*count,*type,indices,*primcount,*basevertex,*baseinstance);
}; break;
-case 5861: { // glDrawElementsInstancedBaseVertexBaseInstance
+case 5862: { // glDrawElementsInstancedBaseVertexBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6974,20 +6982,20 @@ case 5861: { // glDrawElementsInstancedBaseVertexBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertexBaseInstance(*mode,*count,*type,indices,*primcount,*basevertex,*baseinstance);
}; break;
-case 5862: { // glDrawTransformFeedbackInstanced
+case 5863: { // glDrawTransformFeedbackInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawTransformFeedbackInstanced(*mode,*id,*primcount);
}; break;
-case 5863: { // glDrawTransformFeedbackStreamInstanced
+case 5864: { // glDrawTransformFeedbackStreamInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
GLuint *stream = (GLuint *) bp; bp += 4;
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawTransformFeedbackStreamInstanced(*mode,*id,*stream,*primcount);
}; break;
-case 5864: { // glGetInternalformativ
+case 5865: { // glGetInternalformativ
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -7006,7 +7014,7 @@ case 5864: { // glGetInternalformativ
driver_free(rt);
driver_free(params);
}; break;
-case 5865: { // glBindImageTexture
+case 5866: { // glBindImageTexture
GLuint *unit = (GLuint *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
GLint *level = (GLint *) bp; bp += 4;
@@ -7017,18 +7025,18 @@ case 5865: { // glBindImageTexture
GLenum *format = (GLenum *) bp; bp += 4;
weglBindImageTexture(*unit,*texture,*level,*layered,*layer,*access,*format);
}; break;
-case 5866: { // glMemoryBarrier
+case 5867: { // glMemoryBarrier
GLbitfield *barriers = (GLbitfield *) bp; bp += 4;
weglMemoryBarrier(*barriers);
}; break;
-case 5867: { // glTexStorage1D
+case 5868: { // glTexStorage1D
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *levels = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLsizei *width = (GLsizei *) bp; bp += 4;
weglTexStorage1D(*target,*levels,*internalformat,*width);
}; break;
-case 5868: { // glTexStorage2D
+case 5869: { // glTexStorage2D
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *levels = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
@@ -7036,7 +7044,7 @@ case 5868: { // glTexStorage2D
GLsizei *height = (GLsizei *) bp; bp += 4;
weglTexStorage2D(*target,*levels,*internalformat,*width,*height);
}; break;
-case 5869: { // glTexStorage3D
+case 5870: { // glTexStorage3D
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *levels = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
@@ -7045,12 +7053,12 @@ case 5869: { // glTexStorage3D
GLsizei *depth = (GLsizei *) bp; bp += 4;
weglTexStorage3D(*target,*levels,*internalformat,*width,*height,*depth);
}; break;
-case 5870: { // glDepthBoundsEXT
+case 5871: { // glDepthBoundsEXT
GLclampd *zmin = (GLclampd *) bp; bp += 8;
GLclampd *zmax = (GLclampd *) bp; bp += 8;
weglDepthBoundsEXT(*zmin,*zmax);
}; break;
-case 5871: { // glStencilClearTagEXT
+case 5872: { // glStencilClearTagEXT
GLsizei *stencilTagBits = (GLsizei *) bp; bp += 4;
GLuint *stencilClearTag = (GLuint *) bp; bp += 4;
weglStencilClearTagEXT(*stencilTagBits,*stencilClearTag);
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index 4affe2ba53..01787c8a64 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2015. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -306,6 +306,7 @@ void initEventTable()
{wxEVT_ACTIVATE_APP, 232, "activate_app"},
{wxEVT_HIBERNATE, 232, "hibernate"},
{wxEVT_MOUSE_CAPTURE_LOST, 235, "mouse_capture_lost"},
+ {wxEVT_DROP_FILES, 238, "drop_files"},
{-1, 0, }
};
for(int i=0; event_types[i].ev_type != -1; i++) {
@@ -881,6 +882,18 @@ case 235: {// wxMouseCaptureLostEvent
rt.addTupleCount(2);
break;
}
+case 238: {// wxDropFilesEvent
+ wxDropFilesEvent * ev = (wxDropFilesEvent *) event;
+ evClass = (char*)"wxDropFilesEvent";
+ rt.addAtom((char*)"wxDropFiles");
+ rt.addAtom(Etype->eName);
+ rt.addInt(ev->m_noFiles);
+ rt.add(ev->m_pos);
+ wxArrayString tmpArrayStr(ev->m_noFiles, ev->m_files);
+ rt.add(tmpArrayStr);
+ rt.addTupleCount(5);
+ break;
+}
}
rt.addTupleCount(5);
@@ -897,7 +910,7 @@ case 235: {// wxMouseCaptureLostEvent
} else {
send_res = rt.send();
if(cb->skip) event->Skip();
- if(app->recurse_level < 1) {
+ if(app->recurse_level < 1 && Etype->cID != 168) {
app->recurse_level++;
app->dispatch_cmds();
app->recurse_level--;
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index 4243d8a35a..5425e9f3cb 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -315,6 +315,15 @@ case wxWindow_Disable: { // wxWindow::Disable
rt.addBool(Result);
break;
}
+#if wxCHECK_VERSION(2,8,10)
+case wxWindow_DragAcceptFiles: { // wxWindow::DragAcceptFiles
+ wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
+ bool * accept = (bool *) bp; bp += 4;
+ if(!This) throw wxe_badarg(0);
+ This->DragAcceptFiles(*accept);
+ break;
+}
+#endif
case wxWindow_Enable: { // wxWindow::Enable
bool enable=true;
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
@@ -1707,6 +1716,15 @@ case wxWindow_SetDoubleBuffered: { // wxWindow::SetDoubleBuffered
break;
}
#endif
+#if wxCHECK_VERSION(2,9,5)
+case wxWindow_GetContentScaleFactor: { // wxWindow::GetContentScaleFactor
+ wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ double Result = This->GetContentScaleFactor();
+ rt.addFloat(Result);
+ break;
+}
+#endif
case wxTopLevelWindow_GetIcon: { // wxTopLevelWindow::GetIcon
wxTopLevelWindow *This = (wxTopLevelWindow *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
@@ -32049,6 +32067,28 @@ case wxDCOverlay_Clear: { // wxDCOverlay::Clear
This->Clear();
break;
}
+case wxDropFilesEvent_GetPosition: { // wxDropFilesEvent::GetPosition
+ wxDropFilesEvent *This = (wxDropFilesEvent *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxPoint Result = This->GetPosition();
+ rt.add(Result);
+ break;
+}
+case wxDropFilesEvent_GetNumberOfFiles: { // wxDropFilesEvent::GetNumberOfFiles
+ wxDropFilesEvent *This = (wxDropFilesEvent *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ int Result = This->GetNumberOfFiles();
+ rt.addInt(Result);
+ break;
+}
+case wxDropFilesEvent_GetFiles: { // wxDropFilesEvent::GetFiles
+ wxDropFilesEvent *This = (wxDropFilesEvent *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxString * Result = (wxString*)This->GetFiles();
+ wxArrayString tmpArrayStr(This->m_noFiles, Result);
+ rt.add(tmpArrayStr);
+ break;
+}
default: {
wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false); error.addAtom("_wxe_error_");
error.addInt((int) op);
diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h
index 82b39b49cd..f44fa57053 100644
--- a/lib/wx/c_src/gen/wxe_macros.h
+++ b/lib/wx/c_src/gen/wxe_macros.h
@@ -94,3332 +94,3337 @@
#define wxWindow_Destroy 123
#define wxWindow_DestroyChildren 124
#define wxWindow_Disable 125
-#define wxWindow_Enable 126
-#define wxWindow_FindFocus 127
-#define wxWindow_FindWindow_1_0 128
-#define wxWindow_FindWindow_1_1 129
-#define wxWindow_FindWindowById 130
-#define wxWindow_FindWindowByName 131
-#define wxWindow_FindWindowByLabel 132
-#define wxWindow_Fit 133
-#define wxWindow_FitInside 134
-#define wxWindow_Freeze 135
-#define wxWindow_GetAcceleratorTable 136
-#define wxWindow_GetBackgroundColour 137
-#define wxWindow_GetBackgroundStyle 138
-#define wxWindow_GetBestSize 139
-#define wxWindow_GetCaret 141
-#define wxWindow_GetCapture 142
-#define wxWindow_GetCharHeight 143
-#define wxWindow_GetCharWidth 144
-#define wxWindow_GetChildren 145
-#define wxWindow_GetClientSize 148
-#define wxWindow_GetContainingSizer 149
-#define wxWindow_GetCursor 150
-#define wxWindow_GetDropTarget 151
-#define wxWindow_GetEventHandler 152
-#define wxWindow_GetExtraStyle 153
-#define wxWindow_GetFont 154
-#define wxWindow_GetForegroundColour 155
-#define wxWindow_GetGrandParent 156
-#define wxWindow_GetHandle 157
-#define wxWindow_GetHelpText 158
-#define wxWindow_GetId 159
-#define wxWindow_GetLabel 160
-#define wxWindow_GetMaxSize 161
-#define wxWindow_GetMinSize 162
-#define wxWindow_GetName 163
-#define wxWindow_GetParent 164
-#define wxWindow_GetPosition 166
-#define wxWindow_GetRect 167
-#define wxWindow_GetScreenPosition 169
-#define wxWindow_GetScreenRect 170
-#define wxWindow_GetScrollPos 171
-#define wxWindow_GetScrollRange 172
-#define wxWindow_GetScrollThumb 173
-#define wxWindow_GetSize 175
-#define wxWindow_GetSizer 176
-#define wxWindow_GetTextExtent 177
-#define wxWindow_GetToolTip 178
-#define wxWindow_GetUpdateRegion 179
-#define wxWindow_GetVirtualSize 181
-#define wxWindow_GetWindowStyleFlag 183
-#define wxWindow_GetWindowVariant 184
-#define wxWindow_HasCapture 185
-#define wxWindow_HasScrollbar 186
-#define wxWindow_HasTransparentBackground 187
-#define wxWindow_Hide 188
-#define wxWindow_InheritAttributes 189
-#define wxWindow_InitDialog 190
-#define wxWindow_InvalidateBestSize 191
-#define wxWindow_IsEnabled 192
-#define wxWindow_IsExposed_2 193
-#define wxWindow_IsExposed_4 194
-#define wxWindow_IsExposed_1_0 195
-#define wxWindow_IsExposed_1_1 196
-#define wxWindow_IsRetained 197
-#define wxWindow_IsShown 198
-#define wxWindow_IsTopLevel 199
-#define wxWindow_Layout 200
-#define wxWindow_LineDown 201
-#define wxWindow_LineUp 202
-#define wxWindow_Lower 203
-#define wxWindow_MakeModal 204
-#define wxWindow_Move_3 205
-#define wxWindow_Move_2 206
-#define wxWindow_MoveAfterInTabOrder 207
-#define wxWindow_MoveBeforeInTabOrder 208
-#define wxWindow_Navigate 209
-#define wxWindow_PageDown 210
-#define wxWindow_PageUp 211
-#define wxWindow_PopEventHandler 212
-#define wxWindow_PopupMenu_2 213
-#define wxWindow_PopupMenu_3 214
-#define wxWindow_Raise 215
-#define wxWindow_Refresh 216
-#define wxWindow_RefreshRect 217
-#define wxWindow_ReleaseMouse 218
-#define wxWindow_RemoveChild 219
-#define wxWindow_Reparent 220
-#define wxWindow_ScreenToClient_2 221
-#define wxWindow_ScreenToClient_1 222
-#define wxWindow_ScrollLines 224
-#define wxWindow_ScrollPages 226
-#define wxWindow_ScrollWindow 227
-#define wxWindow_SetAcceleratorTable 228
-#define wxWindow_SetAutoLayout 229
-#define wxWindow_SetBackgroundColour 230
-#define wxWindow_SetBackgroundStyle 231
-#define wxWindow_SetCaret 232
-#define wxWindow_SetClientSize_2 233
-#define wxWindow_SetClientSize_1_0 234
-#define wxWindow_SetClientSize_1_1 235
-#define wxWindow_SetContainingSizer 236
-#define wxWindow_SetCursor 237
-#define wxWindow_SetMaxSize 238
-#define wxWindow_SetMinSize 239
-#define wxWindow_SetOwnBackgroundColour 240
-#define wxWindow_SetOwnFont 241
-#define wxWindow_SetOwnForegroundColour 242
-#define wxWindow_SetDropTarget 243
-#define wxWindow_SetExtraStyle 244
-#define wxWindow_SetFocus 245
-#define wxWindow_SetFocusFromKbd 246
-#define wxWindow_SetFont 247
-#define wxWindow_SetForegroundColour 248
-#define wxWindow_SetHelpText 249
-#define wxWindow_SetId 250
-#define wxWindow_SetLabel 252
-#define wxWindow_SetName 253
-#define wxWindow_SetPalette 254
-#define wxWindow_SetScrollbar 255
-#define wxWindow_SetScrollPos 256
-#define wxWindow_SetSize_5 257
-#define wxWindow_SetSize_2_0 258
-#define wxWindow_SetSize_1 259
-#define wxWindow_SetSize_2_1 260
-#define wxWindow_SetSizeHints_3 261
-#define wxWindow_SetSizeHints_2 262
-#define wxWindow_SetSizer 263
-#define wxWindow_SetSizerAndFit 264
-#define wxWindow_SetThemeEnabled 265
-#define wxWindow_SetToolTip_1_0 266
-#define wxWindow_SetToolTip_1_1 267
-#define wxWindow_SetVirtualSize_1 268
-#define wxWindow_SetVirtualSize_2 269
-#define wxWindow_SetVirtualSizeHints_3 270
-#define wxWindow_SetVirtualSizeHints_2 271
-#define wxWindow_SetWindowStyle 272
-#define wxWindow_SetWindowStyleFlag 273
-#define wxWindow_SetWindowVariant 274
-#define wxWindow_ShouldInheritColours 275
-#define wxWindow_Show 276
-#define wxWindow_Thaw 277
-#define wxWindow_TransferDataFromWindow 278
-#define wxWindow_TransferDataToWindow 279
-#define wxWindow_Update 280
-#define wxWindow_UpdateWindowUI 281
-#define wxWindow_Validate 282
-#define wxWindow_WarpPointer 283
-#define wxWindow_SetTransparent 284
-#define wxWindow_CanSetTransparent 285
-#define wxWindow_IsDoubleBuffered 286
-#define wxWindow_SetDoubleBuffered 287
-#define wxTopLevelWindow_GetIcon 288
-#define wxTopLevelWindow_GetIcons 289
-#define wxTopLevelWindow_GetTitle 290
-#define wxTopLevelWindow_IsActive 291
-#define wxTopLevelWindow_Iconize 292
-#define wxTopLevelWindow_IsFullScreen 293
-#define wxTopLevelWindow_IsIconized 294
-#define wxTopLevelWindow_IsMaximized 295
-#define wxTopLevelWindow_Maximize 296
-#define wxTopLevelWindow_RequestUserAttention 297
-#define wxTopLevelWindow_SetIcon 298
-#define wxTopLevelWindow_SetIcons 299
-#define wxTopLevelWindow_CenterOnScreen 300
-#define wxTopLevelWindow_CentreOnScreen 301
-#define wxTopLevelWindow_SetShape 303
-#define wxTopLevelWindow_SetTitle 304
-#define wxTopLevelWindow_ShowFullScreen 305
-#define wxFrame_new_4 307
-#define wxFrame_new_0 308
-#define wxFrame_destruct 310
-#define wxFrame_Create 311
-#define wxFrame_CreateStatusBar 312
-#define wxFrame_CreateToolBar 313
-#define wxFrame_GetClientAreaOrigin 314
-#define wxFrame_GetMenuBar 315
-#define wxFrame_GetStatusBar 316
-#define wxFrame_GetStatusBarPane 317
-#define wxFrame_GetToolBar 318
-#define wxFrame_ProcessCommand 319
-#define wxFrame_SendSizeEvent 320
-#define wxFrame_SetMenuBar 321
-#define wxFrame_SetStatusBar 322
-#define wxFrame_SetStatusBarPane 323
-#define wxFrame_SetStatusText 324
-#define wxFrame_SetStatusWidths 325
-#define wxFrame_SetToolBar 326
-#define wxMiniFrame_new_0 327
-#define wxMiniFrame_new_4 328
-#define wxMiniFrame_Create 329
-#define wxMiniFrame_destroy 330
-#define wxSplashScreen_new_0 331
-#define wxSplashScreen_new_6 332
-#define wxSplashScreen_destruct 333
-#define wxSplashScreen_GetSplashStyle 334
-#define wxSplashScreen_GetTimeout 335
-#define wxPanel_new_0 336
-#define wxPanel_new_6 337
-#define wxPanel_new_2 338
-#define wxPanel_destruct 339
-#define wxPanel_InitDialog 340
-#define wxPanel_SetFocusIgnoringChildren 341
-#define wxScrolledWindow_new_0 342
-#define wxScrolledWindow_new_2 343
-#define wxScrolledWindow_destruct 344
-#define wxScrolledWindow_CalcScrolledPosition_4 345
-#define wxScrolledWindow_CalcScrolledPosition_1 346
-#define wxScrolledWindow_CalcUnscrolledPosition_4 347
-#define wxScrolledWindow_CalcUnscrolledPosition_1 348
-#define wxScrolledWindow_EnableScrolling 349
-#define wxScrolledWindow_GetScrollPixelsPerUnit 350
-#define wxScrolledWindow_GetViewStart 351
-#define wxScrolledWindow_DoPrepareDC 352
-#define wxScrolledWindow_PrepareDC 353
-#define wxScrolledWindow_Scroll 354
-#define wxScrolledWindow_SetScrollbars 355
-#define wxScrolledWindow_SetScrollRate 356
-#define wxScrolledWindow_SetTargetWindow 357
-#define wxSashWindow_new_0 358
-#define wxSashWindow_new_2 359
-#define wxSashWindow_destruct 360
-#define wxSashWindow_GetSashVisible 361
-#define wxSashWindow_GetMaximumSizeX 362
-#define wxSashWindow_GetMaximumSizeY 363
-#define wxSashWindow_GetMinimumSizeX 364
-#define wxSashWindow_GetMinimumSizeY 365
-#define wxSashWindow_SetMaximumSizeX 366
-#define wxSashWindow_SetMaximumSizeY 367
-#define wxSashWindow_SetMinimumSizeX 368
-#define wxSashWindow_SetMinimumSizeY 369
-#define wxSashWindow_SetSashVisible 370
-#define wxSashLayoutWindow_new_0 371
-#define wxSashLayoutWindow_new_2 372
-#define wxSashLayoutWindow_Create 373
-#define wxSashLayoutWindow_GetAlignment 374
-#define wxSashLayoutWindow_GetOrientation 375
-#define wxSashLayoutWindow_SetAlignment 376
-#define wxSashLayoutWindow_SetDefaultSize 377
-#define wxSashLayoutWindow_SetOrientation 378
-#define wxSashLayoutWindow_destroy 379
-#define wxGrid_new_0 380
-#define wxGrid_new_3 381
-#define wxGrid_new_4 382
-#define wxGrid_destruct 383
-#define wxGrid_AppendCols 384
-#define wxGrid_AppendRows 385
-#define wxGrid_AutoSize 386
-#define wxGrid_AutoSizeColumn 387
-#define wxGrid_AutoSizeColumns 388
-#define wxGrid_AutoSizeRow 389
-#define wxGrid_AutoSizeRows 390
-#define wxGrid_BeginBatch 391
-#define wxGrid_BlockToDeviceRect 392
-#define wxGrid_CanDragColSize 393
-#define wxGrid_CanDragRowSize 394
-#define wxGrid_CanDragGridSize 395
-#define wxGrid_CanEnableCellControl 396
-#define wxGrid_CellToRect_2 397
-#define wxGrid_CellToRect_1 398
-#define wxGrid_ClearGrid 399
-#define wxGrid_ClearSelection 400
-#define wxGrid_CreateGrid 401
-#define wxGrid_DeleteCols 402
-#define wxGrid_DeleteRows 403
-#define wxGrid_DisableCellEditControl 404
-#define wxGrid_DisableDragColSize 405
-#define wxGrid_DisableDragGridSize 406
-#define wxGrid_DisableDragRowSize 407
-#define wxGrid_EnableCellEditControl 408
-#define wxGrid_EnableDragColSize 409
-#define wxGrid_EnableDragGridSize 410
-#define wxGrid_EnableDragRowSize 411
-#define wxGrid_EnableEditing 412
-#define wxGrid_EnableGridLines 413
-#define wxGrid_EndBatch 414
-#define wxGrid_Fit 415
-#define wxGrid_ForceRefresh 416
-#define wxGrid_GetBatchCount 417
-#define wxGrid_GetCellAlignment 418
-#define wxGrid_GetCellBackgroundColour 419
-#define wxGrid_GetCellEditor 420
-#define wxGrid_GetCellFont 421
-#define wxGrid_GetCellRenderer 422
-#define wxGrid_GetCellTextColour 423
-#define wxGrid_GetCellValue_2 424
-#define wxGrid_GetCellValue_1 425
-#define wxGrid_GetColLabelAlignment 426
-#define wxGrid_GetColLabelSize 427
-#define wxGrid_GetColLabelValue 428
-#define wxGrid_GetColMinimalAcceptableWidth 429
-#define wxGrid_GetDefaultCellAlignment 430
-#define wxGrid_GetDefaultCellBackgroundColour 431
-#define wxGrid_GetDefaultCellFont 432
-#define wxGrid_GetDefaultCellTextColour 433
-#define wxGrid_GetDefaultColLabelSize 434
-#define wxGrid_GetDefaultColSize 435
-#define wxGrid_GetDefaultEditor 436
-#define wxGrid_GetDefaultEditorForCell_2 437
-#define wxGrid_GetDefaultEditorForCell_1 438
-#define wxGrid_GetDefaultEditorForType 439
-#define wxGrid_GetDefaultRenderer 440
-#define wxGrid_GetDefaultRendererForCell 441
-#define wxGrid_GetDefaultRendererForType 442
-#define wxGrid_GetDefaultRowLabelSize 443
-#define wxGrid_GetDefaultRowSize 444
-#define wxGrid_GetGridCursorCol 445
-#define wxGrid_GetGridCursorRow 446
-#define wxGrid_GetGridLineColour 447
-#define wxGrid_GridLinesEnabled 448
-#define wxGrid_GetLabelBackgroundColour 449
-#define wxGrid_GetLabelFont 450
-#define wxGrid_GetLabelTextColour 451
-#define wxGrid_GetNumberCols 452
-#define wxGrid_GetNumberRows 453
-#define wxGrid_GetOrCreateCellAttr 454
-#define wxGrid_GetRowMinimalAcceptableHeight 455
-#define wxGrid_GetRowLabelAlignment 456
-#define wxGrid_GetRowLabelSize 457
-#define wxGrid_GetRowLabelValue 458
-#define wxGrid_GetRowSize 459
-#define wxGrid_GetScrollLineX 460
-#define wxGrid_GetScrollLineY 461
-#define wxGrid_GetSelectedCells 462
-#define wxGrid_GetSelectedCols 463
-#define wxGrid_GetSelectedRows 464
-#define wxGrid_GetSelectionBackground 465
-#define wxGrid_GetSelectionBlockTopLeft 466
-#define wxGrid_GetSelectionBlockBottomRight 467
-#define wxGrid_GetSelectionForeground 468
-#define wxGrid_GetViewWidth 469
-#define wxGrid_GetGridWindow 470
-#define wxGrid_GetGridRowLabelWindow 471
-#define wxGrid_GetGridColLabelWindow 472
-#define wxGrid_GetGridCornerLabelWindow 473
-#define wxGrid_HideCellEditControl 474
-#define wxGrid_InsertCols 475
-#define wxGrid_InsertRows 476
-#define wxGrid_IsCellEditControlEnabled 477
-#define wxGrid_IsCurrentCellReadOnly 478
-#define wxGrid_IsEditable 479
-#define wxGrid_IsInSelection_2 480
-#define wxGrid_IsInSelection_1 481
-#define wxGrid_IsReadOnly 482
-#define wxGrid_IsSelection 483
-#define wxGrid_IsVisible_3 484
-#define wxGrid_IsVisible_2 485
-#define wxGrid_MakeCellVisible_2 486
-#define wxGrid_MakeCellVisible_1 487
-#define wxGrid_MoveCursorDown 488
-#define wxGrid_MoveCursorLeft 489
-#define wxGrid_MoveCursorRight 490
-#define wxGrid_MoveCursorUp 491
-#define wxGrid_MoveCursorDownBlock 492
-#define wxGrid_MoveCursorLeftBlock 493
-#define wxGrid_MoveCursorRightBlock 494
-#define wxGrid_MoveCursorUpBlock 495
-#define wxGrid_MovePageDown 496
-#define wxGrid_MovePageUp 497
-#define wxGrid_RegisterDataType 498
-#define wxGrid_SaveEditControlValue 499
-#define wxGrid_SelectAll 500
-#define wxGrid_SelectBlock_5 501
-#define wxGrid_SelectBlock_3 502
-#define wxGrid_SelectCol 503
-#define wxGrid_SelectRow 504
-#define wxGrid_SetCellAlignment_4 505
-#define wxGrid_SetCellAlignment_3 506
-#define wxGrid_SetCellAlignment_1 507
-#define wxGrid_SetCellBackgroundColour_3_0 508
-#define wxGrid_SetCellBackgroundColour_1 509
-#define wxGrid_SetCellBackgroundColour_3_1 510
-#define wxGrid_SetCellEditor 511
-#define wxGrid_SetCellFont 512
-#define wxGrid_SetCellRenderer 513
-#define wxGrid_SetCellTextColour_3_0 514
-#define wxGrid_SetCellTextColour_3_1 515
-#define wxGrid_SetCellTextColour_1 516
-#define wxGrid_SetCellValue_3_0 517
-#define wxGrid_SetCellValue_2 518
-#define wxGrid_SetCellValue_3_1 519
-#define wxGrid_SetColAttr 520
-#define wxGrid_SetColFormatBool 521
-#define wxGrid_SetColFormatNumber 522
-#define wxGrid_SetColFormatFloat 523
-#define wxGrid_SetColFormatCustom 524
-#define wxGrid_SetColLabelAlignment 525
-#define wxGrid_SetColLabelSize 526
-#define wxGrid_SetColLabelValue 527
-#define wxGrid_SetColMinimalWidth 528
-#define wxGrid_SetColMinimalAcceptableWidth 529
-#define wxGrid_SetColSize 530
-#define wxGrid_SetDefaultCellAlignment 531
-#define wxGrid_SetDefaultCellBackgroundColour 532
-#define wxGrid_SetDefaultCellFont 533
-#define wxGrid_SetDefaultCellTextColour 534
-#define wxGrid_SetDefaultEditor 535
-#define wxGrid_SetDefaultRenderer 536
-#define wxGrid_SetDefaultColSize 537
-#define wxGrid_SetDefaultRowSize 538
-#define wxGrid_SetGridCursor 539
-#define wxGrid_SetGridLineColour 540
-#define wxGrid_SetLabelBackgroundColour 541
-#define wxGrid_SetLabelFont 542
-#define wxGrid_SetLabelTextColour 543
-#define wxGrid_SetMargins 544
-#define wxGrid_SetReadOnly 545
-#define wxGrid_SetRowAttr 546
-#define wxGrid_SetRowLabelAlignment 547
-#define wxGrid_SetRowLabelSize 548
-#define wxGrid_SetRowLabelValue 549
-#define wxGrid_SetRowMinimalHeight 550
-#define wxGrid_SetRowMinimalAcceptableHeight 551
-#define wxGrid_SetRowSize 552
-#define wxGrid_SetScrollLineX 553
-#define wxGrid_SetScrollLineY 554
-#define wxGrid_SetSelectionBackground 555
-#define wxGrid_SetSelectionForeground 556
-#define wxGrid_SetSelectionMode 557
-#define wxGrid_ShowCellEditControl 558
-#define wxGrid_XToCol 559
-#define wxGrid_XToEdgeOfCol 560
-#define wxGrid_YToEdgeOfRow 561
-#define wxGrid_YToRow 562
-#define wxGridCellRenderer_Draw 563
-#define wxGridCellRenderer_GetBestSize 564
-#define wxGridCellEditor_Create 565
-#define wxGridCellEditor_IsCreated 566
-#define wxGridCellEditor_SetSize 567
-#define wxGridCellEditor_Show 568
-#define wxGridCellEditor_PaintBackground 569
-#define wxGridCellEditor_BeginEdit 570
-#define wxGridCellEditor_EndEdit 571
-#define wxGridCellEditor_Reset 572
-#define wxGridCellEditor_StartingKey 573
-#define wxGridCellEditor_StartingClick 574
-#define wxGridCellEditor_HandleReturn 575
-#define wxGridCellBoolRenderer_new 576
-#define wxGridCellBoolRenderer_destroy 577
-#define wxGridCellBoolEditor_new 578
-#define wxGridCellBoolEditor_IsTrueValue 579
-#define wxGridCellBoolEditor_UseStringValues 580
-#define wxGridCellBoolEditor_destroy 581
-#define wxGridCellFloatRenderer_new 582
-#define wxGridCellFloatRenderer_GetPrecision 583
-#define wxGridCellFloatRenderer_GetWidth 584
-#define wxGridCellFloatRenderer_SetParameters 585
-#define wxGridCellFloatRenderer_SetPrecision 586
-#define wxGridCellFloatRenderer_SetWidth 587
-#define wxGridCellFloatRenderer_destroy 588
-#define wxGridCellFloatEditor_new 589
-#define wxGridCellFloatEditor_SetParameters 590
-#define wxGridCellFloatEditor_destroy 591
-#define wxGridCellStringRenderer_new 592
-#define wxGridCellStringRenderer_destroy 593
-#define wxGridCellTextEditor_new 594
-#define wxGridCellTextEditor_SetParameters 595
-#define wxGridCellTextEditor_destroy 596
-#define wxGridCellChoiceEditor_new 598
-#define wxGridCellChoiceEditor_SetParameters 599
-#define wxGridCellChoiceEditor_destroy 600
-#define wxGridCellNumberRenderer_new 601
-#define wxGridCellNumberRenderer_destroy 602
-#define wxGridCellNumberEditor_new 603
-#define wxGridCellNumberEditor_GetValue 604
-#define wxGridCellNumberEditor_SetParameters 605
-#define wxGridCellNumberEditor_destroy 606
-#define wxGridCellAttr_SetTextColour 607
-#define wxGridCellAttr_SetBackgroundColour 608
-#define wxGridCellAttr_SetFont 609
-#define wxGridCellAttr_SetAlignment 610
-#define wxGridCellAttr_SetReadOnly 611
-#define wxGridCellAttr_SetRenderer 612
-#define wxGridCellAttr_SetEditor 613
-#define wxGridCellAttr_HasTextColour 614
-#define wxGridCellAttr_HasBackgroundColour 615
-#define wxGridCellAttr_HasFont 616
-#define wxGridCellAttr_HasAlignment 617
-#define wxGridCellAttr_HasRenderer 618
-#define wxGridCellAttr_HasEditor 619
-#define wxGridCellAttr_GetTextColour 620
-#define wxGridCellAttr_GetBackgroundColour 621
-#define wxGridCellAttr_GetFont 622
-#define wxGridCellAttr_GetAlignment 623
-#define wxGridCellAttr_GetRenderer 624
-#define wxGridCellAttr_GetEditor 625
-#define wxGridCellAttr_IsReadOnly 626
-#define wxGridCellAttr_SetDefAttr 627
-#define wxDC_Blit 628
-#define wxDC_CalcBoundingBox 629
-#define wxDC_Clear 630
-#define wxDC_ComputeScaleAndOrigin 631
-#define wxDC_CrossHair 632
-#define wxDC_DestroyClippingRegion 633
-#define wxDC_DeviceToLogicalX 634
-#define wxDC_DeviceToLogicalXRel 635
-#define wxDC_DeviceToLogicalY 636
-#define wxDC_DeviceToLogicalYRel 637
-#define wxDC_DrawArc 638
-#define wxDC_DrawBitmap 639
-#define wxDC_DrawCheckMark 640
-#define wxDC_DrawCircle 641
-#define wxDC_DrawEllipse_2 643
-#define wxDC_DrawEllipse_1 644
-#define wxDC_DrawEllipticArc 645
-#define wxDC_DrawIcon 646
-#define wxDC_DrawLabel 647
-#define wxDC_DrawLine 648
-#define wxDC_DrawLines 649
-#define wxDC_DrawPolygon 651
-#define wxDC_DrawPoint 653
-#define wxDC_DrawRectangle_2 655
-#define wxDC_DrawRectangle_1 656
-#define wxDC_DrawRotatedText 657
-#define wxDC_DrawRoundedRectangle_3 659
-#define wxDC_DrawRoundedRectangle_2 660
-#define wxDC_DrawText 661
-#define wxDC_EndDoc 662
-#define wxDC_EndPage 663
-#define wxDC_FloodFill 664
-#define wxDC_GetBackground 665
-#define wxDC_GetBackgroundMode 666
-#define wxDC_GetBrush 667
-#define wxDC_GetCharHeight 668
-#define wxDC_GetCharWidth 669
-#define wxDC_GetClippingBox 670
-#define wxDC_GetFont 672
-#define wxDC_GetLayoutDirection 673
-#define wxDC_GetLogicalFunction 674
-#define wxDC_GetMapMode 675
-#define wxDC_GetMultiLineTextExtent_4 676
-#define wxDC_GetMultiLineTextExtent_1 677
-#define wxDC_GetPartialTextExtents 678
-#define wxDC_GetPen 679
-#define wxDC_GetPixel 680
-#define wxDC_GetPPI 681
-#define wxDC_GetSize 683
-#define wxDC_GetSizeMM 685
-#define wxDC_GetTextBackground 686
-#define wxDC_GetTextExtent_4 687
-#define wxDC_GetTextExtent_1 688
-#define wxDC_GetTextForeground 690
-#define wxDC_GetUserScale 691
-#define wxDC_GradientFillConcentric_3 692
-#define wxDC_GradientFillConcentric_4 693
-#define wxDC_GradientFillLinear 694
-#define wxDC_LogicalToDeviceX 695
-#define wxDC_LogicalToDeviceXRel 696
-#define wxDC_LogicalToDeviceY 697
-#define wxDC_LogicalToDeviceYRel 698
-#define wxDC_MaxX 699
-#define wxDC_MaxY 700
-#define wxDC_MinX 701
-#define wxDC_MinY 702
-#define wxDC_IsOk 703
-#define wxDC_ResetBoundingBox 704
-#define wxDC_SetAxisOrientation 705
-#define wxDC_SetBackground 706
-#define wxDC_SetBackgroundMode 707
-#define wxDC_SetBrush 708
-#define wxDC_SetClippingRegion_2 710
-#define wxDC_SetClippingRegion_1_1 711
-#define wxDC_SetClippingRegion_1_0 712
-#define wxDC_SetDeviceOrigin 713
-#define wxDC_SetFont 714
-#define wxDC_SetLayoutDirection 715
-#define wxDC_SetLogicalFunction 716
-#define wxDC_SetMapMode 717
-#define wxDC_SetPalette 718
-#define wxDC_SetPen 719
-#define wxDC_SetTextBackground 720
-#define wxDC_SetTextForeground 721
-#define wxDC_SetUserScale 722
-#define wxDC_StartDoc 723
-#define wxDC_StartPage 724
-#define wxMirrorDC_new 725
-#define wxMirrorDC_destroy 726
-#define wxScreenDC_new 727
-#define wxScreenDC_destruct 728
-#define wxPostScriptDC_new_0 729
-#define wxPostScriptDC_new_1 730
-#define wxPostScriptDC_destruct 731
-#define wxPostScriptDC_SetResolution 732
-#define wxPostScriptDC_GetResolution 733
-#define wxWindowDC_new_0 734
-#define wxWindowDC_new_1 735
-#define wxWindowDC_destruct 736
-#define wxClientDC_new_0 737
-#define wxClientDC_new_1 738
-#define wxClientDC_destroy 739
-#define wxPaintDC_new_0 740
-#define wxPaintDC_new_1 741
-#define wxPaintDC_destroy 742
-#define wxMemoryDC_new_1_0 744
-#define wxMemoryDC_new_1_1 745
-#define wxMemoryDC_new_0 746
-#define wxMemoryDC_destruct 748
-#define wxMemoryDC_SelectObject 749
-#define wxMemoryDC_SelectObjectAsSource 750
-#define wxBufferedDC_new_0 751
-#define wxBufferedDC_new_2 752
-#define wxBufferedDC_new_3 753
-#define wxBufferedDC_destruct 754
-#define wxBufferedDC_Init_2 755
-#define wxBufferedDC_Init_3 756
-#define wxBufferedPaintDC_new_3 757
-#define wxBufferedPaintDC_new_2 758
-#define wxBufferedPaintDC_destruct 759
-#define wxGraphicsObject_destruct 760
-#define wxGraphicsObject_GetRenderer 761
-#define wxGraphicsObject_IsNull 762
-#define wxGraphicsContext_destruct 763
-#define wxGraphicsContext_Create_1_1 764
-#define wxGraphicsContext_Create_1_0 765
-#define wxGraphicsContext_Create_0 766
-#define wxGraphicsContext_CreatePen 767
-#define wxGraphicsContext_CreateBrush 768
-#define wxGraphicsContext_CreateRadialGradientBrush 769
-#define wxGraphicsContext_CreateLinearGradientBrush 770
-#define wxGraphicsContext_CreateFont 771
-#define wxGraphicsContext_CreateMatrix 772
-#define wxGraphicsContext_CreatePath 773
-#define wxGraphicsContext_Clip_1 774
-#define wxGraphicsContext_Clip_4 775
-#define wxGraphicsContext_ResetClip 776
-#define wxGraphicsContext_DrawBitmap 777
-#define wxGraphicsContext_DrawEllipse 778
-#define wxGraphicsContext_DrawIcon 779
-#define wxGraphicsContext_DrawLines 780
-#define wxGraphicsContext_DrawPath 781
-#define wxGraphicsContext_DrawRectangle 782
-#define wxGraphicsContext_DrawRoundedRectangle 783
-#define wxGraphicsContext_DrawText_3 784
-#define wxGraphicsContext_DrawText_4_0 785
-#define wxGraphicsContext_DrawText_4_1 786
-#define wxGraphicsContext_DrawText_5 787
-#define wxGraphicsContext_FillPath 788
-#define wxGraphicsContext_StrokePath 789
-#define wxGraphicsContext_GetPartialTextExtents 790
-#define wxGraphicsContext_GetTextExtent 791
-#define wxGraphicsContext_Rotate 792
-#define wxGraphicsContext_Scale 793
-#define wxGraphicsContext_Translate 794
-#define wxGraphicsContext_GetTransform 795
-#define wxGraphicsContext_SetTransform 796
-#define wxGraphicsContext_ConcatTransform 797
-#define wxGraphicsContext_SetBrush_1_1 798
-#define wxGraphicsContext_SetBrush_1_0 799
-#define wxGraphicsContext_SetFont_1 800
-#define wxGraphicsContext_SetFont_2 801
-#define wxGraphicsContext_SetPen_1_0 802
-#define wxGraphicsContext_SetPen_1_1 803
-#define wxGraphicsContext_StrokeLine 804
-#define wxGraphicsContext_StrokeLines 805
-#define wxGraphicsMatrix_Concat 807
-#define wxGraphicsMatrix_Get 809
-#define wxGraphicsMatrix_Invert 810
-#define wxGraphicsMatrix_IsEqual 811
-#define wxGraphicsMatrix_IsIdentity 813
-#define wxGraphicsMatrix_Rotate 814
-#define wxGraphicsMatrix_Scale 815
-#define wxGraphicsMatrix_Translate 816
-#define wxGraphicsMatrix_Set 817
-#define wxGraphicsMatrix_TransformPoint 818
-#define wxGraphicsMatrix_TransformDistance 819
-#define wxGraphicsPath_MoveToPoint_2 820
-#define wxGraphicsPath_MoveToPoint_1 821
-#define wxGraphicsPath_AddArc_6 822
-#define wxGraphicsPath_AddArc_5 823
-#define wxGraphicsPath_AddArcToPoint 824
-#define wxGraphicsPath_AddCircle 825
-#define wxGraphicsPath_AddCurveToPoint_6 826
-#define wxGraphicsPath_AddCurveToPoint_3 827
-#define wxGraphicsPath_AddEllipse 828
-#define wxGraphicsPath_AddLineToPoint_2 829
-#define wxGraphicsPath_AddLineToPoint_1 830
-#define wxGraphicsPath_AddPath 831
-#define wxGraphicsPath_AddQuadCurveToPoint 832
-#define wxGraphicsPath_AddRectangle 833
-#define wxGraphicsPath_AddRoundedRectangle 834
-#define wxGraphicsPath_CloseSubpath 835
-#define wxGraphicsPath_Contains_3 836
-#define wxGraphicsPath_Contains_2 837
-#define wxGraphicsPath_GetBox 839
-#define wxGraphicsPath_GetCurrentPoint 841
-#define wxGraphicsPath_Transform 842
-#define wxGraphicsRenderer_GetDefaultRenderer 843
-#define wxGraphicsRenderer_CreateContext_1_1 844
-#define wxGraphicsRenderer_CreateContext_1_0 845
-#define wxGraphicsRenderer_CreatePen 846
-#define wxGraphicsRenderer_CreateBrush 847
-#define wxGraphicsRenderer_CreateLinearGradientBrush 848
-#define wxGraphicsRenderer_CreateRadialGradientBrush 849
-#define wxGraphicsRenderer_CreateFont 850
-#define wxGraphicsRenderer_CreateMatrix 851
-#define wxGraphicsRenderer_CreatePath 852
-#define wxMenuBar_new_1 854
-#define wxMenuBar_new_0 856
-#define wxMenuBar_destruct 858
-#define wxMenuBar_Append 859
-#define wxMenuBar_Check 860
-#define wxMenuBar_Enable_2 861
-#define wxMenuBar_Enable_1 862
-#define wxMenuBar_EnableTop 863
-#define wxMenuBar_FindMenu 864
-#define wxMenuBar_FindMenuItem 865
-#define wxMenuBar_FindItem 866
-#define wxMenuBar_GetHelpString 867
-#define wxMenuBar_GetLabel_1 868
-#define wxMenuBar_GetLabel_0 869
-#define wxMenuBar_GetLabelTop 870
-#define wxMenuBar_GetMenu 871
-#define wxMenuBar_GetMenuCount 872
-#define wxMenuBar_Insert 873
-#define wxMenuBar_IsChecked 874
-#define wxMenuBar_IsEnabled_1 875
-#define wxMenuBar_IsEnabled_0 876
-#define wxMenuBar_Remove 877
-#define wxMenuBar_Replace 878
-#define wxMenuBar_SetHelpString 879
-#define wxMenuBar_SetLabel_2 880
-#define wxMenuBar_SetLabel_1 881
-#define wxMenuBar_SetLabelTop 882
-#define wxControl_GetLabel 883
-#define wxControl_SetLabel 884
-#define wxControlWithItems_Append_1 885
-#define wxControlWithItems_Append_2 886
-#define wxControlWithItems_appendStrings_1 887
-#define wxControlWithItems_Clear 888
-#define wxControlWithItems_Delete 889
-#define wxControlWithItems_FindString 890
-#define wxControlWithItems_getClientData 891
-#define wxControlWithItems_setClientData 892
-#define wxControlWithItems_GetCount 893
-#define wxControlWithItems_GetSelection 894
-#define wxControlWithItems_GetString 895
-#define wxControlWithItems_GetStringSelection 896
-#define wxControlWithItems_Insert_2 897
-#define wxControlWithItems_Insert_3 898
-#define wxControlWithItems_IsEmpty 899
-#define wxControlWithItems_Select 900
-#define wxControlWithItems_SetSelection 901
-#define wxControlWithItems_SetString 902
-#define wxControlWithItems_SetStringSelection 903
-#define wxMenu_new_2 906
-#define wxMenu_new_1 907
-#define wxMenu_destruct 909
-#define wxMenu_Append_3 910
-#define wxMenu_Append_1 911
-#define wxMenu_Append_4_0 912
-#define wxMenu_Append_4_1 913
-#define wxMenu_AppendCheckItem 914
-#define wxMenu_AppendRadioItem 915
-#define wxMenu_AppendSeparator 916
-#define wxMenu_Break 917
-#define wxMenu_Check 918
-#define wxMenu_Delete_1_0 919
-#define wxMenu_Delete_1_1 920
-#define wxMenu_Destroy_1_0 921
-#define wxMenu_Destroy_1_1 922
-#define wxMenu_Enable 923
-#define wxMenu_FindItem_1 924
-#define wxMenu_FindItem_2 925
-#define wxMenu_FindItemByPosition 926
-#define wxMenu_GetHelpString 927
-#define wxMenu_GetLabel 928
-#define wxMenu_GetMenuItemCount 929
-#define wxMenu_GetMenuItems 930
-#define wxMenu_GetTitle 932
-#define wxMenu_Insert_2 933
-#define wxMenu_Insert_3 934
-#define wxMenu_Insert_5_1 935
-#define wxMenu_Insert_5_0 936
-#define wxMenu_InsertCheckItem 937
-#define wxMenu_InsertRadioItem 938
-#define wxMenu_InsertSeparator 939
-#define wxMenu_IsChecked 940
-#define wxMenu_IsEnabled 941
-#define wxMenu_Prepend_1 942
-#define wxMenu_Prepend_2 943
-#define wxMenu_Prepend_4_1 944
-#define wxMenu_Prepend_4_0 945
-#define wxMenu_PrependCheckItem 946
-#define wxMenu_PrependRadioItem 947
-#define wxMenu_PrependSeparator 948
-#define wxMenu_Remove_1_0 949
-#define wxMenu_Remove_1_1 950
-#define wxMenu_SetHelpString 951
-#define wxMenu_SetLabel 952
-#define wxMenu_SetTitle 953
-#define wxMenuItem_new 954
-#define wxMenuItem_destruct 956
-#define wxMenuItem_Check 957
-#define wxMenuItem_Enable 958
-#define wxMenuItem_GetBitmap 959
-#define wxMenuItem_GetHelp 960
-#define wxMenuItem_GetId 961
-#define wxMenuItem_GetKind 962
-#define wxMenuItem_GetLabel 963
-#define wxMenuItem_GetLabelFromText 964
-#define wxMenuItem_GetMenu 965
-#define wxMenuItem_GetText 966
-#define wxMenuItem_GetSubMenu 967
-#define wxMenuItem_IsCheckable 968
-#define wxMenuItem_IsChecked 969
-#define wxMenuItem_IsEnabled 970
-#define wxMenuItem_IsSeparator 971
-#define wxMenuItem_IsSubMenu 972
-#define wxMenuItem_SetBitmap 973
-#define wxMenuItem_SetHelp 974
-#define wxMenuItem_SetMenu 975
-#define wxMenuItem_SetSubMenu 976
-#define wxMenuItem_SetText 977
-#define wxToolBar_AddControl 978
-#define wxToolBar_AddSeparator 979
-#define wxToolBar_AddTool_5 980
-#define wxToolBar_AddTool_4_0 981
-#define wxToolBar_AddTool_1 982
-#define wxToolBar_AddTool_4_1 983
-#define wxToolBar_AddTool_3 984
-#define wxToolBar_AddTool_6 985
-#define wxToolBar_AddCheckTool 986
-#define wxToolBar_AddRadioTool 987
-#define wxToolBar_AddStretchableSpace 988
-#define wxToolBar_InsertStretchableSpace 989
-#define wxToolBar_DeleteTool 990
-#define wxToolBar_DeleteToolByPos 991
-#define wxToolBar_EnableTool 992
-#define wxToolBar_FindById 993
-#define wxToolBar_FindControl 994
-#define wxToolBar_FindToolForPosition 995
-#define wxToolBar_GetToolSize 996
-#define wxToolBar_GetToolBitmapSize 997
-#define wxToolBar_GetMargins 998
-#define wxToolBar_GetToolEnabled 999
-#define wxToolBar_GetToolLongHelp 1000
-#define wxToolBar_GetToolPacking 1001
-#define wxToolBar_GetToolPos 1002
-#define wxToolBar_GetToolSeparation 1003
-#define wxToolBar_GetToolShortHelp 1004
-#define wxToolBar_GetToolState 1005
-#define wxToolBar_InsertControl 1006
-#define wxToolBar_InsertSeparator 1007
-#define wxToolBar_InsertTool_5 1008
-#define wxToolBar_InsertTool_2 1009
-#define wxToolBar_InsertTool_4 1010
-#define wxToolBar_Realize 1011
-#define wxToolBar_RemoveTool 1012
-#define wxToolBar_SetMargins 1013
-#define wxToolBar_SetToolBitmapSize 1014
-#define wxToolBar_SetToolLongHelp 1015
-#define wxToolBar_SetToolPacking 1016
-#define wxToolBar_SetToolShortHelp 1017
-#define wxToolBar_SetToolSeparation 1018
-#define wxToolBar_ToggleTool 1019
-#define wxStatusBar_new_0 1021
-#define wxStatusBar_new_2 1022
-#define wxStatusBar_destruct 1024
-#define wxStatusBar_Create 1025
-#define wxStatusBar_GetFieldRect 1026
-#define wxStatusBar_GetFieldsCount 1027
-#define wxStatusBar_GetStatusText 1028
-#define wxStatusBar_PopStatusText 1029
-#define wxStatusBar_PushStatusText 1030
-#define wxStatusBar_SetFieldsCount 1031
-#define wxStatusBar_SetMinHeight 1032
-#define wxStatusBar_SetStatusText 1033
-#define wxStatusBar_SetStatusWidths 1034
-#define wxStatusBar_SetStatusStyles 1035
-#define wxBitmap_new_0 1036
-#define wxBitmap_new_3 1037
-#define wxBitmap_new_4 1038
-#define wxBitmap_new_2_0 1039
-#define wxBitmap_new_2_1 1040
-#define wxBitmap_destruct 1041
-#define wxBitmap_ConvertToImage 1042
-#define wxBitmap_CopyFromIcon 1043
-#define wxBitmap_Create 1044
-#define wxBitmap_GetDepth 1045
-#define wxBitmap_GetHeight 1046
-#define wxBitmap_GetPalette 1047
-#define wxBitmap_GetMask 1048
-#define wxBitmap_GetWidth 1049
-#define wxBitmap_GetSubBitmap 1050
-#define wxBitmap_LoadFile 1051
-#define wxBitmap_Ok 1052
-#define wxBitmap_SaveFile 1053
-#define wxBitmap_SetDepth 1054
-#define wxBitmap_SetHeight 1055
-#define wxBitmap_SetMask 1056
-#define wxBitmap_SetPalette 1057
-#define wxBitmap_SetWidth 1058
-#define wxIcon_new_0 1059
-#define wxIcon_new_2 1060
-#define wxIcon_new_1 1061
-#define wxIcon_CopyFromBitmap 1062
-#define wxIcon_destroy 1063
-#define wxIconBundle_new_0 1064
-#define wxIconBundle_new_2 1065
-#define wxIconBundle_new_1_0 1066
-#define wxIconBundle_new_1_1 1067
-#define wxIconBundle_destruct 1068
-#define wxIconBundle_AddIcon_2 1069
-#define wxIconBundle_AddIcon_1 1070
-#define wxIconBundle_GetIcon_1_1 1071
-#define wxIconBundle_GetIcon_1_0 1072
-#define wxCursor_new_0 1073
-#define wxCursor_new_1_0 1074
-#define wxCursor_new_1_1 1075
-#define wxCursor_new_4 1076
-#define wxCursor_destruct 1077
-#define wxCursor_Ok 1078
-#define wxMask_new_0 1079
-#define wxMask_new_2_1 1080
-#define wxMask_new_2_0 1081
-#define wxMask_new_1 1082
-#define wxMask_destruct 1083
-#define wxMask_Create_2_1 1084
-#define wxMask_Create_2_0 1085
-#define wxMask_Create_1 1086
-#define wxImage_new_0 1087
-#define wxImage_new_3_0 1088
-#define wxImage_new_4 1089
-#define wxImage_new_5 1090
-#define wxImage_new_2 1091
-#define wxImage_new_3_1 1092
-#define wxImage_Blur 1093
-#define wxImage_BlurHorizontal 1094
-#define wxImage_BlurVertical 1095
-#define wxImage_ConvertAlphaToMask 1096
-#define wxImage_ConvertToGreyscale 1097
-#define wxImage_ConvertToMono 1098
-#define wxImage_Copy 1099
-#define wxImage_Create_3 1100
-#define wxImage_Create_4 1101
-#define wxImage_Create_5 1102
-#define wxImage_Destroy 1103
-#define wxImage_FindFirstUnusedColour 1104
-#define wxImage_GetImageExtWildcard 1105
-#define wxImage_GetAlpha_2 1106
-#define wxImage_GetAlpha_0 1107
-#define wxImage_GetBlue 1108
-#define wxImage_GetData 1109
-#define wxImage_GetGreen 1110
-#define wxImage_GetImageCount 1111
-#define wxImage_GetHeight 1112
-#define wxImage_GetMaskBlue 1113
-#define wxImage_GetMaskGreen 1114
-#define wxImage_GetMaskRed 1115
-#define wxImage_GetOrFindMaskColour 1116
-#define wxImage_GetPalette 1117
-#define wxImage_GetRed 1118
-#define wxImage_GetSubImage 1119
-#define wxImage_GetWidth 1120
-#define wxImage_HasAlpha 1121
-#define wxImage_HasMask 1122
-#define wxImage_GetOption 1123
-#define wxImage_GetOptionInt 1124
-#define wxImage_HasOption 1125
-#define wxImage_InitAlpha 1126
-#define wxImage_InitStandardHandlers 1127
-#define wxImage_IsTransparent 1128
-#define wxImage_LoadFile_2 1129
-#define wxImage_LoadFile_3 1130
-#define wxImage_Ok 1131
-#define wxImage_RemoveHandler 1132
-#define wxImage_Mirror 1133
-#define wxImage_Replace 1134
-#define wxImage_Rescale 1135
-#define wxImage_Resize 1136
-#define wxImage_Rotate 1137
-#define wxImage_RotateHue 1138
-#define wxImage_Rotate90 1139
-#define wxImage_SaveFile_1 1140
-#define wxImage_SaveFile_2_0 1141
-#define wxImage_SaveFile_2_1 1142
-#define wxImage_Scale 1143
-#define wxImage_Size 1144
-#define wxImage_SetAlpha_3 1145
-#define wxImage_SetAlpha_2 1146
-#define wxImage_SetData_2 1147
-#define wxImage_SetData_4 1148
-#define wxImage_SetMask 1149
-#define wxImage_SetMaskColour 1150
-#define wxImage_SetMaskFromImage 1151
-#define wxImage_SetOption_2_1 1152
-#define wxImage_SetOption_2_0 1153
-#define wxImage_SetPalette 1154
-#define wxImage_SetRGB_5 1155
-#define wxImage_SetRGB_4 1156
-#define wxImage_destroy 1157
-#define wxBrush_new_0 1158
-#define wxBrush_new_2 1159
-#define wxBrush_new_1 1160
-#define wxBrush_destruct 1162
-#define wxBrush_GetColour 1163
-#define wxBrush_GetStipple 1164
-#define wxBrush_GetStyle 1165
-#define wxBrush_IsHatch 1166
-#define wxBrush_IsOk 1167
-#define wxBrush_SetColour_1 1168
-#define wxBrush_SetColour_3 1169
-#define wxBrush_SetStipple 1170
-#define wxBrush_SetStyle 1171
-#define wxPen_new_0 1172
-#define wxPen_new_2 1173
-#define wxPen_destruct 1174
-#define wxPen_GetCap 1175
-#define wxPen_GetColour 1176
-#define wxPen_GetJoin 1177
-#define wxPen_GetStyle 1178
-#define wxPen_GetWidth 1179
-#define wxPen_IsOk 1180
-#define wxPen_SetCap 1181
-#define wxPen_SetColour_1 1182
-#define wxPen_SetColour_3 1183
-#define wxPen_SetJoin 1184
-#define wxPen_SetStyle 1185
-#define wxPen_SetWidth 1186
-#define wxRegion_new_0 1187
-#define wxRegion_new_4 1188
-#define wxRegion_new_2 1189
-#define wxRegion_new_1_1 1190
-#define wxRegion_new_1_0 1192
-#define wxRegion_destruct 1194
-#define wxRegion_Clear 1195
-#define wxRegion_Contains_2 1196
-#define wxRegion_Contains_1_0 1197
-#define wxRegion_Contains_4 1198
-#define wxRegion_Contains_1_1 1199
-#define wxRegion_ConvertToBitmap 1200
-#define wxRegion_GetBox 1201
-#define wxRegion_Intersect_4 1202
-#define wxRegion_Intersect_1_1 1203
-#define wxRegion_Intersect_1_0 1204
-#define wxRegion_IsEmpty 1205
-#define wxRegion_Subtract_4 1206
-#define wxRegion_Subtract_1_1 1207
-#define wxRegion_Subtract_1_0 1208
-#define wxRegion_Offset_2 1209
-#define wxRegion_Offset_1 1210
-#define wxRegion_Union_4 1211
-#define wxRegion_Union_1_2 1212
-#define wxRegion_Union_1_1 1213
-#define wxRegion_Union_1_0 1214
-#define wxRegion_Union_3 1215
-#define wxRegion_Xor_4 1216
-#define wxRegion_Xor_1_1 1217
-#define wxRegion_Xor_1_0 1218
-#define wxAcceleratorTable_new_0 1219
-#define wxAcceleratorTable_new_2 1220
-#define wxAcceleratorTable_destruct 1221
-#define wxAcceleratorTable_Ok 1222
-#define wxAcceleratorEntry_new_1_0 1223
-#define wxAcceleratorEntry_new_1_1 1224
-#define wxAcceleratorEntry_GetCommand 1225
-#define wxAcceleratorEntry_GetFlags 1226
-#define wxAcceleratorEntry_GetKeyCode 1227
-#define wxAcceleratorEntry_Set 1228
-#define wxAcceleratorEntry_destroy 1229
-#define wxCaret_new_3 1234
-#define wxCaret_new_2 1235
-#define wxCaret_destruct 1237
-#define wxCaret_Create_3 1238
-#define wxCaret_Create_2 1239
-#define wxCaret_GetBlinkTime 1240
-#define wxCaret_GetPosition 1242
-#define wxCaret_GetSize 1244
-#define wxCaret_GetWindow 1245
-#define wxCaret_Hide 1246
-#define wxCaret_IsOk 1247
-#define wxCaret_IsVisible 1248
-#define wxCaret_Move_2 1249
-#define wxCaret_Move_1 1250
-#define wxCaret_SetBlinkTime 1251
-#define wxCaret_SetSize_2 1252
-#define wxCaret_SetSize_1 1253
-#define wxCaret_Show 1254
-#define wxSizer_Add_2_1 1255
-#define wxSizer_Add_2_0 1256
-#define wxSizer_Add_3 1257
-#define wxSizer_Add_2_3 1258
-#define wxSizer_Add_2_2 1259
-#define wxSizer_AddSpacer 1260
-#define wxSizer_AddStretchSpacer 1261
-#define wxSizer_CalcMin 1262
-#define wxSizer_Clear 1263
-#define wxSizer_Detach_1_2 1264
-#define wxSizer_Detach_1_1 1265
-#define wxSizer_Detach_1_0 1266
-#define wxSizer_Fit 1267
-#define wxSizer_FitInside 1268
-#define wxSizer_GetChildren 1269
-#define wxSizer_GetItem_2_1 1270
-#define wxSizer_GetItem_2_0 1271
-#define wxSizer_GetItem_1 1272
-#define wxSizer_GetSize 1273
-#define wxSizer_GetPosition 1274
-#define wxSizer_GetMinSize 1275
-#define wxSizer_Hide_2_0 1276
-#define wxSizer_Hide_2_1 1277
-#define wxSizer_Hide_1 1278
-#define wxSizer_Insert_3_1 1279
-#define wxSizer_Insert_3_0 1280
-#define wxSizer_Insert_4 1281
-#define wxSizer_Insert_3_3 1282
-#define wxSizer_Insert_3_2 1283
-#define wxSizer_Insert_2 1284
-#define wxSizer_InsertSpacer 1285
-#define wxSizer_InsertStretchSpacer 1286
-#define wxSizer_IsShown_1_2 1287
-#define wxSizer_IsShown_1_1 1288
-#define wxSizer_IsShown_1_0 1289
-#define wxSizer_Layout 1290
-#define wxSizer_Prepend_2_1 1291
-#define wxSizer_Prepend_2_0 1292
-#define wxSizer_Prepend_3 1293
-#define wxSizer_Prepend_2_3 1294
-#define wxSizer_Prepend_2_2 1295
-#define wxSizer_Prepend_1 1296
-#define wxSizer_PrependSpacer 1297
-#define wxSizer_PrependStretchSpacer 1298
-#define wxSizer_RecalcSizes 1299
-#define wxSizer_Remove_1_1 1300
-#define wxSizer_Remove_1_0 1301
-#define wxSizer_Replace_3_1 1302
-#define wxSizer_Replace_3_0 1303
-#define wxSizer_Replace_2 1304
-#define wxSizer_SetDimension 1305
-#define wxSizer_SetMinSize_2 1306
-#define wxSizer_SetMinSize_1 1307
-#define wxSizer_SetItemMinSize_3_2 1308
-#define wxSizer_SetItemMinSize_2_2 1309
-#define wxSizer_SetItemMinSize_3_1 1310
-#define wxSizer_SetItemMinSize_2_1 1311
-#define wxSizer_SetItemMinSize_3_0 1312
-#define wxSizer_SetItemMinSize_2_0 1313
-#define wxSizer_SetSizeHints 1314
-#define wxSizer_SetVirtualSizeHints 1315
-#define wxSizer_Show_2_2 1316
-#define wxSizer_Show_2_1 1317
-#define wxSizer_Show_2_0 1318
-#define wxSizer_Show_1 1319
-#define wxSizerFlags_new 1320
-#define wxSizerFlags_Align 1321
-#define wxSizerFlags_Border_2 1322
-#define wxSizerFlags_Border_1 1323
-#define wxSizerFlags_Center 1324
-#define wxSizerFlags_Centre 1325
-#define wxSizerFlags_Expand 1326
-#define wxSizerFlags_Left 1327
-#define wxSizerFlags_Proportion 1328
-#define wxSizerFlags_Right 1329
-#define wxSizerFlags_destroy 1330
-#define wxSizerItem_new_5_1 1331
-#define wxSizerItem_new_2_1 1332
-#define wxSizerItem_new_5_0 1333
-#define wxSizerItem_new_2_0 1334
-#define wxSizerItem_new_6 1335
-#define wxSizerItem_new_3 1336
-#define wxSizerItem_new_0 1337
-#define wxSizerItem_destruct 1338
-#define wxSizerItem_CalcMin 1339
-#define wxSizerItem_DeleteWindows 1340
-#define wxSizerItem_DetachSizer 1341
-#define wxSizerItem_GetBorder 1342
-#define wxSizerItem_GetFlag 1343
-#define wxSizerItem_GetMinSize 1344
-#define wxSizerItem_GetPosition 1345
-#define wxSizerItem_GetProportion 1346
-#define wxSizerItem_GetRatio 1347
-#define wxSizerItem_GetRect 1348
-#define wxSizerItem_GetSize 1349
-#define wxSizerItem_GetSizer 1350
-#define wxSizerItem_GetSpacer 1351
-#define wxSizerItem_GetUserData 1352
-#define wxSizerItem_GetWindow 1353
-#define wxSizerItem_IsSizer 1354
-#define wxSizerItem_IsShown 1355
-#define wxSizerItem_IsSpacer 1356
-#define wxSizerItem_IsWindow 1357
-#define wxSizerItem_SetBorder 1358
-#define wxSizerItem_SetDimension 1359
-#define wxSizerItem_SetFlag 1360
-#define wxSizerItem_SetInitSize 1361
-#define wxSizerItem_SetMinSize_1 1362
-#define wxSizerItem_SetMinSize_2 1363
-#define wxSizerItem_SetProportion 1364
-#define wxSizerItem_SetRatio_2 1365
-#define wxSizerItem_SetRatio_1_1 1366
-#define wxSizerItem_SetRatio_1_0 1367
-#define wxSizerItem_SetSizer 1368
-#define wxSizerItem_SetSpacer_1 1369
-#define wxSizerItem_SetSpacer_2 1370
-#define wxSizerItem_SetWindow 1371
-#define wxSizerItem_Show 1372
-#define wxBoxSizer_new 1373
-#define wxBoxSizer_GetOrientation 1374
-#define wxBoxSizer_destroy 1375
-#define wxStaticBoxSizer_new_2 1376
-#define wxStaticBoxSizer_new_3 1377
-#define wxStaticBoxSizer_GetStaticBox 1378
-#define wxStaticBoxSizer_destroy 1379
-#define wxGridSizer_new_4 1380
-#define wxGridSizer_new_2 1381
-#define wxGridSizer_GetCols 1382
-#define wxGridSizer_GetHGap 1383
-#define wxGridSizer_GetRows 1384
-#define wxGridSizer_GetVGap 1385
-#define wxGridSizer_SetCols 1386
-#define wxGridSizer_SetHGap 1387
-#define wxGridSizer_SetRows 1388
-#define wxGridSizer_SetVGap 1389
-#define wxGridSizer_destroy 1390
-#define wxFlexGridSizer_new_4 1391
-#define wxFlexGridSizer_new_2 1392
-#define wxFlexGridSizer_AddGrowableCol 1393
-#define wxFlexGridSizer_AddGrowableRow 1394
-#define wxFlexGridSizer_GetFlexibleDirection 1395
-#define wxFlexGridSizer_GetNonFlexibleGrowMode 1396
-#define wxFlexGridSizer_RemoveGrowableCol 1397
-#define wxFlexGridSizer_RemoveGrowableRow 1398
-#define wxFlexGridSizer_SetFlexibleDirection 1399
-#define wxFlexGridSizer_SetNonFlexibleGrowMode 1400
-#define wxFlexGridSizer_destroy 1401
-#define wxGridBagSizer_new 1402
-#define wxGridBagSizer_Add_3_2 1403
-#define wxGridBagSizer_Add_3_1 1404
-#define wxGridBagSizer_Add_4 1405
-#define wxGridBagSizer_Add_1_0 1406
-#define wxGridBagSizer_Add_2_1 1407
-#define wxGridBagSizer_Add_2_0 1408
-#define wxGridBagSizer_Add_3_0 1409
-#define wxGridBagSizer_Add_1_1 1410
-#define wxGridBagSizer_CalcMin 1411
-#define wxGridBagSizer_CheckForIntersection_2 1412
-#define wxGridBagSizer_CheckForIntersection_3 1413
-#define wxGridBagSizer_FindItem_1_1 1414
-#define wxGridBagSizer_FindItem_1_0 1415
-#define wxGridBagSizer_FindItemAtPoint 1416
-#define wxGridBagSizer_FindItemAtPosition 1417
-#define wxGridBagSizer_FindItemWithData 1418
-#define wxGridBagSizer_GetCellSize 1419
-#define wxGridBagSizer_GetEmptyCellSize 1420
-#define wxGridBagSizer_GetItemPosition_1_2 1421
-#define wxGridBagSizer_GetItemPosition_1_1 1422
-#define wxGridBagSizer_GetItemPosition_1_0 1423
-#define wxGridBagSizer_GetItemSpan_1_2 1424
-#define wxGridBagSizer_GetItemSpan_1_1 1425
-#define wxGridBagSizer_GetItemSpan_1_0 1426
-#define wxGridBagSizer_SetEmptyCellSize 1427
-#define wxGridBagSizer_SetItemPosition_2_2 1428
-#define wxGridBagSizer_SetItemPosition_2_1 1429
-#define wxGridBagSizer_SetItemPosition_2_0 1430
-#define wxGridBagSizer_SetItemSpan_2_2 1431
-#define wxGridBagSizer_SetItemSpan_2_1 1432
-#define wxGridBagSizer_SetItemSpan_2_0 1433
-#define wxGridBagSizer_destroy 1434
-#define wxStdDialogButtonSizer_new 1435
-#define wxStdDialogButtonSizer_AddButton 1436
-#define wxStdDialogButtonSizer_Realize 1437
-#define wxStdDialogButtonSizer_SetAffirmativeButton 1438
-#define wxStdDialogButtonSizer_SetCancelButton 1439
-#define wxStdDialogButtonSizer_SetNegativeButton 1440
-#define wxStdDialogButtonSizer_destroy 1441
-#define wxFont_new_0 1442
-#define wxFont_new_1 1443
-#define wxFont_new_5 1444
-#define wxFont_destruct 1446
-#define wxFont_IsFixedWidth 1447
-#define wxFont_GetDefaultEncoding 1448
-#define wxFont_GetFaceName 1449
-#define wxFont_GetFamily 1450
-#define wxFont_GetNativeFontInfoDesc 1451
-#define wxFont_GetNativeFontInfoUserDesc 1452
-#define wxFont_GetPointSize 1453
-#define wxFont_GetStyle 1454
-#define wxFont_GetUnderlined 1455
-#define wxFont_GetWeight 1456
-#define wxFont_Ok 1457
-#define wxFont_SetDefaultEncoding 1458
-#define wxFont_SetFaceName 1459
-#define wxFont_SetFamily 1460
-#define wxFont_SetPointSize 1461
-#define wxFont_SetStyle 1462
-#define wxFont_SetUnderlined 1463
-#define wxFont_SetWeight 1464
-#define wxToolTip_Enable 1465
-#define wxToolTip_SetDelay 1466
-#define wxToolTip_new 1467
-#define wxToolTip_SetTip 1468
-#define wxToolTip_GetTip 1469
-#define wxToolTip_GetWindow 1470
-#define wxToolTip_destroy 1471
-#define wxButton_new_3 1473
-#define wxButton_new_0 1474
-#define wxButton_destruct 1475
-#define wxButton_Create 1476
-#define wxButton_GetDefaultSize 1477
-#define wxButton_SetDefault 1478
-#define wxButton_SetLabel 1479
-#define wxBitmapButton_new_4 1481
-#define wxBitmapButton_new_0 1482
-#define wxBitmapButton_Create 1483
-#define wxBitmapButton_GetBitmapDisabled 1484
-#define wxBitmapButton_GetBitmapFocus 1486
-#define wxBitmapButton_GetBitmapLabel 1488
-#define wxBitmapButton_GetBitmapSelected 1490
-#define wxBitmapButton_SetBitmapDisabled 1492
-#define wxBitmapButton_SetBitmapFocus 1493
-#define wxBitmapButton_SetBitmapLabel 1494
-#define wxBitmapButton_SetBitmapSelected 1495
-#define wxBitmapButton_destroy 1496
-#define wxToggleButton_new_0 1497
-#define wxToggleButton_new_4 1498
-#define wxToggleButton_Create 1499
-#define wxToggleButton_GetValue 1500
-#define wxToggleButton_SetValue 1501
-#define wxToggleButton_destroy 1502
-#define wxCalendarCtrl_new_0 1503
-#define wxCalendarCtrl_new_3 1504
-#define wxCalendarCtrl_Create 1505
-#define wxCalendarCtrl_destruct 1506
-#define wxCalendarCtrl_SetDate 1507
-#define wxCalendarCtrl_GetDate 1508
-#define wxCalendarCtrl_EnableYearChange 1509
-#define wxCalendarCtrl_EnableMonthChange 1510
-#define wxCalendarCtrl_EnableHolidayDisplay 1511
-#define wxCalendarCtrl_SetHeaderColours 1512
-#define wxCalendarCtrl_GetHeaderColourFg 1513
-#define wxCalendarCtrl_GetHeaderColourBg 1514
-#define wxCalendarCtrl_SetHighlightColours 1515
-#define wxCalendarCtrl_GetHighlightColourFg 1516
-#define wxCalendarCtrl_GetHighlightColourBg 1517
-#define wxCalendarCtrl_SetHolidayColours 1518
-#define wxCalendarCtrl_GetHolidayColourFg 1519
-#define wxCalendarCtrl_GetHolidayColourBg 1520
-#define wxCalendarCtrl_GetAttr 1521
-#define wxCalendarCtrl_SetAttr 1522
-#define wxCalendarCtrl_SetHoliday 1523
-#define wxCalendarCtrl_ResetAttr 1524
-#define wxCalendarCtrl_HitTest 1525
-#define wxCalendarDateAttr_new_0 1526
-#define wxCalendarDateAttr_new_2_1 1527
-#define wxCalendarDateAttr_new_2_0 1528
-#define wxCalendarDateAttr_SetTextColour 1529
-#define wxCalendarDateAttr_SetBackgroundColour 1530
-#define wxCalendarDateAttr_SetBorderColour 1531
-#define wxCalendarDateAttr_SetFont 1532
-#define wxCalendarDateAttr_SetBorder 1533
-#define wxCalendarDateAttr_SetHoliday 1534
-#define wxCalendarDateAttr_HasTextColour 1535
-#define wxCalendarDateAttr_HasBackgroundColour 1536
-#define wxCalendarDateAttr_HasBorderColour 1537
-#define wxCalendarDateAttr_HasFont 1538
-#define wxCalendarDateAttr_HasBorder 1539
-#define wxCalendarDateAttr_IsHoliday 1540
-#define wxCalendarDateAttr_GetTextColour 1541
-#define wxCalendarDateAttr_GetBackgroundColour 1542
-#define wxCalendarDateAttr_GetBorderColour 1543
-#define wxCalendarDateAttr_GetFont 1544
-#define wxCalendarDateAttr_GetBorder 1545
-#define wxCalendarDateAttr_destroy 1546
-#define wxCheckBox_new_4 1548
-#define wxCheckBox_new_0 1549
-#define wxCheckBox_Create 1550
-#define wxCheckBox_GetValue 1551
-#define wxCheckBox_Get3StateValue 1552
-#define wxCheckBox_Is3rdStateAllowedForUser 1553
-#define wxCheckBox_Is3State 1554
-#define wxCheckBox_IsChecked 1555
-#define wxCheckBox_SetValue 1556
-#define wxCheckBox_Set3StateValue 1557
-#define wxCheckBox_destroy 1558
-#define wxCheckListBox_new_0 1559
-#define wxCheckListBox_new_3 1561
-#define wxCheckListBox_Check 1562
-#define wxCheckListBox_IsChecked 1563
-#define wxCheckListBox_destroy 1564
-#define wxChoice_new_3 1567
-#define wxChoice_new_0 1568
-#define wxChoice_destruct 1570
-#define wxChoice_Create 1572
-#define wxChoice_Delete 1573
-#define wxChoice_GetColumns 1574
-#define wxChoice_SetColumns 1575
-#define wxComboBox_new_0 1576
-#define wxComboBox_new_3 1578
-#define wxComboBox_destruct 1579
-#define wxComboBox_Create 1581
-#define wxComboBox_CanCopy 1582
-#define wxComboBox_CanCut 1583
-#define wxComboBox_CanPaste 1584
-#define wxComboBox_CanRedo 1585
-#define wxComboBox_CanUndo 1586
-#define wxComboBox_Copy 1587
-#define wxComboBox_Cut 1588
-#define wxComboBox_GetInsertionPoint 1589
-#define wxComboBox_GetLastPosition 1590
-#define wxComboBox_GetValue 1591
-#define wxComboBox_Paste 1592
-#define wxComboBox_Redo 1593
-#define wxComboBox_Replace 1594
-#define wxComboBox_Remove 1595
-#define wxComboBox_SetInsertionPoint 1596
-#define wxComboBox_SetInsertionPointEnd 1597
-#define wxComboBox_SetSelection_1 1598
-#define wxComboBox_SetSelection_2 1599
-#define wxComboBox_SetValue 1600
-#define wxComboBox_Undo 1601
-#define wxGauge_new_0 1602
-#define wxGauge_new_4 1603
-#define wxGauge_Create 1604
-#define wxGauge_GetRange 1605
-#define wxGauge_GetValue 1606
-#define wxGauge_IsVertical 1607
-#define wxGauge_SetRange 1608
-#define wxGauge_SetValue 1609
-#define wxGauge_Pulse 1610
-#define wxGauge_destroy 1611
-#define wxGenericDirCtrl_new_0 1612
-#define wxGenericDirCtrl_new_2 1613
-#define wxGenericDirCtrl_destruct 1614
-#define wxGenericDirCtrl_Create 1615
-#define wxGenericDirCtrl_Init 1616
-#define wxGenericDirCtrl_CollapseTree 1617
-#define wxGenericDirCtrl_ExpandPath 1618
-#define wxGenericDirCtrl_GetDefaultPath 1619
-#define wxGenericDirCtrl_GetPath 1620
-#define wxGenericDirCtrl_GetFilePath 1621
-#define wxGenericDirCtrl_GetFilter 1622
-#define wxGenericDirCtrl_GetFilterIndex 1623
-#define wxGenericDirCtrl_GetRootId 1624
-#define wxGenericDirCtrl_GetTreeCtrl 1625
-#define wxGenericDirCtrl_ReCreateTree 1626
-#define wxGenericDirCtrl_SetDefaultPath 1627
-#define wxGenericDirCtrl_SetFilter 1628
-#define wxGenericDirCtrl_SetFilterIndex 1629
-#define wxGenericDirCtrl_SetPath 1630
-#define wxStaticBox_new_4 1632
-#define wxStaticBox_new_0 1633
-#define wxStaticBox_Create 1634
-#define wxStaticBox_destroy 1635
-#define wxStaticLine_new_2 1637
-#define wxStaticLine_new_0 1638
-#define wxStaticLine_Create 1639
-#define wxStaticLine_IsVertical 1640
-#define wxStaticLine_GetDefaultSize 1641
-#define wxStaticLine_destroy 1642
-#define wxListBox_new_3 1645
-#define wxListBox_new_0 1646
-#define wxListBox_destruct 1648
-#define wxListBox_Create 1650
-#define wxListBox_Deselect 1651
-#define wxListBox_GetSelections 1652
-#define wxListBox_InsertItems 1653
-#define wxListBox_IsSelected 1654
-#define wxListBox_Set 1655
-#define wxListBox_HitTest 1656
-#define wxListBox_SetFirstItem_1_0 1657
-#define wxListBox_SetFirstItem_1_1 1658
-#define wxListCtrl_new_0 1659
-#define wxListCtrl_new_2 1660
-#define wxListCtrl_Arrange 1661
-#define wxListCtrl_AssignImageList 1662
-#define wxListCtrl_ClearAll 1663
-#define wxListCtrl_Create 1664
-#define wxListCtrl_DeleteAllItems 1665
-#define wxListCtrl_DeleteColumn 1666
-#define wxListCtrl_DeleteItem 1667
-#define wxListCtrl_EditLabel 1668
-#define wxListCtrl_EnsureVisible 1669
-#define wxListCtrl_FindItem_3_0 1670
-#define wxListCtrl_FindItem_3_1 1671
-#define wxListCtrl_GetColumn 1672
-#define wxListCtrl_GetColumnCount 1673
-#define wxListCtrl_GetColumnWidth 1674
-#define wxListCtrl_GetCountPerPage 1675
-#define wxListCtrl_GetEditControl 1676
-#define wxListCtrl_GetImageList 1677
-#define wxListCtrl_GetItem 1678
-#define wxListCtrl_GetItemBackgroundColour 1679
-#define wxListCtrl_GetItemCount 1680
-#define wxListCtrl_GetItemData 1681
-#define wxListCtrl_GetItemFont 1682
-#define wxListCtrl_GetItemPosition 1683
-#define wxListCtrl_GetItemRect 1684
-#define wxListCtrl_GetItemSpacing 1685
-#define wxListCtrl_GetItemState 1686
-#define wxListCtrl_GetItemText 1687
-#define wxListCtrl_GetItemTextColour 1688
-#define wxListCtrl_GetNextItem 1689
-#define wxListCtrl_GetSelectedItemCount 1690
-#define wxListCtrl_GetTextColour 1691
-#define wxListCtrl_GetTopItem 1692
-#define wxListCtrl_GetViewRect 1693
-#define wxListCtrl_HitTest 1694
-#define wxListCtrl_InsertColumn_2 1695
-#define wxListCtrl_InsertColumn_3 1696
-#define wxListCtrl_InsertItem_1 1697
-#define wxListCtrl_InsertItem_2_1 1698
-#define wxListCtrl_InsertItem_2_0 1699
-#define wxListCtrl_InsertItem_3 1700
-#define wxListCtrl_RefreshItem 1701
-#define wxListCtrl_RefreshItems 1702
-#define wxListCtrl_ScrollList 1703
-#define wxListCtrl_SetBackgroundColour 1704
-#define wxListCtrl_SetColumn 1705
-#define wxListCtrl_SetColumnWidth 1706
-#define wxListCtrl_SetImageList 1707
-#define wxListCtrl_SetItem_1 1708
-#define wxListCtrl_SetItem_4 1709
-#define wxListCtrl_SetItemBackgroundColour 1710
-#define wxListCtrl_SetItemCount 1711
-#define wxListCtrl_SetItemData 1712
-#define wxListCtrl_SetItemFont 1713
-#define wxListCtrl_SetItemImage 1714
-#define wxListCtrl_SetItemColumnImage 1715
-#define wxListCtrl_SetItemPosition 1716
-#define wxListCtrl_SetItemState 1717
-#define wxListCtrl_SetItemText 1718
-#define wxListCtrl_SetItemTextColour 1719
-#define wxListCtrl_SetSingleStyle 1720
-#define wxListCtrl_SetTextColour 1721
-#define wxListCtrl_SetWindowStyleFlag 1722
-#define wxListCtrl_SortItems 1723
-#define wxListCtrl_destroy 1724
-#define wxListView_ClearColumnImage 1725
-#define wxListView_Focus 1726
-#define wxListView_GetFirstSelected 1727
-#define wxListView_GetFocusedItem 1728
-#define wxListView_GetNextSelected 1729
-#define wxListView_IsSelected 1730
-#define wxListView_Select 1731
-#define wxListView_SetColumnImage 1732
-#define wxListItem_new_0 1733
-#define wxListItem_new_1 1734
-#define wxListItem_destruct 1735
-#define wxListItem_Clear 1736
-#define wxListItem_GetAlign 1737
-#define wxListItem_GetBackgroundColour 1738
-#define wxListItem_GetColumn 1739
-#define wxListItem_GetFont 1740
-#define wxListItem_GetId 1741
-#define wxListItem_GetImage 1742
-#define wxListItem_GetMask 1743
-#define wxListItem_GetState 1744
-#define wxListItem_GetText 1745
-#define wxListItem_GetTextColour 1746
-#define wxListItem_GetWidth 1747
-#define wxListItem_SetAlign 1748
-#define wxListItem_SetBackgroundColour 1749
-#define wxListItem_SetColumn 1750
-#define wxListItem_SetFont 1751
-#define wxListItem_SetId 1752
-#define wxListItem_SetImage 1753
-#define wxListItem_SetMask 1754
-#define wxListItem_SetState 1755
-#define wxListItem_SetStateMask 1756
-#define wxListItem_SetText 1757
-#define wxListItem_SetTextColour 1758
-#define wxListItem_SetWidth 1759
-#define wxListItemAttr_new_0 1760
-#define wxListItemAttr_new_3 1761
-#define wxListItemAttr_GetBackgroundColour 1762
-#define wxListItemAttr_GetFont 1763
-#define wxListItemAttr_GetTextColour 1764
-#define wxListItemAttr_HasBackgroundColour 1765
-#define wxListItemAttr_HasFont 1766
-#define wxListItemAttr_HasTextColour 1767
-#define wxListItemAttr_SetBackgroundColour 1768
-#define wxListItemAttr_SetFont 1769
-#define wxListItemAttr_SetTextColour 1770
-#define wxListItemAttr_destroy 1771
-#define wxImageList_new_0 1772
-#define wxImageList_new_3 1773
-#define wxImageList_Add_1 1774
-#define wxImageList_Add_2_0 1775
-#define wxImageList_Add_2_1 1776
-#define wxImageList_Create 1777
-#define wxImageList_Draw 1779
-#define wxImageList_GetBitmap 1780
-#define wxImageList_GetIcon 1781
-#define wxImageList_GetImageCount 1782
-#define wxImageList_GetSize 1783
-#define wxImageList_Remove 1784
-#define wxImageList_RemoveAll 1785
-#define wxImageList_Replace_2 1786
-#define wxImageList_Replace_3 1787
-#define wxImageList_destroy 1788
-#define wxTextAttr_new_0 1789
-#define wxTextAttr_new_2 1790
-#define wxTextAttr_GetAlignment 1791
-#define wxTextAttr_GetBackgroundColour 1792
-#define wxTextAttr_GetFont 1793
-#define wxTextAttr_GetLeftIndent 1794
-#define wxTextAttr_GetLeftSubIndent 1795
-#define wxTextAttr_GetRightIndent 1796
-#define wxTextAttr_GetTabs 1797
-#define wxTextAttr_GetTextColour 1798
-#define wxTextAttr_HasBackgroundColour 1799
-#define wxTextAttr_HasFont 1800
-#define wxTextAttr_HasTextColour 1801
-#define wxTextAttr_GetFlags 1802
-#define wxTextAttr_IsDefault 1803
-#define wxTextAttr_SetAlignment 1804
-#define wxTextAttr_SetBackgroundColour 1805
-#define wxTextAttr_SetFlags 1806
-#define wxTextAttr_SetFont 1807
-#define wxTextAttr_SetLeftIndent 1808
-#define wxTextAttr_SetRightIndent 1809
-#define wxTextAttr_SetTabs 1810
-#define wxTextAttr_SetTextColour 1811
-#define wxTextAttr_destroy 1812
-#define wxTextCtrl_new_3 1814
-#define wxTextCtrl_new_0 1815
-#define wxTextCtrl_destruct 1817
-#define wxTextCtrl_AppendText 1818
-#define wxTextCtrl_CanCopy 1819
-#define wxTextCtrl_CanCut 1820
-#define wxTextCtrl_CanPaste 1821
-#define wxTextCtrl_CanRedo 1822
-#define wxTextCtrl_CanUndo 1823
-#define wxTextCtrl_Clear 1824
-#define wxTextCtrl_Copy 1825
-#define wxTextCtrl_Create 1826
-#define wxTextCtrl_Cut 1827
-#define wxTextCtrl_DiscardEdits 1828
-#define wxTextCtrl_ChangeValue 1829
-#define wxTextCtrl_EmulateKeyPress 1830
-#define wxTextCtrl_GetDefaultStyle 1831
-#define wxTextCtrl_GetInsertionPoint 1832
-#define wxTextCtrl_GetLastPosition 1833
-#define wxTextCtrl_GetLineLength 1834
-#define wxTextCtrl_GetLineText 1835
-#define wxTextCtrl_GetNumberOfLines 1836
-#define wxTextCtrl_GetRange 1837
-#define wxTextCtrl_GetSelection 1838
-#define wxTextCtrl_GetStringSelection 1839
-#define wxTextCtrl_GetStyle 1840
-#define wxTextCtrl_GetValue 1841
-#define wxTextCtrl_IsEditable 1842
-#define wxTextCtrl_IsModified 1843
-#define wxTextCtrl_IsMultiLine 1844
-#define wxTextCtrl_IsSingleLine 1845
-#define wxTextCtrl_LoadFile 1846
-#define wxTextCtrl_MarkDirty 1847
-#define wxTextCtrl_Paste 1848
-#define wxTextCtrl_PositionToXY 1849
-#define wxTextCtrl_Redo 1850
-#define wxTextCtrl_Remove 1851
-#define wxTextCtrl_Replace 1852
-#define wxTextCtrl_SaveFile 1853
-#define wxTextCtrl_SetDefaultStyle 1854
-#define wxTextCtrl_SetEditable 1855
-#define wxTextCtrl_SetInsertionPoint 1856
-#define wxTextCtrl_SetInsertionPointEnd 1857
-#define wxTextCtrl_SetMaxLength 1859
-#define wxTextCtrl_SetSelection 1860
-#define wxTextCtrl_SetStyle 1861
-#define wxTextCtrl_SetValue 1862
-#define wxTextCtrl_ShowPosition 1863
-#define wxTextCtrl_Undo 1864
-#define wxTextCtrl_WriteText 1865
-#define wxTextCtrl_XYToPosition 1866
-#define wxNotebook_new_0 1869
-#define wxNotebook_new_3 1870
-#define wxNotebook_destruct 1871
-#define wxNotebook_AddPage 1872
-#define wxNotebook_AdvanceSelection 1873
-#define wxNotebook_AssignImageList 1874
-#define wxNotebook_Create 1875
-#define wxNotebook_DeleteAllPages 1876
-#define wxNotebook_DeletePage 1877
-#define wxNotebook_RemovePage 1878
-#define wxNotebook_GetCurrentPage 1879
-#define wxNotebook_GetImageList 1880
-#define wxNotebook_GetPage 1882
-#define wxNotebook_GetPageCount 1883
-#define wxNotebook_GetPageImage 1884
-#define wxNotebook_GetPageText 1885
-#define wxNotebook_GetRowCount 1886
-#define wxNotebook_GetSelection 1887
-#define wxNotebook_GetThemeBackgroundColour 1888
-#define wxNotebook_HitTest 1890
-#define wxNotebook_InsertPage 1892
-#define wxNotebook_SetImageList 1893
-#define wxNotebook_SetPadding 1894
-#define wxNotebook_SetPageSize 1895
-#define wxNotebook_SetPageImage 1896
-#define wxNotebook_SetPageText 1897
-#define wxNotebook_SetSelection 1898
-#define wxNotebook_ChangeSelection 1899
-#define wxChoicebook_new_0 1900
-#define wxChoicebook_new_3 1901
-#define wxChoicebook_AddPage 1902
-#define wxChoicebook_AdvanceSelection 1903
-#define wxChoicebook_AssignImageList 1904
-#define wxChoicebook_Create 1905
-#define wxChoicebook_DeleteAllPages 1906
-#define wxChoicebook_DeletePage 1907
-#define wxChoicebook_RemovePage 1908
-#define wxChoicebook_GetCurrentPage 1909
-#define wxChoicebook_GetImageList 1910
-#define wxChoicebook_GetPage 1912
-#define wxChoicebook_GetPageCount 1913
-#define wxChoicebook_GetPageImage 1914
-#define wxChoicebook_GetPageText 1915
-#define wxChoicebook_GetSelection 1916
-#define wxChoicebook_HitTest 1917
-#define wxChoicebook_InsertPage 1918
-#define wxChoicebook_SetImageList 1919
-#define wxChoicebook_SetPageSize 1920
-#define wxChoicebook_SetPageImage 1921
-#define wxChoicebook_SetPageText 1922
-#define wxChoicebook_SetSelection 1923
-#define wxChoicebook_ChangeSelection 1924
-#define wxChoicebook_destroy 1925
-#define wxToolbook_new_0 1926
-#define wxToolbook_new_3 1927
-#define wxToolbook_AddPage 1928
-#define wxToolbook_AdvanceSelection 1929
-#define wxToolbook_AssignImageList 1930
-#define wxToolbook_Create 1931
-#define wxToolbook_DeleteAllPages 1932
-#define wxToolbook_DeletePage 1933
-#define wxToolbook_RemovePage 1934
-#define wxToolbook_GetCurrentPage 1935
-#define wxToolbook_GetImageList 1936
-#define wxToolbook_GetPage 1938
-#define wxToolbook_GetPageCount 1939
-#define wxToolbook_GetPageImage 1940
-#define wxToolbook_GetPageText 1941
-#define wxToolbook_GetSelection 1942
-#define wxToolbook_HitTest 1944
-#define wxToolbook_InsertPage 1945
-#define wxToolbook_SetImageList 1946
-#define wxToolbook_SetPageSize 1947
-#define wxToolbook_SetPageImage 1948
-#define wxToolbook_SetPageText 1949
-#define wxToolbook_SetSelection 1950
-#define wxToolbook_ChangeSelection 1951
-#define wxToolbook_destroy 1952
-#define wxListbook_new_0 1953
-#define wxListbook_new_3 1954
-#define wxListbook_AddPage 1955
-#define wxListbook_AdvanceSelection 1956
-#define wxListbook_AssignImageList 1957
-#define wxListbook_Create 1958
-#define wxListbook_DeleteAllPages 1959
-#define wxListbook_DeletePage 1960
-#define wxListbook_RemovePage 1961
-#define wxListbook_GetCurrentPage 1962
-#define wxListbook_GetImageList 1963
-#define wxListbook_GetPage 1965
-#define wxListbook_GetPageCount 1966
-#define wxListbook_GetPageImage 1967
-#define wxListbook_GetPageText 1968
-#define wxListbook_GetSelection 1969
-#define wxListbook_HitTest 1971
-#define wxListbook_InsertPage 1972
-#define wxListbook_SetImageList 1973
-#define wxListbook_SetPageSize 1974
-#define wxListbook_SetPageImage 1975
-#define wxListbook_SetPageText 1976
-#define wxListbook_SetSelection 1977
-#define wxListbook_ChangeSelection 1978
-#define wxListbook_destroy 1979
-#define wxTreebook_new_0 1980
-#define wxTreebook_new_3 1981
-#define wxTreebook_AddPage 1982
-#define wxTreebook_AdvanceSelection 1983
-#define wxTreebook_AssignImageList 1984
-#define wxTreebook_Create 1985
-#define wxTreebook_DeleteAllPages 1986
-#define wxTreebook_DeletePage 1987
-#define wxTreebook_RemovePage 1988
-#define wxTreebook_GetCurrentPage 1989
-#define wxTreebook_GetImageList 1990
-#define wxTreebook_GetPage 1992
-#define wxTreebook_GetPageCount 1993
-#define wxTreebook_GetPageImage 1994
-#define wxTreebook_GetPageText 1995
-#define wxTreebook_GetSelection 1996
-#define wxTreebook_ExpandNode 1997
-#define wxTreebook_IsNodeExpanded 1998
-#define wxTreebook_HitTest 2000
-#define wxTreebook_InsertPage 2001
-#define wxTreebook_InsertSubPage 2002
-#define wxTreebook_SetImageList 2003
-#define wxTreebook_SetPageSize 2004
-#define wxTreebook_SetPageImage 2005
-#define wxTreebook_SetPageText 2006
-#define wxTreebook_SetSelection 2007
-#define wxTreebook_ChangeSelection 2008
-#define wxTreebook_destroy 2009
-#define wxTreeCtrl_new_2 2012
-#define wxTreeCtrl_new_0 2013
-#define wxTreeCtrl_destruct 2015
-#define wxTreeCtrl_AddRoot 2016
-#define wxTreeCtrl_AppendItem 2017
-#define wxTreeCtrl_AssignImageList 2018
-#define wxTreeCtrl_AssignStateImageList 2019
-#define wxTreeCtrl_Collapse 2020
-#define wxTreeCtrl_CollapseAndReset 2021
-#define wxTreeCtrl_Create 2022
-#define wxTreeCtrl_Delete 2023
-#define wxTreeCtrl_DeleteAllItems 2024
-#define wxTreeCtrl_DeleteChildren 2025
-#define wxTreeCtrl_EditLabel 2026
-#define wxTreeCtrl_EnsureVisible 2027
-#define wxTreeCtrl_Expand 2028
-#define wxTreeCtrl_GetBoundingRect 2029
-#define wxTreeCtrl_GetChildrenCount 2031
-#define wxTreeCtrl_GetCount 2032
-#define wxTreeCtrl_GetEditControl 2033
-#define wxTreeCtrl_GetFirstChild 2034
-#define wxTreeCtrl_GetNextChild 2035
-#define wxTreeCtrl_GetFirstVisibleItem 2036
-#define wxTreeCtrl_GetImageList 2037
-#define wxTreeCtrl_GetIndent 2038
-#define wxTreeCtrl_GetItemBackgroundColour 2039
-#define wxTreeCtrl_GetItemData 2040
-#define wxTreeCtrl_GetItemFont 2041
-#define wxTreeCtrl_GetItemImage_1 2042
-#define wxTreeCtrl_GetItemImage_2 2043
-#define wxTreeCtrl_GetItemText 2044
-#define wxTreeCtrl_GetItemTextColour 2045
-#define wxTreeCtrl_GetLastChild 2046
-#define wxTreeCtrl_GetNextSibling 2047
-#define wxTreeCtrl_GetNextVisible 2048
-#define wxTreeCtrl_GetItemParent 2049
-#define wxTreeCtrl_GetPrevSibling 2050
-#define wxTreeCtrl_GetPrevVisible 2051
-#define wxTreeCtrl_GetRootItem 2052
-#define wxTreeCtrl_GetSelection 2053
-#define wxTreeCtrl_GetSelections 2054
-#define wxTreeCtrl_GetStateImageList 2055
-#define wxTreeCtrl_HitTest 2056
-#define wxTreeCtrl_InsertItem 2058
-#define wxTreeCtrl_IsBold 2059
-#define wxTreeCtrl_IsExpanded 2060
-#define wxTreeCtrl_IsSelected 2061
-#define wxTreeCtrl_IsVisible 2062
-#define wxTreeCtrl_ItemHasChildren 2063
-#define wxTreeCtrl_IsTreeItemIdOk 2064
-#define wxTreeCtrl_PrependItem 2065
-#define wxTreeCtrl_ScrollTo 2066
-#define wxTreeCtrl_SelectItem_1 2067
-#define wxTreeCtrl_SelectItem_2 2068
-#define wxTreeCtrl_SetIndent 2069
-#define wxTreeCtrl_SetImageList 2070
-#define wxTreeCtrl_SetItemBackgroundColour 2071
-#define wxTreeCtrl_SetItemBold 2072
-#define wxTreeCtrl_SetItemData 2073
-#define wxTreeCtrl_SetItemDropHighlight 2074
-#define wxTreeCtrl_SetItemFont 2075
-#define wxTreeCtrl_SetItemHasChildren 2076
-#define wxTreeCtrl_SetItemImage_2 2077
-#define wxTreeCtrl_SetItemImage_3 2078
-#define wxTreeCtrl_SetItemText 2079
-#define wxTreeCtrl_SetItemTextColour 2080
-#define wxTreeCtrl_SetStateImageList 2081
-#define wxTreeCtrl_SetWindowStyle 2082
-#define wxTreeCtrl_SortChildren 2083
-#define wxTreeCtrl_Toggle 2084
-#define wxTreeCtrl_ToggleItemSelection 2085
-#define wxTreeCtrl_Unselect 2086
-#define wxTreeCtrl_UnselectAll 2087
-#define wxTreeCtrl_UnselectItem 2088
-#define wxScrollBar_new_0 2089
-#define wxScrollBar_new_3 2090
-#define wxScrollBar_destruct 2091
-#define wxScrollBar_Create 2092
-#define wxScrollBar_GetRange 2093
-#define wxScrollBar_GetPageSize 2094
-#define wxScrollBar_GetThumbPosition 2095
-#define wxScrollBar_GetThumbSize 2096
-#define wxScrollBar_SetThumbPosition 2097
-#define wxScrollBar_SetScrollbar 2098
-#define wxSpinButton_new_2 2100
-#define wxSpinButton_new_0 2101
-#define wxSpinButton_Create 2102
-#define wxSpinButton_GetMax 2103
-#define wxSpinButton_GetMin 2104
-#define wxSpinButton_GetValue 2105
-#define wxSpinButton_SetRange 2106
-#define wxSpinButton_SetValue 2107
-#define wxSpinButton_destroy 2108
-#define wxSpinCtrl_new_0 2109
-#define wxSpinCtrl_new_2 2110
-#define wxSpinCtrl_Create 2112
-#define wxSpinCtrl_SetValue_1_1 2115
-#define wxSpinCtrl_SetValue_1_0 2116
-#define wxSpinCtrl_GetValue 2118
-#define wxSpinCtrl_SetRange 2120
-#define wxSpinCtrl_SetSelection 2121
-#define wxSpinCtrl_GetMin 2123
-#define wxSpinCtrl_GetMax 2125
-#define wxSpinCtrl_destroy 2126
-#define wxStaticText_new_0 2127
-#define wxStaticText_new_4 2128
-#define wxStaticText_Create 2129
-#define wxStaticText_GetLabel 2130
-#define wxStaticText_SetLabel 2131
-#define wxStaticText_Wrap 2132
-#define wxStaticText_destroy 2133
-#define wxStaticBitmap_new_0 2134
-#define wxStaticBitmap_new_4 2135
-#define wxStaticBitmap_Create 2136
-#define wxStaticBitmap_GetBitmap 2137
-#define wxStaticBitmap_SetBitmap 2138
-#define wxStaticBitmap_destroy 2139
-#define wxRadioBox_new 2140
-#define wxRadioBox_destruct 2142
-#define wxRadioBox_Create 2143
-#define wxRadioBox_Enable_2 2144
-#define wxRadioBox_Enable_1 2145
-#define wxRadioBox_GetSelection 2146
-#define wxRadioBox_GetString 2147
-#define wxRadioBox_SetSelection 2148
-#define wxRadioBox_Show_2 2149
-#define wxRadioBox_Show_1 2150
-#define wxRadioBox_GetColumnCount 2151
-#define wxRadioBox_GetItemHelpText 2152
-#define wxRadioBox_GetItemToolTip 2153
-#define wxRadioBox_GetItemFromPoint 2155
-#define wxRadioBox_GetRowCount 2156
-#define wxRadioBox_IsItemEnabled 2157
-#define wxRadioBox_IsItemShown 2158
-#define wxRadioBox_SetItemHelpText 2159
-#define wxRadioBox_SetItemToolTip 2160
-#define wxRadioButton_new_0 2161
-#define wxRadioButton_new_4 2162
-#define wxRadioButton_Create 2163
-#define wxRadioButton_GetValue 2164
-#define wxRadioButton_SetValue 2165
-#define wxRadioButton_destroy 2166
-#define wxSlider_new_6 2168
-#define wxSlider_new_0 2169
-#define wxSlider_Create 2170
-#define wxSlider_GetLineSize 2171
-#define wxSlider_GetMax 2172
-#define wxSlider_GetMin 2173
-#define wxSlider_GetPageSize 2174
-#define wxSlider_GetThumbLength 2175
-#define wxSlider_GetValue 2176
-#define wxSlider_SetLineSize 2177
-#define wxSlider_SetPageSize 2178
-#define wxSlider_SetRange 2179
-#define wxSlider_SetThumbLength 2180
-#define wxSlider_SetValue 2181
-#define wxSlider_destroy 2182
-#define wxDialog_new_4 2184
-#define wxDialog_new_0 2185
-#define wxDialog_destruct 2187
-#define wxDialog_Create 2188
-#define wxDialog_CreateButtonSizer 2189
-#define wxDialog_CreateStdDialogButtonSizer 2190
-#define wxDialog_EndModal 2191
-#define wxDialog_GetAffirmativeId 2192
-#define wxDialog_GetReturnCode 2193
-#define wxDialog_IsModal 2194
-#define wxDialog_SetAffirmativeId 2195
-#define wxDialog_SetReturnCode 2196
-#define wxDialog_Show 2197
-#define wxDialog_ShowModal 2198
-#define wxColourDialog_new_0 2199
-#define wxColourDialog_new_2 2200
-#define wxColourDialog_destruct 2201
-#define wxColourDialog_Create 2202
-#define wxColourDialog_GetColourData 2203
-#define wxColourData_new_0 2204
-#define wxColourData_new_1 2205
-#define wxColourData_destruct 2206
-#define wxColourData_GetChooseFull 2207
-#define wxColourData_GetColour 2208
-#define wxColourData_GetCustomColour 2210
-#define wxColourData_SetChooseFull 2211
-#define wxColourData_SetColour 2212
-#define wxColourData_SetCustomColour 2213
-#define wxPalette_new_0 2214
-#define wxPalette_new_4 2215
-#define wxPalette_destruct 2217
-#define wxPalette_Create 2218
-#define wxPalette_GetColoursCount 2219
-#define wxPalette_GetPixel 2220
-#define wxPalette_GetRGB 2221
-#define wxPalette_IsOk 2222
-#define wxDirDialog_new 2226
-#define wxDirDialog_destruct 2227
-#define wxDirDialog_GetPath 2228
-#define wxDirDialog_GetMessage 2229
-#define wxDirDialog_SetMessage 2230
-#define wxDirDialog_SetPath 2231
-#define wxFileDialog_new 2235
-#define wxFileDialog_destruct 2236
-#define wxFileDialog_GetDirectory 2237
-#define wxFileDialog_GetFilename 2238
-#define wxFileDialog_GetFilenames 2239
-#define wxFileDialog_GetFilterIndex 2240
-#define wxFileDialog_GetMessage 2241
-#define wxFileDialog_GetPath 2242
-#define wxFileDialog_GetPaths 2243
-#define wxFileDialog_GetWildcard 2244
-#define wxFileDialog_SetDirectory 2245
-#define wxFileDialog_SetFilename 2246
-#define wxFileDialog_SetFilterIndex 2247
-#define wxFileDialog_SetMessage 2248
-#define wxFileDialog_SetPath 2249
-#define wxFileDialog_SetWildcard 2250
-#define wxPickerBase_SetInternalMargin 2251
-#define wxPickerBase_GetInternalMargin 2252
-#define wxPickerBase_SetTextCtrlProportion 2253
-#define wxPickerBase_SetPickerCtrlProportion 2254
-#define wxPickerBase_GetTextCtrlProportion 2255
-#define wxPickerBase_GetPickerCtrlProportion 2256
-#define wxPickerBase_HasTextCtrl 2257
-#define wxPickerBase_GetTextCtrl 2258
-#define wxPickerBase_IsTextCtrlGrowable 2259
-#define wxPickerBase_SetPickerCtrlGrowable 2260
-#define wxPickerBase_SetTextCtrlGrowable 2261
-#define wxPickerBase_IsPickerCtrlGrowable 2262
-#define wxFilePickerCtrl_new_0 2263
-#define wxFilePickerCtrl_new_3 2264
-#define wxFilePickerCtrl_Create 2265
-#define wxFilePickerCtrl_GetPath 2266
-#define wxFilePickerCtrl_SetPath 2267
-#define wxFilePickerCtrl_destroy 2268
-#define wxDirPickerCtrl_new_0 2269
-#define wxDirPickerCtrl_new_3 2270
-#define wxDirPickerCtrl_Create 2271
-#define wxDirPickerCtrl_GetPath 2272
-#define wxDirPickerCtrl_SetPath 2273
-#define wxDirPickerCtrl_destroy 2274
-#define wxColourPickerCtrl_new_0 2275
-#define wxColourPickerCtrl_new_3 2276
-#define wxColourPickerCtrl_Create 2277
-#define wxColourPickerCtrl_GetColour 2278
-#define wxColourPickerCtrl_SetColour_1_1 2279
-#define wxColourPickerCtrl_SetColour_1_0 2280
-#define wxColourPickerCtrl_destroy 2281
-#define wxDatePickerCtrl_new_0 2282
-#define wxDatePickerCtrl_new_3 2283
-#define wxDatePickerCtrl_GetRange 2284
-#define wxDatePickerCtrl_GetValue 2285
-#define wxDatePickerCtrl_SetRange 2286
-#define wxDatePickerCtrl_SetValue 2287
-#define wxDatePickerCtrl_destroy 2288
-#define wxFontPickerCtrl_new_0 2289
-#define wxFontPickerCtrl_new_3 2290
-#define wxFontPickerCtrl_Create 2291
-#define wxFontPickerCtrl_GetSelectedFont 2292
-#define wxFontPickerCtrl_SetSelectedFont 2293
-#define wxFontPickerCtrl_GetMaxPointSize 2294
-#define wxFontPickerCtrl_SetMaxPointSize 2295
-#define wxFontPickerCtrl_destroy 2296
-#define wxFindReplaceDialog_new_0 2299
-#define wxFindReplaceDialog_new_4 2300
-#define wxFindReplaceDialog_destruct 2301
-#define wxFindReplaceDialog_Create 2302
-#define wxFindReplaceDialog_GetData 2303
-#define wxFindReplaceData_new_0 2304
-#define wxFindReplaceData_new_1 2305
-#define wxFindReplaceData_GetFindString 2306
-#define wxFindReplaceData_GetReplaceString 2307
-#define wxFindReplaceData_GetFlags 2308
-#define wxFindReplaceData_SetFlags 2309
-#define wxFindReplaceData_SetFindString 2310
-#define wxFindReplaceData_SetReplaceString 2311
-#define wxFindReplaceData_destroy 2312
-#define wxMultiChoiceDialog_new_0 2313
-#define wxMultiChoiceDialog_new_5 2315
-#define wxMultiChoiceDialog_GetSelections 2316
-#define wxMultiChoiceDialog_SetSelections 2317
-#define wxMultiChoiceDialog_destroy 2318
-#define wxSingleChoiceDialog_new_0 2319
-#define wxSingleChoiceDialog_new_5 2321
-#define wxSingleChoiceDialog_GetSelection 2322
-#define wxSingleChoiceDialog_GetStringSelection 2323
-#define wxSingleChoiceDialog_SetSelection 2324
-#define wxSingleChoiceDialog_destroy 2325
-#define wxTextEntryDialog_new 2326
-#define wxTextEntryDialog_GetValue 2327
-#define wxTextEntryDialog_SetValue 2328
-#define wxTextEntryDialog_destroy 2329
-#define wxPasswordEntryDialog_new 2330
-#define wxPasswordEntryDialog_destroy 2331
-#define wxFontData_new_0 2332
-#define wxFontData_new_1 2333
-#define wxFontData_destruct 2334
-#define wxFontData_EnableEffects 2335
-#define wxFontData_GetAllowSymbols 2336
-#define wxFontData_GetColour 2337
-#define wxFontData_GetChosenFont 2338
-#define wxFontData_GetEnableEffects 2339
-#define wxFontData_GetInitialFont 2340
-#define wxFontData_GetShowHelp 2341
-#define wxFontData_SetAllowSymbols 2342
-#define wxFontData_SetChosenFont 2343
-#define wxFontData_SetColour 2344
-#define wxFontData_SetInitialFont 2345
-#define wxFontData_SetRange 2346
-#define wxFontData_SetShowHelp 2347
-#define wxFontDialog_new_0 2351
-#define wxFontDialog_new_2 2353
-#define wxFontDialog_Create 2355
-#define wxFontDialog_GetFontData 2356
-#define wxFontDialog_destroy 2358
-#define wxProgressDialog_new 2359
-#define wxProgressDialog_destruct 2360
-#define wxProgressDialog_Resume 2361
-#define wxProgressDialog_Update_2 2362
-#define wxProgressDialog_Update_0 2363
-#define wxMessageDialog_new 2364
-#define wxMessageDialog_destruct 2365
-#define wxPageSetupDialog_new 2366
-#define wxPageSetupDialog_destruct 2367
-#define wxPageSetupDialog_GetPageSetupData 2368
-#define wxPageSetupDialog_ShowModal 2369
-#define wxPageSetupDialogData_new_0 2370
-#define wxPageSetupDialogData_new_1_0 2371
-#define wxPageSetupDialogData_new_1_1 2372
-#define wxPageSetupDialogData_destruct 2373
-#define wxPageSetupDialogData_EnableHelp 2374
-#define wxPageSetupDialogData_EnableMargins 2375
-#define wxPageSetupDialogData_EnableOrientation 2376
-#define wxPageSetupDialogData_EnablePaper 2377
-#define wxPageSetupDialogData_EnablePrinter 2378
-#define wxPageSetupDialogData_GetDefaultMinMargins 2379
-#define wxPageSetupDialogData_GetEnableMargins 2380
-#define wxPageSetupDialogData_GetEnableOrientation 2381
-#define wxPageSetupDialogData_GetEnablePaper 2382
-#define wxPageSetupDialogData_GetEnablePrinter 2383
-#define wxPageSetupDialogData_GetEnableHelp 2384
-#define wxPageSetupDialogData_GetDefaultInfo 2385
-#define wxPageSetupDialogData_GetMarginTopLeft 2386
-#define wxPageSetupDialogData_GetMarginBottomRight 2387
-#define wxPageSetupDialogData_GetMinMarginTopLeft 2388
-#define wxPageSetupDialogData_GetMinMarginBottomRight 2389
-#define wxPageSetupDialogData_GetPaperId 2390
-#define wxPageSetupDialogData_GetPaperSize 2391
-#define wxPageSetupDialogData_GetPrintData 2393
-#define wxPageSetupDialogData_IsOk 2394
-#define wxPageSetupDialogData_SetDefaultInfo 2395
-#define wxPageSetupDialogData_SetDefaultMinMargins 2396
-#define wxPageSetupDialogData_SetMarginTopLeft 2397
-#define wxPageSetupDialogData_SetMarginBottomRight 2398
-#define wxPageSetupDialogData_SetMinMarginTopLeft 2399
-#define wxPageSetupDialogData_SetMinMarginBottomRight 2400
-#define wxPageSetupDialogData_SetPaperId 2401
-#define wxPageSetupDialogData_SetPaperSize_1_1 2402
-#define wxPageSetupDialogData_SetPaperSize_1_0 2403
-#define wxPageSetupDialogData_SetPrintData 2404
-#define wxPrintDialog_new_2_0 2405
-#define wxPrintDialog_new_2_1 2406
-#define wxPrintDialog_destruct 2407
-#define wxPrintDialog_GetPrintDialogData 2408
-#define wxPrintDialog_GetPrintDC 2409
-#define wxPrintDialogData_new_0 2410
-#define wxPrintDialogData_new_1_1 2411
-#define wxPrintDialogData_new_1_0 2412
-#define wxPrintDialogData_destruct 2413
-#define wxPrintDialogData_EnableHelp 2414
-#define wxPrintDialogData_EnablePageNumbers 2415
-#define wxPrintDialogData_EnablePrintToFile 2416
-#define wxPrintDialogData_EnableSelection 2417
-#define wxPrintDialogData_GetAllPages 2418
-#define wxPrintDialogData_GetCollate 2419
-#define wxPrintDialogData_GetFromPage 2420
-#define wxPrintDialogData_GetMaxPage 2421
-#define wxPrintDialogData_GetMinPage 2422
-#define wxPrintDialogData_GetNoCopies 2423
-#define wxPrintDialogData_GetPrintData 2424
-#define wxPrintDialogData_GetPrintToFile 2425
-#define wxPrintDialogData_GetSelection 2426
-#define wxPrintDialogData_GetToPage 2427
-#define wxPrintDialogData_IsOk 2428
-#define wxPrintDialogData_SetCollate 2429
-#define wxPrintDialogData_SetFromPage 2430
-#define wxPrintDialogData_SetMaxPage 2431
-#define wxPrintDialogData_SetMinPage 2432
-#define wxPrintDialogData_SetNoCopies 2433
-#define wxPrintDialogData_SetPrintData 2434
-#define wxPrintDialogData_SetPrintToFile 2435
-#define wxPrintDialogData_SetSelection 2436
-#define wxPrintDialogData_SetToPage 2437
-#define wxPrintData_new_0 2438
-#define wxPrintData_new_1 2439
-#define wxPrintData_destruct 2440
-#define wxPrintData_GetCollate 2441
-#define wxPrintData_GetBin 2442
-#define wxPrintData_GetColour 2443
-#define wxPrintData_GetDuplex 2444
-#define wxPrintData_GetNoCopies 2445
-#define wxPrintData_GetOrientation 2446
-#define wxPrintData_GetPaperId 2447
-#define wxPrintData_GetPrinterName 2448
-#define wxPrintData_GetQuality 2449
-#define wxPrintData_IsOk 2450
-#define wxPrintData_SetBin 2451
-#define wxPrintData_SetCollate 2452
-#define wxPrintData_SetColour 2453
-#define wxPrintData_SetDuplex 2454
-#define wxPrintData_SetNoCopies 2455
-#define wxPrintData_SetOrientation 2456
-#define wxPrintData_SetPaperId 2457
-#define wxPrintData_SetPrinterName 2458
-#define wxPrintData_SetQuality 2459
-#define wxPrintPreview_new_2 2462
-#define wxPrintPreview_new_3 2463
-#define wxPrintPreview_destruct 2465
-#define wxPrintPreview_GetCanvas 2466
-#define wxPrintPreview_GetCurrentPage 2467
-#define wxPrintPreview_GetFrame 2468
-#define wxPrintPreview_GetMaxPage 2469
-#define wxPrintPreview_GetMinPage 2470
-#define wxPrintPreview_GetPrintout 2471
-#define wxPrintPreview_GetPrintoutForPrinting 2472
-#define wxPrintPreview_IsOk 2473
-#define wxPrintPreview_PaintPage 2474
-#define wxPrintPreview_Print 2475
-#define wxPrintPreview_RenderPage 2476
-#define wxPrintPreview_SetCanvas 2477
-#define wxPrintPreview_SetCurrentPage 2478
-#define wxPrintPreview_SetFrame 2479
-#define wxPrintPreview_SetPrintout 2480
-#define wxPrintPreview_SetZoom 2481
-#define wxPreviewFrame_new 2482
-#define wxPreviewFrame_destruct 2483
-#define wxPreviewFrame_CreateControlBar 2484
-#define wxPreviewFrame_CreateCanvas 2485
-#define wxPreviewFrame_Initialize 2486
-#define wxPreviewFrame_OnCloseWindow 2487
-#define wxPreviewControlBar_new 2488
-#define wxPreviewControlBar_destruct 2489
-#define wxPreviewControlBar_CreateButtons 2490
-#define wxPreviewControlBar_GetPrintPreview 2491
-#define wxPreviewControlBar_GetZoomControl 2492
-#define wxPreviewControlBar_SetZoomControl 2493
-#define wxPrinter_new 2495
-#define wxPrinter_CreateAbortWindow 2496
-#define wxPrinter_GetAbort 2497
-#define wxPrinter_GetLastError 2498
-#define wxPrinter_GetPrintDialogData 2499
-#define wxPrinter_Print 2500
-#define wxPrinter_PrintDialog 2501
-#define wxPrinter_ReportError 2502
-#define wxPrinter_Setup 2503
-#define wxPrinter_destroy 2504
-#define wxXmlResource_new_1 2505
-#define wxXmlResource_new_2 2506
-#define wxXmlResource_destruct 2507
-#define wxXmlResource_AttachUnknownControl 2508
-#define wxXmlResource_ClearHandlers 2509
-#define wxXmlResource_CompareVersion 2510
-#define wxXmlResource_Get 2511
-#define wxXmlResource_GetFlags 2512
-#define wxXmlResource_GetVersion 2513
-#define wxXmlResource_GetXRCID 2514
-#define wxXmlResource_InitAllHandlers 2515
-#define wxXmlResource_Load 2516
-#define wxXmlResource_LoadBitmap 2517
-#define wxXmlResource_LoadDialog_2 2518
-#define wxXmlResource_LoadDialog_3 2519
-#define wxXmlResource_LoadFrame_2 2520
-#define wxXmlResource_LoadFrame_3 2521
-#define wxXmlResource_LoadIcon 2522
-#define wxXmlResource_LoadMenu 2523
-#define wxXmlResource_LoadMenuBar_2 2524
-#define wxXmlResource_LoadMenuBar_1 2525
-#define wxXmlResource_LoadPanel_2 2526
-#define wxXmlResource_LoadPanel_3 2527
-#define wxXmlResource_LoadToolBar 2528
-#define wxXmlResource_Set 2529
-#define wxXmlResource_SetFlags 2530
-#define wxXmlResource_Unload 2531
-#define wxXmlResource_xrcctrl 2532
-#define wxHtmlEasyPrinting_new 2533
-#define wxHtmlEasyPrinting_destruct 2534
-#define wxHtmlEasyPrinting_GetPrintData 2535
-#define wxHtmlEasyPrinting_GetPageSetupData 2536
-#define wxHtmlEasyPrinting_PreviewFile 2537
-#define wxHtmlEasyPrinting_PreviewText 2538
-#define wxHtmlEasyPrinting_PrintFile 2539
-#define wxHtmlEasyPrinting_PrintText 2540
-#define wxHtmlEasyPrinting_PageSetup 2541
-#define wxHtmlEasyPrinting_SetFonts 2542
-#define wxHtmlEasyPrinting_SetHeader 2543
-#define wxHtmlEasyPrinting_SetFooter 2544
-#define wxGLCanvas_new_2 2546
-#define wxGLCanvas_new_3_1 2547
-#define wxGLCanvas_new_3_0 2548
-#define wxGLCanvas_GetContext 2549
-#define wxGLCanvas_SetCurrent 2551
-#define wxGLCanvas_SwapBuffers 2552
-#define wxGLCanvas_destroy 2553
-#define wxAuiManager_new 2554
-#define wxAuiManager_destruct 2555
-#define wxAuiManager_AddPane_2_1 2556
-#define wxAuiManager_AddPane_3 2557
-#define wxAuiManager_AddPane_2_0 2558
-#define wxAuiManager_DetachPane 2559
-#define wxAuiManager_GetAllPanes 2560
-#define wxAuiManager_GetArtProvider 2561
-#define wxAuiManager_GetDockSizeConstraint 2562
-#define wxAuiManager_GetFlags 2563
-#define wxAuiManager_GetManagedWindow 2564
-#define wxAuiManager_GetManager 2565
-#define wxAuiManager_GetPane_1_1 2566
-#define wxAuiManager_GetPane_1_0 2567
-#define wxAuiManager_HideHint 2568
-#define wxAuiManager_InsertPane 2569
-#define wxAuiManager_LoadPaneInfo 2570
-#define wxAuiManager_LoadPerspective 2571
-#define wxAuiManager_SavePaneInfo 2572
-#define wxAuiManager_SavePerspective 2573
-#define wxAuiManager_SetArtProvider 2574
-#define wxAuiManager_SetDockSizeConstraint 2575
-#define wxAuiManager_SetFlags 2576
-#define wxAuiManager_SetManagedWindow 2577
-#define wxAuiManager_ShowHint 2578
-#define wxAuiManager_UnInit 2579
-#define wxAuiManager_Update 2580
-#define wxAuiPaneInfo_new_0 2581
-#define wxAuiPaneInfo_new_1 2582
-#define wxAuiPaneInfo_destruct 2583
-#define wxAuiPaneInfo_BestSize_1 2584
-#define wxAuiPaneInfo_BestSize_2 2585
-#define wxAuiPaneInfo_Bottom 2586
-#define wxAuiPaneInfo_BottomDockable 2587
-#define wxAuiPaneInfo_Caption 2588
-#define wxAuiPaneInfo_CaptionVisible 2589
-#define wxAuiPaneInfo_Centre 2590
-#define wxAuiPaneInfo_CentrePane 2591
-#define wxAuiPaneInfo_CloseButton 2592
-#define wxAuiPaneInfo_DefaultPane 2593
-#define wxAuiPaneInfo_DestroyOnClose 2594
-#define wxAuiPaneInfo_Direction 2595
-#define wxAuiPaneInfo_Dock 2596
-#define wxAuiPaneInfo_Dockable 2597
-#define wxAuiPaneInfo_Fixed 2598
-#define wxAuiPaneInfo_Float 2599
-#define wxAuiPaneInfo_Floatable 2600
-#define wxAuiPaneInfo_FloatingPosition_1 2601
-#define wxAuiPaneInfo_FloatingPosition_2 2602
-#define wxAuiPaneInfo_FloatingSize_1 2603
-#define wxAuiPaneInfo_FloatingSize_2 2604
-#define wxAuiPaneInfo_Gripper 2605
-#define wxAuiPaneInfo_GripperTop 2606
-#define wxAuiPaneInfo_HasBorder 2607
-#define wxAuiPaneInfo_HasCaption 2608
-#define wxAuiPaneInfo_HasCloseButton 2609
-#define wxAuiPaneInfo_HasFlag 2610
-#define wxAuiPaneInfo_HasGripper 2611
-#define wxAuiPaneInfo_HasGripperTop 2612
-#define wxAuiPaneInfo_HasMaximizeButton 2613
-#define wxAuiPaneInfo_HasMinimizeButton 2614
-#define wxAuiPaneInfo_HasPinButton 2615
-#define wxAuiPaneInfo_Hide 2616
-#define wxAuiPaneInfo_IsBottomDockable 2617
-#define wxAuiPaneInfo_IsDocked 2618
-#define wxAuiPaneInfo_IsFixed 2619
-#define wxAuiPaneInfo_IsFloatable 2620
-#define wxAuiPaneInfo_IsFloating 2621
-#define wxAuiPaneInfo_IsLeftDockable 2622
-#define wxAuiPaneInfo_IsMovable 2623
-#define wxAuiPaneInfo_IsOk 2624
-#define wxAuiPaneInfo_IsResizable 2625
-#define wxAuiPaneInfo_IsRightDockable 2626
-#define wxAuiPaneInfo_IsShown 2627
-#define wxAuiPaneInfo_IsToolbar 2628
-#define wxAuiPaneInfo_IsTopDockable 2629
-#define wxAuiPaneInfo_Layer 2630
-#define wxAuiPaneInfo_Left 2631
-#define wxAuiPaneInfo_LeftDockable 2632
-#define wxAuiPaneInfo_MaxSize_1 2633
-#define wxAuiPaneInfo_MaxSize_2 2634
-#define wxAuiPaneInfo_MaximizeButton 2635
-#define wxAuiPaneInfo_MinSize_1 2636
-#define wxAuiPaneInfo_MinSize_2 2637
-#define wxAuiPaneInfo_MinimizeButton 2638
-#define wxAuiPaneInfo_Movable 2639
-#define wxAuiPaneInfo_Name 2640
-#define wxAuiPaneInfo_PaneBorder 2641
-#define wxAuiPaneInfo_PinButton 2642
-#define wxAuiPaneInfo_Position 2643
-#define wxAuiPaneInfo_Resizable 2644
-#define wxAuiPaneInfo_Right 2645
-#define wxAuiPaneInfo_RightDockable 2646
-#define wxAuiPaneInfo_Row 2647
-#define wxAuiPaneInfo_SafeSet 2648
-#define wxAuiPaneInfo_SetFlag 2649
-#define wxAuiPaneInfo_Show 2650
-#define wxAuiPaneInfo_ToolbarPane 2651
-#define wxAuiPaneInfo_Top 2652
-#define wxAuiPaneInfo_TopDockable 2653
-#define wxAuiPaneInfo_Window 2654
-#define wxAuiPaneInfo_GetWindow 2655
-#define wxAuiPaneInfo_GetFrame 2656
-#define wxAuiPaneInfo_GetDirection 2657
-#define wxAuiPaneInfo_GetLayer 2658
-#define wxAuiPaneInfo_GetRow 2659
-#define wxAuiPaneInfo_GetPosition 2660
-#define wxAuiPaneInfo_GetFloatingPosition 2661
-#define wxAuiPaneInfo_GetFloatingSize 2662
-#define wxAuiNotebook_new_0 2663
-#define wxAuiNotebook_new_2 2664
-#define wxAuiNotebook_AddPage 2665
-#define wxAuiNotebook_Create 2666
-#define wxAuiNotebook_DeletePage 2667
-#define wxAuiNotebook_GetArtProvider 2668
-#define wxAuiNotebook_GetPage 2669
-#define wxAuiNotebook_GetPageBitmap 2670
-#define wxAuiNotebook_GetPageCount 2671
-#define wxAuiNotebook_GetPageIndex 2672
-#define wxAuiNotebook_GetPageText 2673
-#define wxAuiNotebook_GetSelection 2674
-#define wxAuiNotebook_InsertPage 2675
-#define wxAuiNotebook_RemovePage 2676
-#define wxAuiNotebook_SetArtProvider 2677
-#define wxAuiNotebook_SetFont 2678
-#define wxAuiNotebook_SetPageBitmap 2679
-#define wxAuiNotebook_SetPageText 2680
-#define wxAuiNotebook_SetSelection 2681
-#define wxAuiNotebook_SetTabCtrlHeight 2682
-#define wxAuiNotebook_SetUniformBitmapSize 2683
-#define wxAuiNotebook_destroy 2684
-#define wxAuiTabArt_SetFlags 2685
-#define wxAuiTabArt_SetMeasuringFont 2686
-#define wxAuiTabArt_SetNormalFont 2687
-#define wxAuiTabArt_SetSelectedFont 2688
-#define wxAuiTabArt_SetColour 2689
-#define wxAuiTabArt_SetActiveColour 2690
-#define wxAuiDockArt_GetColour 2691
-#define wxAuiDockArt_GetFont 2692
-#define wxAuiDockArt_GetMetric 2693
-#define wxAuiDockArt_SetColour 2694
-#define wxAuiDockArt_SetFont 2695
-#define wxAuiDockArt_SetMetric 2696
-#define wxAuiSimpleTabArt_new 2697
-#define wxAuiSimpleTabArt_destroy 2698
-#define wxMDIParentFrame_new_0 2699
-#define wxMDIParentFrame_new_4 2700
-#define wxMDIParentFrame_destruct 2701
-#define wxMDIParentFrame_ActivateNext 2702
-#define wxMDIParentFrame_ActivatePrevious 2703
-#define wxMDIParentFrame_ArrangeIcons 2704
-#define wxMDIParentFrame_Cascade 2705
-#define wxMDIParentFrame_Create 2706
-#define wxMDIParentFrame_GetActiveChild 2707
-#define wxMDIParentFrame_GetClientWindow 2708
-#define wxMDIParentFrame_Tile 2709
-#define wxMDIChildFrame_new_0 2710
-#define wxMDIChildFrame_new_4 2711
-#define wxMDIChildFrame_destruct 2712
-#define wxMDIChildFrame_Activate 2713
-#define wxMDIChildFrame_Create 2714
-#define wxMDIChildFrame_Maximize 2715
-#define wxMDIChildFrame_Restore 2716
-#define wxMDIClientWindow_new_0 2717
-#define wxMDIClientWindow_new_2 2718
-#define wxMDIClientWindow_destruct 2719
-#define wxMDIClientWindow_CreateClient 2720
-#define wxLayoutAlgorithm_new 2721
-#define wxLayoutAlgorithm_LayoutFrame 2722
-#define wxLayoutAlgorithm_LayoutMDIFrame 2723
-#define wxLayoutAlgorithm_LayoutWindow 2724
-#define wxLayoutAlgorithm_destroy 2725
-#define wxEvent_GetId 2726
-#define wxEvent_GetSkipped 2727
-#define wxEvent_GetTimestamp 2728
-#define wxEvent_IsCommandEvent 2729
-#define wxEvent_ResumePropagation 2730
-#define wxEvent_ShouldPropagate 2731
-#define wxEvent_Skip 2732
-#define wxEvent_StopPropagation 2733
-#define wxCommandEvent_getClientData 2734
-#define wxCommandEvent_GetExtraLong 2735
-#define wxCommandEvent_GetInt 2736
-#define wxCommandEvent_GetSelection 2737
-#define wxCommandEvent_GetString 2738
-#define wxCommandEvent_IsChecked 2739
-#define wxCommandEvent_IsSelection 2740
-#define wxCommandEvent_SetInt 2741
-#define wxCommandEvent_SetString 2742
-#define wxScrollEvent_GetOrientation 2743
-#define wxScrollEvent_GetPosition 2744
-#define wxScrollWinEvent_GetOrientation 2745
-#define wxScrollWinEvent_GetPosition 2746
-#define wxMouseEvent_AltDown 2747
-#define wxMouseEvent_Button 2748
-#define wxMouseEvent_ButtonDClick 2749
-#define wxMouseEvent_ButtonDown 2750
-#define wxMouseEvent_ButtonUp 2751
-#define wxMouseEvent_CmdDown 2752
-#define wxMouseEvent_ControlDown 2753
-#define wxMouseEvent_Dragging 2754
-#define wxMouseEvent_Entering 2755
-#define wxMouseEvent_GetButton 2756
-#define wxMouseEvent_GetPosition 2759
-#define wxMouseEvent_GetLogicalPosition 2760
-#define wxMouseEvent_GetLinesPerAction 2761
-#define wxMouseEvent_GetWheelRotation 2762
-#define wxMouseEvent_GetWheelDelta 2763
-#define wxMouseEvent_GetX 2764
-#define wxMouseEvent_GetY 2765
-#define wxMouseEvent_IsButton 2766
-#define wxMouseEvent_IsPageScroll 2767
-#define wxMouseEvent_Leaving 2768
-#define wxMouseEvent_LeftDClick 2769
-#define wxMouseEvent_LeftDown 2770
-#define wxMouseEvent_LeftIsDown 2771
-#define wxMouseEvent_LeftUp 2772
-#define wxMouseEvent_MetaDown 2773
-#define wxMouseEvent_MiddleDClick 2774
-#define wxMouseEvent_MiddleDown 2775
-#define wxMouseEvent_MiddleIsDown 2776
-#define wxMouseEvent_MiddleUp 2777
-#define wxMouseEvent_Moving 2778
-#define wxMouseEvent_RightDClick 2779
-#define wxMouseEvent_RightDown 2780
-#define wxMouseEvent_RightIsDown 2781
-#define wxMouseEvent_RightUp 2782
-#define wxMouseEvent_ShiftDown 2783
-#define wxSetCursorEvent_GetCursor 2784
-#define wxSetCursorEvent_GetX 2785
-#define wxSetCursorEvent_GetY 2786
-#define wxSetCursorEvent_HasCursor 2787
-#define wxSetCursorEvent_SetCursor 2788
-#define wxKeyEvent_AltDown 2789
-#define wxKeyEvent_CmdDown 2790
-#define wxKeyEvent_ControlDown 2791
-#define wxKeyEvent_GetKeyCode 2792
-#define wxKeyEvent_GetModifiers 2793
-#define wxKeyEvent_GetPosition 2796
-#define wxKeyEvent_GetRawKeyCode 2797
-#define wxKeyEvent_GetRawKeyFlags 2798
-#define wxKeyEvent_GetUnicodeKey 2799
-#define wxKeyEvent_GetX 2800
-#define wxKeyEvent_GetY 2801
-#define wxKeyEvent_HasModifiers 2802
-#define wxKeyEvent_MetaDown 2803
-#define wxKeyEvent_ShiftDown 2804
-#define wxSizeEvent_GetSize 2805
-#define wxMoveEvent_GetPosition 2806
-#define wxEraseEvent_GetDC 2807
-#define wxFocusEvent_GetWindow 2808
-#define wxChildFocusEvent_GetWindow 2809
-#define wxMenuEvent_GetMenu 2810
-#define wxMenuEvent_GetMenuId 2811
-#define wxMenuEvent_IsPopup 2812
-#define wxCloseEvent_CanVeto 2813
-#define wxCloseEvent_GetLoggingOff 2814
-#define wxCloseEvent_SetCanVeto 2815
-#define wxCloseEvent_SetLoggingOff 2816
-#define wxCloseEvent_Veto 2817
-#define wxShowEvent_SetShow 2818
-#define wxShowEvent_GetShow 2819
-#define wxIconizeEvent_Iconized 2820
-#define wxJoystickEvent_ButtonDown 2821
-#define wxJoystickEvent_ButtonIsDown 2822
-#define wxJoystickEvent_ButtonUp 2823
-#define wxJoystickEvent_GetButtonChange 2824
-#define wxJoystickEvent_GetButtonState 2825
-#define wxJoystickEvent_GetJoystick 2826
-#define wxJoystickEvent_GetPosition 2827
-#define wxJoystickEvent_GetZPosition 2828
-#define wxJoystickEvent_IsButton 2829
-#define wxJoystickEvent_IsMove 2830
-#define wxJoystickEvent_IsZMove 2831
-#define wxUpdateUIEvent_CanUpdate 2832
-#define wxUpdateUIEvent_Check 2833
-#define wxUpdateUIEvent_Enable 2834
-#define wxUpdateUIEvent_Show 2835
-#define wxUpdateUIEvent_GetChecked 2836
-#define wxUpdateUIEvent_GetEnabled 2837
-#define wxUpdateUIEvent_GetShown 2838
-#define wxUpdateUIEvent_GetSetChecked 2839
-#define wxUpdateUIEvent_GetSetEnabled 2840
-#define wxUpdateUIEvent_GetSetShown 2841
-#define wxUpdateUIEvent_GetSetText 2842
-#define wxUpdateUIEvent_GetText 2843
-#define wxUpdateUIEvent_GetMode 2844
-#define wxUpdateUIEvent_GetUpdateInterval 2845
-#define wxUpdateUIEvent_ResetUpdateTime 2846
-#define wxUpdateUIEvent_SetMode 2847
-#define wxUpdateUIEvent_SetText 2848
-#define wxUpdateUIEvent_SetUpdateInterval 2849
-#define wxMouseCaptureChangedEvent_GetCapturedWindow 2850
-#define wxPaletteChangedEvent_SetChangedWindow 2851
-#define wxPaletteChangedEvent_GetChangedWindow 2852
-#define wxQueryNewPaletteEvent_SetPaletteRealized 2853
-#define wxQueryNewPaletteEvent_GetPaletteRealized 2854
-#define wxNavigationKeyEvent_GetDirection 2855
-#define wxNavigationKeyEvent_SetDirection 2856
-#define wxNavigationKeyEvent_IsWindowChange 2857
-#define wxNavigationKeyEvent_SetWindowChange 2858
-#define wxNavigationKeyEvent_IsFromTab 2859
-#define wxNavigationKeyEvent_SetFromTab 2860
-#define wxNavigationKeyEvent_GetCurrentFocus 2861
-#define wxNavigationKeyEvent_SetCurrentFocus 2862
-#define wxHelpEvent_GetOrigin 2863
-#define wxHelpEvent_GetPosition 2864
-#define wxHelpEvent_SetOrigin 2865
-#define wxHelpEvent_SetPosition 2866
-#define wxContextMenuEvent_GetPosition 2867
-#define wxContextMenuEvent_SetPosition 2868
-#define wxIdleEvent_CanSend 2869
-#define wxIdleEvent_GetMode 2870
-#define wxIdleEvent_RequestMore 2871
-#define wxIdleEvent_MoreRequested 2872
-#define wxIdleEvent_SetMode 2873
-#define wxGridEvent_AltDown 2874
-#define wxGridEvent_ControlDown 2875
-#define wxGridEvent_GetCol 2876
-#define wxGridEvent_GetPosition 2877
-#define wxGridEvent_GetRow 2878
-#define wxGridEvent_MetaDown 2879
-#define wxGridEvent_Selecting 2880
-#define wxGridEvent_ShiftDown 2881
-#define wxNotifyEvent_Allow 2882
-#define wxNotifyEvent_IsAllowed 2883
-#define wxNotifyEvent_Veto 2884
-#define wxSashEvent_GetEdge 2885
-#define wxSashEvent_GetDragRect 2886
-#define wxSashEvent_GetDragStatus 2887
-#define wxListEvent_GetCacheFrom 2888
-#define wxListEvent_GetCacheTo 2889
-#define wxListEvent_GetKeyCode 2890
-#define wxListEvent_GetIndex 2891
-#define wxListEvent_GetColumn 2892
-#define wxListEvent_GetPoint 2893
-#define wxListEvent_GetLabel 2894
-#define wxListEvent_GetText 2895
-#define wxListEvent_GetImage 2896
-#define wxListEvent_GetData 2897
-#define wxListEvent_GetMask 2898
-#define wxListEvent_GetItem 2899
-#define wxListEvent_IsEditCancelled 2900
-#define wxDateEvent_GetDate 2901
-#define wxCalendarEvent_GetWeekDay 2902
-#define wxFileDirPickerEvent_GetPath 2903
-#define wxColourPickerEvent_GetColour 2904
-#define wxFontPickerEvent_GetFont 2905
-#define wxStyledTextEvent_GetPosition 2906
-#define wxStyledTextEvent_GetKey 2907
-#define wxStyledTextEvent_GetModifiers 2908
-#define wxStyledTextEvent_GetModificationType 2909
-#define wxStyledTextEvent_GetText 2910
-#define wxStyledTextEvent_GetLength 2911
-#define wxStyledTextEvent_GetLinesAdded 2912
-#define wxStyledTextEvent_GetLine 2913
-#define wxStyledTextEvent_GetFoldLevelNow 2914
-#define wxStyledTextEvent_GetFoldLevelPrev 2915
-#define wxStyledTextEvent_GetMargin 2916
-#define wxStyledTextEvent_GetMessage 2917
-#define wxStyledTextEvent_GetWParam 2918
-#define wxStyledTextEvent_GetLParam 2919
-#define wxStyledTextEvent_GetListType 2920
-#define wxStyledTextEvent_GetX 2921
-#define wxStyledTextEvent_GetY 2922
-#define wxStyledTextEvent_GetDragText 2923
-#define wxStyledTextEvent_GetDragAllowMove 2924
-#define wxStyledTextEvent_GetDragResult 2925
-#define wxStyledTextEvent_GetShift 2926
-#define wxStyledTextEvent_GetControl 2927
-#define wxStyledTextEvent_GetAlt 2928
-#define utils_wxGetKeyState 2929
-#define utils_wxGetMousePosition 2930
-#define utils_wxGetMouseState 2931
-#define utils_wxSetDetectableAutoRepeat 2932
-#define utils_wxBell 2933
-#define utils_wxFindMenuItemId 2934
-#define utils_wxGenericFindWindowAtPoint 2935
-#define utils_wxFindWindowAtPoint 2936
-#define utils_wxBeginBusyCursor 2937
-#define utils_wxEndBusyCursor 2938
-#define utils_wxIsBusy 2939
-#define utils_wxShutdown 2940
-#define utils_wxShell 2941
-#define utils_wxLaunchDefaultBrowser 2942
-#define utils_wxGetEmailAddress 2943
-#define utils_wxGetUserId 2944
-#define utils_wxGetHomeDir 2945
-#define utils_wxNewId 2946
-#define utils_wxRegisterId 2947
-#define utils_wxGetCurrentId 2948
-#define utils_wxGetOsDescription 2949
-#define utils_wxIsPlatformLittleEndian 2950
-#define utils_wxIsPlatform64Bit 2951
-#define gdicmn_wxDisplaySize 2952
-#define gdicmn_wxSetCursor 2953
-#define wxPrintout_new 2954
-#define wxPrintout_destruct 2955
-#define wxPrintout_GetDC 2956
-#define wxPrintout_GetPageSizeMM 2957
-#define wxPrintout_GetPageSizePixels 2958
-#define wxPrintout_GetPaperRectPixels 2959
-#define wxPrintout_GetPPIPrinter 2960
-#define wxPrintout_GetPPIScreen 2961
-#define wxPrintout_GetTitle 2962
-#define wxPrintout_IsPreview 2963
-#define wxPrintout_FitThisSizeToPaper 2964
-#define wxPrintout_FitThisSizeToPage 2965
-#define wxPrintout_FitThisSizeToPageMargins 2966
-#define wxPrintout_MapScreenSizeToPaper 2967
-#define wxPrintout_MapScreenSizeToPage 2968
-#define wxPrintout_MapScreenSizeToPageMargins 2969
-#define wxPrintout_MapScreenSizeToDevice 2970
-#define wxPrintout_GetLogicalPaperRect 2971
-#define wxPrintout_GetLogicalPageRect 2972
-#define wxPrintout_GetLogicalPageMarginsRect 2973
-#define wxPrintout_SetLogicalOrigin 2974
-#define wxPrintout_OffsetLogicalOrigin 2975
-#define wxStyledTextCtrl_new_2 2976
-#define wxStyledTextCtrl_new_0 2977
-#define wxStyledTextCtrl_destruct 2978
-#define wxStyledTextCtrl_Create 2979
-#define wxStyledTextCtrl_AddText 2980
-#define wxStyledTextCtrl_AddStyledText 2981
-#define wxStyledTextCtrl_InsertText 2982
-#define wxStyledTextCtrl_ClearAll 2983
-#define wxStyledTextCtrl_ClearDocumentStyle 2984
-#define wxStyledTextCtrl_GetLength 2985
-#define wxStyledTextCtrl_GetCharAt 2986
-#define wxStyledTextCtrl_GetCurrentPos 2987
-#define wxStyledTextCtrl_GetAnchor 2988
-#define wxStyledTextCtrl_GetStyleAt 2989
-#define wxStyledTextCtrl_Redo 2990
-#define wxStyledTextCtrl_SetUndoCollection 2991
-#define wxStyledTextCtrl_SelectAll 2992
-#define wxStyledTextCtrl_SetSavePoint 2993
-#define wxStyledTextCtrl_GetStyledText 2994
-#define wxStyledTextCtrl_CanRedo 2995
-#define wxStyledTextCtrl_MarkerLineFromHandle 2996
-#define wxStyledTextCtrl_MarkerDeleteHandle 2997
-#define wxStyledTextCtrl_GetUndoCollection 2998
-#define wxStyledTextCtrl_GetViewWhiteSpace 2999
-#define wxStyledTextCtrl_SetViewWhiteSpace 3000
-#define wxStyledTextCtrl_PositionFromPoint 3001
-#define wxStyledTextCtrl_PositionFromPointClose 3002
-#define wxStyledTextCtrl_GotoLine 3003
-#define wxStyledTextCtrl_GotoPos 3004
-#define wxStyledTextCtrl_SetAnchor 3005
-#define wxStyledTextCtrl_GetCurLine 3006
-#define wxStyledTextCtrl_GetEndStyled 3007
-#define wxStyledTextCtrl_ConvertEOLs 3008
-#define wxStyledTextCtrl_GetEOLMode 3009
-#define wxStyledTextCtrl_SetEOLMode 3010
-#define wxStyledTextCtrl_StartStyling 3011
-#define wxStyledTextCtrl_SetStyling 3012
-#define wxStyledTextCtrl_GetBufferedDraw 3013
-#define wxStyledTextCtrl_SetBufferedDraw 3014
-#define wxStyledTextCtrl_SetTabWidth 3015
-#define wxStyledTextCtrl_GetTabWidth 3016
-#define wxStyledTextCtrl_SetCodePage 3017
-#define wxStyledTextCtrl_MarkerDefine 3018
-#define wxStyledTextCtrl_MarkerSetForeground 3019
-#define wxStyledTextCtrl_MarkerSetBackground 3020
-#define wxStyledTextCtrl_MarkerAdd 3021
-#define wxStyledTextCtrl_MarkerDelete 3022
-#define wxStyledTextCtrl_MarkerDeleteAll 3023
-#define wxStyledTextCtrl_MarkerGet 3024
-#define wxStyledTextCtrl_MarkerNext 3025
-#define wxStyledTextCtrl_MarkerPrevious 3026
-#define wxStyledTextCtrl_MarkerDefineBitmap 3027
-#define wxStyledTextCtrl_MarkerAddSet 3028
-#define wxStyledTextCtrl_MarkerSetAlpha 3029
-#define wxStyledTextCtrl_SetMarginType 3030
-#define wxStyledTextCtrl_GetMarginType 3031
-#define wxStyledTextCtrl_SetMarginWidth 3032
-#define wxStyledTextCtrl_GetMarginWidth 3033
-#define wxStyledTextCtrl_SetMarginMask 3034
-#define wxStyledTextCtrl_GetMarginMask 3035
-#define wxStyledTextCtrl_SetMarginSensitive 3036
-#define wxStyledTextCtrl_GetMarginSensitive 3037
-#define wxStyledTextCtrl_StyleClearAll 3038
-#define wxStyledTextCtrl_StyleSetForeground 3039
-#define wxStyledTextCtrl_StyleSetBackground 3040
-#define wxStyledTextCtrl_StyleSetBold 3041
-#define wxStyledTextCtrl_StyleSetItalic 3042
-#define wxStyledTextCtrl_StyleSetSize 3043
-#define wxStyledTextCtrl_StyleSetFaceName 3044
-#define wxStyledTextCtrl_StyleSetEOLFilled 3045
-#define wxStyledTextCtrl_StyleResetDefault 3046
-#define wxStyledTextCtrl_StyleSetUnderline 3047
-#define wxStyledTextCtrl_StyleSetCase 3048
-#define wxStyledTextCtrl_StyleSetHotSpot 3049
-#define wxStyledTextCtrl_SetSelForeground 3050
-#define wxStyledTextCtrl_SetSelBackground 3051
-#define wxStyledTextCtrl_GetSelAlpha 3052
-#define wxStyledTextCtrl_SetSelAlpha 3053
-#define wxStyledTextCtrl_SetCaretForeground 3054
-#define wxStyledTextCtrl_CmdKeyAssign 3055
-#define wxStyledTextCtrl_CmdKeyClear 3056
-#define wxStyledTextCtrl_CmdKeyClearAll 3057
-#define wxStyledTextCtrl_SetStyleBytes 3058
-#define wxStyledTextCtrl_StyleSetVisible 3059
-#define wxStyledTextCtrl_GetCaretPeriod 3060
-#define wxStyledTextCtrl_SetCaretPeriod 3061
-#define wxStyledTextCtrl_SetWordChars 3062
-#define wxStyledTextCtrl_BeginUndoAction 3063
-#define wxStyledTextCtrl_EndUndoAction 3064
-#define wxStyledTextCtrl_IndicatorSetStyle 3065
-#define wxStyledTextCtrl_IndicatorGetStyle 3066
-#define wxStyledTextCtrl_IndicatorSetForeground 3067
-#define wxStyledTextCtrl_IndicatorGetForeground 3068
-#define wxStyledTextCtrl_SetWhitespaceForeground 3069
-#define wxStyledTextCtrl_SetWhitespaceBackground 3070
-#define wxStyledTextCtrl_GetStyleBits 3071
-#define wxStyledTextCtrl_SetLineState 3072
-#define wxStyledTextCtrl_GetLineState 3073
-#define wxStyledTextCtrl_GetMaxLineState 3074
-#define wxStyledTextCtrl_GetCaretLineVisible 3075
-#define wxStyledTextCtrl_SetCaretLineVisible 3076
-#define wxStyledTextCtrl_GetCaretLineBackground 3077
-#define wxStyledTextCtrl_SetCaretLineBackground 3078
-#define wxStyledTextCtrl_AutoCompShow 3079
-#define wxStyledTextCtrl_AutoCompCancel 3080
-#define wxStyledTextCtrl_AutoCompActive 3081
-#define wxStyledTextCtrl_AutoCompPosStart 3082
-#define wxStyledTextCtrl_AutoCompComplete 3083
-#define wxStyledTextCtrl_AutoCompStops 3084
-#define wxStyledTextCtrl_AutoCompSetSeparator 3085
-#define wxStyledTextCtrl_AutoCompGetSeparator 3086
-#define wxStyledTextCtrl_AutoCompSelect 3087
-#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3088
-#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3089
-#define wxStyledTextCtrl_AutoCompSetFillUps 3090
-#define wxStyledTextCtrl_AutoCompSetChooseSingle 3091
-#define wxStyledTextCtrl_AutoCompGetChooseSingle 3092
-#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3093
-#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3094
-#define wxStyledTextCtrl_UserListShow 3095
-#define wxStyledTextCtrl_AutoCompSetAutoHide 3096
-#define wxStyledTextCtrl_AutoCompGetAutoHide 3097
-#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3098
-#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3099
-#define wxStyledTextCtrl_RegisterImage 3100
-#define wxStyledTextCtrl_ClearRegisteredImages 3101
-#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3102
-#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3103
-#define wxStyledTextCtrl_AutoCompSetMaxWidth 3104
-#define wxStyledTextCtrl_AutoCompGetMaxWidth 3105
-#define wxStyledTextCtrl_AutoCompSetMaxHeight 3106
-#define wxStyledTextCtrl_AutoCompGetMaxHeight 3107
-#define wxStyledTextCtrl_SetIndent 3108
-#define wxStyledTextCtrl_GetIndent 3109
-#define wxStyledTextCtrl_SetUseTabs 3110
-#define wxStyledTextCtrl_GetUseTabs 3111
-#define wxStyledTextCtrl_SetLineIndentation 3112
-#define wxStyledTextCtrl_GetLineIndentation 3113
-#define wxStyledTextCtrl_GetLineIndentPosition 3114
-#define wxStyledTextCtrl_GetColumn 3115
-#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3116
-#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3117
-#define wxStyledTextCtrl_SetIndentationGuides 3118
-#define wxStyledTextCtrl_GetIndentationGuides 3119
-#define wxStyledTextCtrl_SetHighlightGuide 3120
-#define wxStyledTextCtrl_GetHighlightGuide 3121
-#define wxStyledTextCtrl_GetLineEndPosition 3122
-#define wxStyledTextCtrl_GetCodePage 3123
-#define wxStyledTextCtrl_GetCaretForeground 3124
-#define wxStyledTextCtrl_GetReadOnly 3125
-#define wxStyledTextCtrl_SetCurrentPos 3126
-#define wxStyledTextCtrl_SetSelectionStart 3127
-#define wxStyledTextCtrl_GetSelectionStart 3128
-#define wxStyledTextCtrl_SetSelectionEnd 3129
-#define wxStyledTextCtrl_GetSelectionEnd 3130
-#define wxStyledTextCtrl_SetPrintMagnification 3131
-#define wxStyledTextCtrl_GetPrintMagnification 3132
-#define wxStyledTextCtrl_SetPrintColourMode 3133
-#define wxStyledTextCtrl_GetPrintColourMode 3134
-#define wxStyledTextCtrl_FindText 3135
-#define wxStyledTextCtrl_FormatRange 3136
-#define wxStyledTextCtrl_GetFirstVisibleLine 3137
-#define wxStyledTextCtrl_GetLine 3138
-#define wxStyledTextCtrl_GetLineCount 3139
-#define wxStyledTextCtrl_SetMarginLeft 3140
-#define wxStyledTextCtrl_GetMarginLeft 3141
-#define wxStyledTextCtrl_SetMarginRight 3142
-#define wxStyledTextCtrl_GetMarginRight 3143
-#define wxStyledTextCtrl_GetModify 3144
-#define wxStyledTextCtrl_SetSelection 3145
-#define wxStyledTextCtrl_GetSelectedText 3146
-#define wxStyledTextCtrl_GetTextRange 3147
-#define wxStyledTextCtrl_HideSelection 3148
-#define wxStyledTextCtrl_LineFromPosition 3149
-#define wxStyledTextCtrl_PositionFromLine 3150
-#define wxStyledTextCtrl_LineScroll 3151
-#define wxStyledTextCtrl_EnsureCaretVisible 3152
-#define wxStyledTextCtrl_ReplaceSelection 3153
-#define wxStyledTextCtrl_SetReadOnly 3154
-#define wxStyledTextCtrl_CanPaste 3155
-#define wxStyledTextCtrl_CanUndo 3156
-#define wxStyledTextCtrl_EmptyUndoBuffer 3157
-#define wxStyledTextCtrl_Undo 3158
-#define wxStyledTextCtrl_Cut 3159
-#define wxStyledTextCtrl_Copy 3160
-#define wxStyledTextCtrl_Paste 3161
-#define wxStyledTextCtrl_Clear 3162
-#define wxStyledTextCtrl_SetText 3163
-#define wxStyledTextCtrl_GetText 3164
-#define wxStyledTextCtrl_GetTextLength 3165
-#define wxStyledTextCtrl_GetOvertype 3166
-#define wxStyledTextCtrl_SetCaretWidth 3167
-#define wxStyledTextCtrl_GetCaretWidth 3168
-#define wxStyledTextCtrl_SetTargetStart 3169
-#define wxStyledTextCtrl_GetTargetStart 3170
-#define wxStyledTextCtrl_SetTargetEnd 3171
-#define wxStyledTextCtrl_GetTargetEnd 3172
-#define wxStyledTextCtrl_ReplaceTarget 3173
-#define wxStyledTextCtrl_SearchInTarget 3174
-#define wxStyledTextCtrl_SetSearchFlags 3175
-#define wxStyledTextCtrl_GetSearchFlags 3176
-#define wxStyledTextCtrl_CallTipShow 3177
-#define wxStyledTextCtrl_CallTipCancel 3178
-#define wxStyledTextCtrl_CallTipActive 3179
-#define wxStyledTextCtrl_CallTipPosAtStart 3180
-#define wxStyledTextCtrl_CallTipSetHighlight 3181
-#define wxStyledTextCtrl_CallTipSetBackground 3182
-#define wxStyledTextCtrl_CallTipSetForeground 3183
-#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3184
-#define wxStyledTextCtrl_CallTipUseStyle 3185
-#define wxStyledTextCtrl_VisibleFromDocLine 3186
-#define wxStyledTextCtrl_DocLineFromVisible 3187
-#define wxStyledTextCtrl_WrapCount 3188
-#define wxStyledTextCtrl_SetFoldLevel 3189
-#define wxStyledTextCtrl_GetFoldLevel 3190
-#define wxStyledTextCtrl_GetLastChild 3191
-#define wxStyledTextCtrl_GetFoldParent 3192
-#define wxStyledTextCtrl_ShowLines 3193
-#define wxStyledTextCtrl_HideLines 3194
-#define wxStyledTextCtrl_GetLineVisible 3195
-#define wxStyledTextCtrl_SetFoldExpanded 3196
-#define wxStyledTextCtrl_GetFoldExpanded 3197
-#define wxStyledTextCtrl_ToggleFold 3198
-#define wxStyledTextCtrl_EnsureVisible 3199
-#define wxStyledTextCtrl_SetFoldFlags 3200
-#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3201
-#define wxStyledTextCtrl_SetTabIndents 3202
-#define wxStyledTextCtrl_GetTabIndents 3203
-#define wxStyledTextCtrl_SetBackSpaceUnIndents 3204
-#define wxStyledTextCtrl_GetBackSpaceUnIndents 3205
-#define wxStyledTextCtrl_SetMouseDwellTime 3206
-#define wxStyledTextCtrl_GetMouseDwellTime 3207
-#define wxStyledTextCtrl_WordStartPosition 3208
-#define wxStyledTextCtrl_WordEndPosition 3209
-#define wxStyledTextCtrl_SetWrapMode 3210
-#define wxStyledTextCtrl_GetWrapMode 3211
-#define wxStyledTextCtrl_SetWrapVisualFlags 3212
-#define wxStyledTextCtrl_GetWrapVisualFlags 3213
-#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3214
-#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3215
-#define wxStyledTextCtrl_SetWrapStartIndent 3216
-#define wxStyledTextCtrl_GetWrapStartIndent 3217
-#define wxStyledTextCtrl_SetLayoutCache 3218
-#define wxStyledTextCtrl_GetLayoutCache 3219
-#define wxStyledTextCtrl_SetScrollWidth 3220
-#define wxStyledTextCtrl_GetScrollWidth 3221
-#define wxStyledTextCtrl_TextWidth 3222
-#define wxStyledTextCtrl_GetEndAtLastLine 3223
-#define wxStyledTextCtrl_TextHeight 3224
-#define wxStyledTextCtrl_SetUseVerticalScrollBar 3225
-#define wxStyledTextCtrl_GetUseVerticalScrollBar 3226
-#define wxStyledTextCtrl_AppendText 3227
-#define wxStyledTextCtrl_GetTwoPhaseDraw 3228
-#define wxStyledTextCtrl_SetTwoPhaseDraw 3229
-#define wxStyledTextCtrl_TargetFromSelection 3230
-#define wxStyledTextCtrl_LinesJoin 3231
-#define wxStyledTextCtrl_LinesSplit 3232
-#define wxStyledTextCtrl_SetFoldMarginColour 3233
-#define wxStyledTextCtrl_SetFoldMarginHiColour 3234
-#define wxStyledTextCtrl_LineDown 3235
-#define wxStyledTextCtrl_LineDownExtend 3236
-#define wxStyledTextCtrl_LineUp 3237
-#define wxStyledTextCtrl_LineUpExtend 3238
-#define wxStyledTextCtrl_CharLeft 3239
-#define wxStyledTextCtrl_CharLeftExtend 3240
-#define wxStyledTextCtrl_CharRight 3241
-#define wxStyledTextCtrl_CharRightExtend 3242
-#define wxStyledTextCtrl_WordLeft 3243
-#define wxStyledTextCtrl_WordLeftExtend 3244
-#define wxStyledTextCtrl_WordRight 3245
-#define wxStyledTextCtrl_WordRightExtend 3246
-#define wxStyledTextCtrl_Home 3247
-#define wxStyledTextCtrl_HomeExtend 3248
-#define wxStyledTextCtrl_LineEnd 3249
-#define wxStyledTextCtrl_LineEndExtend 3250
-#define wxStyledTextCtrl_DocumentStart 3251
-#define wxStyledTextCtrl_DocumentStartExtend 3252
-#define wxStyledTextCtrl_DocumentEnd 3253
-#define wxStyledTextCtrl_DocumentEndExtend 3254
-#define wxStyledTextCtrl_PageUp 3255
-#define wxStyledTextCtrl_PageUpExtend 3256
-#define wxStyledTextCtrl_PageDown 3257
-#define wxStyledTextCtrl_PageDownExtend 3258
-#define wxStyledTextCtrl_EditToggleOvertype 3259
-#define wxStyledTextCtrl_Cancel 3260
-#define wxStyledTextCtrl_DeleteBack 3261
-#define wxStyledTextCtrl_Tab 3262
-#define wxStyledTextCtrl_BackTab 3263
-#define wxStyledTextCtrl_NewLine 3264
-#define wxStyledTextCtrl_FormFeed 3265
-#define wxStyledTextCtrl_VCHome 3266
-#define wxStyledTextCtrl_VCHomeExtend 3267
-#define wxStyledTextCtrl_ZoomIn 3268
-#define wxStyledTextCtrl_ZoomOut 3269
-#define wxStyledTextCtrl_DelWordLeft 3270
-#define wxStyledTextCtrl_DelWordRight 3271
-#define wxStyledTextCtrl_LineCut 3272
-#define wxStyledTextCtrl_LineDelete 3273
-#define wxStyledTextCtrl_LineTranspose 3274
-#define wxStyledTextCtrl_LineDuplicate 3275
-#define wxStyledTextCtrl_LowerCase 3276
-#define wxStyledTextCtrl_UpperCase 3277
-#define wxStyledTextCtrl_LineScrollDown 3278
-#define wxStyledTextCtrl_LineScrollUp 3279
-#define wxStyledTextCtrl_DeleteBackNotLine 3280
-#define wxStyledTextCtrl_HomeDisplay 3281
-#define wxStyledTextCtrl_HomeDisplayExtend 3282
-#define wxStyledTextCtrl_LineEndDisplay 3283
-#define wxStyledTextCtrl_LineEndDisplayExtend 3284
-#define wxStyledTextCtrl_HomeWrapExtend 3285
-#define wxStyledTextCtrl_LineEndWrap 3286
-#define wxStyledTextCtrl_LineEndWrapExtend 3287
-#define wxStyledTextCtrl_VCHomeWrap 3288
-#define wxStyledTextCtrl_VCHomeWrapExtend 3289
-#define wxStyledTextCtrl_LineCopy 3290
-#define wxStyledTextCtrl_MoveCaretInsideView 3291
-#define wxStyledTextCtrl_LineLength 3292
-#define wxStyledTextCtrl_BraceHighlight 3293
-#define wxStyledTextCtrl_BraceBadLight 3294
-#define wxStyledTextCtrl_BraceMatch 3295
-#define wxStyledTextCtrl_GetViewEOL 3296
-#define wxStyledTextCtrl_SetViewEOL 3297
-#define wxStyledTextCtrl_SetModEventMask 3298
-#define wxStyledTextCtrl_GetEdgeColumn 3299
-#define wxStyledTextCtrl_SetEdgeColumn 3300
-#define wxStyledTextCtrl_SetEdgeMode 3301
-#define wxStyledTextCtrl_GetEdgeMode 3302
-#define wxStyledTextCtrl_GetEdgeColour 3303
-#define wxStyledTextCtrl_SetEdgeColour 3304
-#define wxStyledTextCtrl_SearchAnchor 3305
-#define wxStyledTextCtrl_SearchNext 3306
-#define wxStyledTextCtrl_SearchPrev 3307
-#define wxStyledTextCtrl_LinesOnScreen 3308
-#define wxStyledTextCtrl_UsePopUp 3309
-#define wxStyledTextCtrl_SelectionIsRectangle 3310
-#define wxStyledTextCtrl_SetZoom 3311
-#define wxStyledTextCtrl_GetZoom 3312
-#define wxStyledTextCtrl_GetModEventMask 3313
-#define wxStyledTextCtrl_SetSTCFocus 3314
-#define wxStyledTextCtrl_GetSTCFocus 3315
-#define wxStyledTextCtrl_SetStatus 3316
-#define wxStyledTextCtrl_GetStatus 3317
-#define wxStyledTextCtrl_SetMouseDownCaptures 3318
-#define wxStyledTextCtrl_GetMouseDownCaptures 3319
-#define wxStyledTextCtrl_SetSTCCursor 3320
-#define wxStyledTextCtrl_GetSTCCursor 3321
-#define wxStyledTextCtrl_SetControlCharSymbol 3322
-#define wxStyledTextCtrl_GetControlCharSymbol 3323
-#define wxStyledTextCtrl_WordPartLeft 3324
-#define wxStyledTextCtrl_WordPartLeftExtend 3325
-#define wxStyledTextCtrl_WordPartRight 3326
-#define wxStyledTextCtrl_WordPartRightExtend 3327
-#define wxStyledTextCtrl_SetVisiblePolicy 3328
-#define wxStyledTextCtrl_DelLineLeft 3329
-#define wxStyledTextCtrl_DelLineRight 3330
-#define wxStyledTextCtrl_GetXOffset 3331
-#define wxStyledTextCtrl_ChooseCaretX 3332
-#define wxStyledTextCtrl_SetXCaretPolicy 3333
-#define wxStyledTextCtrl_SetYCaretPolicy 3334
-#define wxStyledTextCtrl_GetPrintWrapMode 3335
-#define wxStyledTextCtrl_SetHotspotActiveForeground 3336
-#define wxStyledTextCtrl_SetHotspotActiveBackground 3337
-#define wxStyledTextCtrl_SetHotspotActiveUnderline 3338
-#define wxStyledTextCtrl_SetHotspotSingleLine 3339
-#define wxStyledTextCtrl_ParaDownExtend 3340
-#define wxStyledTextCtrl_ParaUp 3341
-#define wxStyledTextCtrl_ParaUpExtend 3342
-#define wxStyledTextCtrl_PositionBefore 3343
-#define wxStyledTextCtrl_PositionAfter 3344
-#define wxStyledTextCtrl_CopyRange 3345
-#define wxStyledTextCtrl_CopyText 3346
-#define wxStyledTextCtrl_SetSelectionMode 3347
-#define wxStyledTextCtrl_GetSelectionMode 3348
-#define wxStyledTextCtrl_LineDownRectExtend 3349
-#define wxStyledTextCtrl_LineUpRectExtend 3350
-#define wxStyledTextCtrl_CharLeftRectExtend 3351
-#define wxStyledTextCtrl_CharRightRectExtend 3352
-#define wxStyledTextCtrl_HomeRectExtend 3353
-#define wxStyledTextCtrl_VCHomeRectExtend 3354
-#define wxStyledTextCtrl_LineEndRectExtend 3355
-#define wxStyledTextCtrl_PageUpRectExtend 3356
-#define wxStyledTextCtrl_PageDownRectExtend 3357
-#define wxStyledTextCtrl_StutteredPageUp 3358
-#define wxStyledTextCtrl_StutteredPageUpExtend 3359
-#define wxStyledTextCtrl_StutteredPageDown 3360
-#define wxStyledTextCtrl_StutteredPageDownExtend 3361
-#define wxStyledTextCtrl_WordLeftEnd 3362
-#define wxStyledTextCtrl_WordLeftEndExtend 3363
-#define wxStyledTextCtrl_WordRightEnd 3364
-#define wxStyledTextCtrl_WordRightEndExtend 3365
-#define wxStyledTextCtrl_SetWhitespaceChars 3366
-#define wxStyledTextCtrl_SetCharsDefault 3367
-#define wxStyledTextCtrl_AutoCompGetCurrent 3368
-#define wxStyledTextCtrl_Allocate 3369
-#define wxStyledTextCtrl_FindColumn 3370
-#define wxStyledTextCtrl_GetCaretSticky 3371
-#define wxStyledTextCtrl_SetCaretSticky 3372
-#define wxStyledTextCtrl_ToggleCaretSticky 3373
-#define wxStyledTextCtrl_SetPasteConvertEndings 3374
-#define wxStyledTextCtrl_GetPasteConvertEndings 3375
-#define wxStyledTextCtrl_SelectionDuplicate 3376
-#define wxStyledTextCtrl_SetCaretLineBackAlpha 3377
-#define wxStyledTextCtrl_GetCaretLineBackAlpha 3378
-#define wxStyledTextCtrl_StartRecord 3379
-#define wxStyledTextCtrl_StopRecord 3380
-#define wxStyledTextCtrl_SetLexer 3381
-#define wxStyledTextCtrl_GetLexer 3382
-#define wxStyledTextCtrl_Colourise 3383
-#define wxStyledTextCtrl_SetProperty 3384
-#define wxStyledTextCtrl_SetKeyWords 3385
-#define wxStyledTextCtrl_SetLexerLanguage 3386
-#define wxStyledTextCtrl_GetProperty 3387
-#define wxStyledTextCtrl_GetStyleBitsNeeded 3388
-#define wxStyledTextCtrl_GetCurrentLine 3389
-#define wxStyledTextCtrl_StyleSetSpec 3390
-#define wxStyledTextCtrl_StyleSetFont 3391
-#define wxStyledTextCtrl_StyleSetFontAttr 3392
-#define wxStyledTextCtrl_StyleSetCharacterSet 3393
-#define wxStyledTextCtrl_StyleSetFontEncoding 3394
-#define wxStyledTextCtrl_CmdKeyExecute 3395
-#define wxStyledTextCtrl_SetMargins 3396
-#define wxStyledTextCtrl_GetSelection 3397
-#define wxStyledTextCtrl_PointFromPosition 3398
-#define wxStyledTextCtrl_ScrollToLine 3399
-#define wxStyledTextCtrl_ScrollToColumn 3400
-#define wxStyledTextCtrl_SetVScrollBar 3401
-#define wxStyledTextCtrl_SetHScrollBar 3402
-#define wxStyledTextCtrl_GetLastKeydownProcessed 3403
-#define wxStyledTextCtrl_SetLastKeydownProcessed 3404
-#define wxStyledTextCtrl_SaveFile 3405
-#define wxStyledTextCtrl_LoadFile 3406
-#define wxStyledTextCtrl_DoDragOver 3407
-#define wxStyledTextCtrl_DoDropText 3408
-#define wxStyledTextCtrl_GetUseAntiAliasing 3409
-#define wxStyledTextCtrl_AddTextRaw 3410
-#define wxStyledTextCtrl_InsertTextRaw 3411
-#define wxStyledTextCtrl_GetCurLineRaw 3412
-#define wxStyledTextCtrl_GetLineRaw 3413
-#define wxStyledTextCtrl_GetSelectedTextRaw 3414
-#define wxStyledTextCtrl_GetTextRangeRaw 3415
-#define wxStyledTextCtrl_SetTextRaw 3416
-#define wxStyledTextCtrl_GetTextRaw 3417
-#define wxStyledTextCtrl_AppendTextRaw 3418
-#define wxArtProvider_GetBitmap 3419
-#define wxArtProvider_GetIcon 3420
-#define wxTreeEvent_GetKeyCode 3421
-#define wxTreeEvent_GetItem 3422
-#define wxTreeEvent_GetKeyEvent 3423
-#define wxTreeEvent_GetLabel 3424
-#define wxTreeEvent_GetOldItem 3425
-#define wxTreeEvent_GetPoint 3426
-#define wxTreeEvent_IsEditCancelled 3427
-#define wxTreeEvent_SetToolTip 3428
-#define wxNotebookEvent_GetOldSelection 3429
-#define wxNotebookEvent_GetSelection 3430
-#define wxNotebookEvent_SetOldSelection 3431
-#define wxNotebookEvent_SetSelection 3432
-#define wxFileDataObject_new 3433
-#define wxFileDataObject_AddFile 3434
-#define wxFileDataObject_GetFilenames 3435
-#define wxFileDataObject_destroy 3436
-#define wxTextDataObject_new 3437
-#define wxTextDataObject_GetTextLength 3438
-#define wxTextDataObject_GetText 3439
-#define wxTextDataObject_SetText 3440
-#define wxTextDataObject_destroy 3441
-#define wxBitmapDataObject_new_1_1 3442
-#define wxBitmapDataObject_new_1_0 3443
-#define wxBitmapDataObject_GetBitmap 3444
-#define wxBitmapDataObject_SetBitmap 3445
-#define wxBitmapDataObject_destroy 3446
-#define wxClipboard_new 3448
-#define wxClipboard_destruct 3449
-#define wxClipboard_AddData 3450
-#define wxClipboard_Clear 3451
-#define wxClipboard_Close 3452
-#define wxClipboard_Flush 3453
-#define wxClipboard_GetData 3454
-#define wxClipboard_IsOpened 3455
-#define wxClipboard_Open 3456
-#define wxClipboard_SetData 3457
-#define wxClipboard_UsePrimarySelection 3459
-#define wxClipboard_IsSupported 3460
-#define wxClipboard_Get 3461
-#define wxSpinEvent_GetPosition 3462
-#define wxSpinEvent_SetPosition 3463
-#define wxSplitterWindow_new_0 3464
-#define wxSplitterWindow_new_2 3465
-#define wxSplitterWindow_destruct 3466
-#define wxSplitterWindow_Create 3467
-#define wxSplitterWindow_GetMinimumPaneSize 3468
-#define wxSplitterWindow_GetSashGravity 3469
-#define wxSplitterWindow_GetSashPosition 3470
-#define wxSplitterWindow_GetSplitMode 3471
-#define wxSplitterWindow_GetWindow1 3472
-#define wxSplitterWindow_GetWindow2 3473
-#define wxSplitterWindow_Initialize 3474
-#define wxSplitterWindow_IsSplit 3475
-#define wxSplitterWindow_ReplaceWindow 3476
-#define wxSplitterWindow_SetSashGravity 3477
-#define wxSplitterWindow_SetSashPosition 3478
-#define wxSplitterWindow_SetSashSize 3479
-#define wxSplitterWindow_SetMinimumPaneSize 3480
-#define wxSplitterWindow_SetSplitMode 3481
-#define wxSplitterWindow_SplitHorizontally 3482
-#define wxSplitterWindow_SplitVertically 3483
-#define wxSplitterWindow_Unsplit 3484
-#define wxSplitterWindow_UpdateSize 3485
-#define wxSplitterEvent_GetSashPosition 3486
-#define wxSplitterEvent_GetX 3487
-#define wxSplitterEvent_GetY 3488
-#define wxSplitterEvent_GetWindowBeingRemoved 3489
-#define wxSplitterEvent_SetSashPosition 3490
-#define wxHtmlWindow_new_0 3491
-#define wxHtmlWindow_new_2 3492
-#define wxHtmlWindow_AppendToPage 3493
-#define wxHtmlWindow_GetOpenedAnchor 3494
-#define wxHtmlWindow_GetOpenedPage 3495
-#define wxHtmlWindow_GetOpenedPageTitle 3496
-#define wxHtmlWindow_GetRelatedFrame 3497
-#define wxHtmlWindow_HistoryBack 3498
-#define wxHtmlWindow_HistoryCanBack 3499
-#define wxHtmlWindow_HistoryCanForward 3500
-#define wxHtmlWindow_HistoryClear 3501
-#define wxHtmlWindow_HistoryForward 3502
-#define wxHtmlWindow_LoadFile 3503
-#define wxHtmlWindow_LoadPage 3504
-#define wxHtmlWindow_SelectAll 3505
-#define wxHtmlWindow_SelectionToText 3506
-#define wxHtmlWindow_SelectLine 3507
-#define wxHtmlWindow_SelectWord 3508
-#define wxHtmlWindow_SetBorders 3509
-#define wxHtmlWindow_SetFonts 3510
-#define wxHtmlWindow_SetPage 3511
-#define wxHtmlWindow_SetRelatedFrame 3512
-#define wxHtmlWindow_SetRelatedStatusBar 3513
-#define wxHtmlWindow_ToText 3514
-#define wxHtmlWindow_destroy 3515
-#define wxHtmlLinkEvent_GetLinkInfo 3516
-#define wxSystemSettings_GetColour 3517
-#define wxSystemSettings_GetFont 3518
-#define wxSystemSettings_GetMetric 3519
-#define wxSystemSettings_GetScreenType 3520
-#define wxSystemOptions_GetOption 3521
-#define wxSystemOptions_GetOptionInt 3522
-#define wxSystemOptions_HasOption 3523
-#define wxSystemOptions_IsFalse 3524
-#define wxSystemOptions_SetOption_2_1 3525
-#define wxSystemOptions_SetOption_2_0 3526
-#define wxAuiNotebookEvent_SetSelection 3527
-#define wxAuiNotebookEvent_GetSelection 3528
-#define wxAuiNotebookEvent_SetOldSelection 3529
-#define wxAuiNotebookEvent_GetOldSelection 3530
-#define wxAuiNotebookEvent_SetDragSource 3531
-#define wxAuiNotebookEvent_GetDragSource 3532
-#define wxAuiManagerEvent_SetManager 3533
-#define wxAuiManagerEvent_GetManager 3534
-#define wxAuiManagerEvent_SetPane 3535
-#define wxAuiManagerEvent_GetPane 3536
-#define wxAuiManagerEvent_SetButton 3537
-#define wxAuiManagerEvent_GetButton 3538
-#define wxAuiManagerEvent_SetDC 3539
-#define wxAuiManagerEvent_GetDC 3540
-#define wxAuiManagerEvent_Veto 3541
-#define wxAuiManagerEvent_GetVeto 3542
-#define wxAuiManagerEvent_SetCanVeto 3543
-#define wxAuiManagerEvent_CanVeto 3544
-#define wxLogNull_new 3545
-#define wxLogNull_destroy 3546
-#define wxTaskBarIcon_new 3547
-#define wxTaskBarIcon_destruct 3548
-#define wxTaskBarIcon_PopupMenu 3549
-#define wxTaskBarIcon_RemoveIcon 3550
-#define wxTaskBarIcon_SetIcon 3551
-#define wxLocale_new_0 3552
-#define wxLocale_new_2 3554
-#define wxLocale_destruct 3555
-#define wxLocale_Init 3557
-#define wxLocale_AddCatalog_1 3558
-#define wxLocale_AddCatalog_3 3559
-#define wxLocale_AddCatalogLookupPathPrefix 3560
-#define wxLocale_GetCanonicalName 3561
-#define wxLocale_GetLanguage 3562
-#define wxLocale_GetLanguageName 3563
-#define wxLocale_GetLocale 3564
-#define wxLocale_GetName 3565
-#define wxLocale_GetString_2 3566
-#define wxLocale_GetString_4 3567
-#define wxLocale_GetHeaderValue 3568
-#define wxLocale_GetSysName 3569
-#define wxLocale_GetSystemEncoding 3570
-#define wxLocale_GetSystemEncodingName 3571
-#define wxLocale_GetSystemLanguage 3572
-#define wxLocale_IsLoaded 3573
-#define wxLocale_IsOk 3574
-#define wxActivateEvent_GetActive 3575
-#define wxPopupWindow_new_2 3577
-#define wxPopupWindow_new_0 3578
-#define wxPopupWindow_destruct 3580
-#define wxPopupWindow_Create 3581
-#define wxPopupWindow_Position 3582
-#define wxPopupTransientWindow_new_0 3583
-#define wxPopupTransientWindow_new_2 3584
-#define wxPopupTransientWindow_destruct 3585
-#define wxPopupTransientWindow_Popup 3586
-#define wxPopupTransientWindow_Dismiss 3587
-#define wxOverlay_new 3588
-#define wxOverlay_destruct 3589
-#define wxOverlay_Reset 3590
-#define wxDCOverlay_new_6 3591
-#define wxDCOverlay_new_2 3592
-#define wxDCOverlay_destruct 3593
-#define wxDCOverlay_Clear 3594
+#define wxWindow_DragAcceptFiles 126
+#define wxWindow_Enable 127
+#define wxWindow_FindFocus 128
+#define wxWindow_FindWindow_1_0 129
+#define wxWindow_FindWindow_1_1 130
+#define wxWindow_FindWindowById 131
+#define wxWindow_FindWindowByName 132
+#define wxWindow_FindWindowByLabel 133
+#define wxWindow_Fit 134
+#define wxWindow_FitInside 135
+#define wxWindow_Freeze 136
+#define wxWindow_GetAcceleratorTable 137
+#define wxWindow_GetBackgroundColour 138
+#define wxWindow_GetBackgroundStyle 139
+#define wxWindow_GetBestSize 140
+#define wxWindow_GetCaret 142
+#define wxWindow_GetCapture 143
+#define wxWindow_GetCharHeight 144
+#define wxWindow_GetCharWidth 145
+#define wxWindow_GetChildren 146
+#define wxWindow_GetClientSize 149
+#define wxWindow_GetContainingSizer 150
+#define wxWindow_GetCursor 151
+#define wxWindow_GetDropTarget 152
+#define wxWindow_GetEventHandler 153
+#define wxWindow_GetExtraStyle 154
+#define wxWindow_GetFont 155
+#define wxWindow_GetForegroundColour 156
+#define wxWindow_GetGrandParent 157
+#define wxWindow_GetHandle 158
+#define wxWindow_GetHelpText 159
+#define wxWindow_GetId 160
+#define wxWindow_GetLabel 161
+#define wxWindow_GetMaxSize 162
+#define wxWindow_GetMinSize 163
+#define wxWindow_GetName 164
+#define wxWindow_GetParent 165
+#define wxWindow_GetPosition 167
+#define wxWindow_GetRect 168
+#define wxWindow_GetScreenPosition 170
+#define wxWindow_GetScreenRect 171
+#define wxWindow_GetScrollPos 172
+#define wxWindow_GetScrollRange 173
+#define wxWindow_GetScrollThumb 174
+#define wxWindow_GetSize 176
+#define wxWindow_GetSizer 177
+#define wxWindow_GetTextExtent 178
+#define wxWindow_GetToolTip 179
+#define wxWindow_GetUpdateRegion 180
+#define wxWindow_GetVirtualSize 182
+#define wxWindow_GetWindowStyleFlag 184
+#define wxWindow_GetWindowVariant 185
+#define wxWindow_HasCapture 186
+#define wxWindow_HasScrollbar 187
+#define wxWindow_HasTransparentBackground 188
+#define wxWindow_Hide 189
+#define wxWindow_InheritAttributes 190
+#define wxWindow_InitDialog 191
+#define wxWindow_InvalidateBestSize 192
+#define wxWindow_IsEnabled 193
+#define wxWindow_IsExposed_2 194
+#define wxWindow_IsExposed_4 195
+#define wxWindow_IsExposed_1_0 196
+#define wxWindow_IsExposed_1_1 197
+#define wxWindow_IsRetained 198
+#define wxWindow_IsShown 199
+#define wxWindow_IsTopLevel 200
+#define wxWindow_Layout 201
+#define wxWindow_LineDown 202
+#define wxWindow_LineUp 203
+#define wxWindow_Lower 204
+#define wxWindow_MakeModal 205
+#define wxWindow_Move_3 206
+#define wxWindow_Move_2 207
+#define wxWindow_MoveAfterInTabOrder 208
+#define wxWindow_MoveBeforeInTabOrder 209
+#define wxWindow_Navigate 210
+#define wxWindow_PageDown 211
+#define wxWindow_PageUp 212
+#define wxWindow_PopEventHandler 213
+#define wxWindow_PopupMenu_2 214
+#define wxWindow_PopupMenu_3 215
+#define wxWindow_Raise 216
+#define wxWindow_Refresh 217
+#define wxWindow_RefreshRect 218
+#define wxWindow_ReleaseMouse 219
+#define wxWindow_RemoveChild 220
+#define wxWindow_Reparent 221
+#define wxWindow_ScreenToClient_2 222
+#define wxWindow_ScreenToClient_1 223
+#define wxWindow_ScrollLines 225
+#define wxWindow_ScrollPages 227
+#define wxWindow_ScrollWindow 228
+#define wxWindow_SetAcceleratorTable 229
+#define wxWindow_SetAutoLayout 230
+#define wxWindow_SetBackgroundColour 231
+#define wxWindow_SetBackgroundStyle 232
+#define wxWindow_SetCaret 233
+#define wxWindow_SetClientSize_2 234
+#define wxWindow_SetClientSize_1_0 235
+#define wxWindow_SetClientSize_1_1 236
+#define wxWindow_SetContainingSizer 237
+#define wxWindow_SetCursor 238
+#define wxWindow_SetMaxSize 239
+#define wxWindow_SetMinSize 240
+#define wxWindow_SetOwnBackgroundColour 241
+#define wxWindow_SetOwnFont 242
+#define wxWindow_SetOwnForegroundColour 243
+#define wxWindow_SetDropTarget 244
+#define wxWindow_SetExtraStyle 245
+#define wxWindow_SetFocus 246
+#define wxWindow_SetFocusFromKbd 247
+#define wxWindow_SetFont 248
+#define wxWindow_SetForegroundColour 249
+#define wxWindow_SetHelpText 250
+#define wxWindow_SetId 251
+#define wxWindow_SetLabel 253
+#define wxWindow_SetName 254
+#define wxWindow_SetPalette 255
+#define wxWindow_SetScrollbar 256
+#define wxWindow_SetScrollPos 257
+#define wxWindow_SetSize_5 258
+#define wxWindow_SetSize_2_0 259
+#define wxWindow_SetSize_1 260
+#define wxWindow_SetSize_2_1 261
+#define wxWindow_SetSizeHints_3 262
+#define wxWindow_SetSizeHints_2 263
+#define wxWindow_SetSizer 264
+#define wxWindow_SetSizerAndFit 265
+#define wxWindow_SetThemeEnabled 266
+#define wxWindow_SetToolTip_1_0 267
+#define wxWindow_SetToolTip_1_1 268
+#define wxWindow_SetVirtualSize_1 269
+#define wxWindow_SetVirtualSize_2 270
+#define wxWindow_SetVirtualSizeHints_3 271
+#define wxWindow_SetVirtualSizeHints_2 272
+#define wxWindow_SetWindowStyle 273
+#define wxWindow_SetWindowStyleFlag 274
+#define wxWindow_SetWindowVariant 275
+#define wxWindow_ShouldInheritColours 276
+#define wxWindow_Show 277
+#define wxWindow_Thaw 278
+#define wxWindow_TransferDataFromWindow 279
+#define wxWindow_TransferDataToWindow 280
+#define wxWindow_Update 281
+#define wxWindow_UpdateWindowUI 282
+#define wxWindow_Validate 283
+#define wxWindow_WarpPointer 284
+#define wxWindow_SetTransparent 285
+#define wxWindow_CanSetTransparent 286
+#define wxWindow_IsDoubleBuffered 287
+#define wxWindow_SetDoubleBuffered 288
+#define wxWindow_GetContentScaleFactor 289
+#define wxTopLevelWindow_GetIcon 290
+#define wxTopLevelWindow_GetIcons 291
+#define wxTopLevelWindow_GetTitle 292
+#define wxTopLevelWindow_IsActive 293
+#define wxTopLevelWindow_Iconize 294
+#define wxTopLevelWindow_IsFullScreen 295
+#define wxTopLevelWindow_IsIconized 296
+#define wxTopLevelWindow_IsMaximized 297
+#define wxTopLevelWindow_Maximize 298
+#define wxTopLevelWindow_RequestUserAttention 299
+#define wxTopLevelWindow_SetIcon 300
+#define wxTopLevelWindow_SetIcons 301
+#define wxTopLevelWindow_CenterOnScreen 302
+#define wxTopLevelWindow_CentreOnScreen 303
+#define wxTopLevelWindow_SetShape 305
+#define wxTopLevelWindow_SetTitle 306
+#define wxTopLevelWindow_ShowFullScreen 307
+#define wxFrame_new_4 309
+#define wxFrame_new_0 310
+#define wxFrame_destruct 312
+#define wxFrame_Create 313
+#define wxFrame_CreateStatusBar 314
+#define wxFrame_CreateToolBar 315
+#define wxFrame_GetClientAreaOrigin 316
+#define wxFrame_GetMenuBar 317
+#define wxFrame_GetStatusBar 318
+#define wxFrame_GetStatusBarPane 319
+#define wxFrame_GetToolBar 320
+#define wxFrame_ProcessCommand 321
+#define wxFrame_SendSizeEvent 322
+#define wxFrame_SetMenuBar 323
+#define wxFrame_SetStatusBar 324
+#define wxFrame_SetStatusBarPane 325
+#define wxFrame_SetStatusText 326
+#define wxFrame_SetStatusWidths 327
+#define wxFrame_SetToolBar 328
+#define wxMiniFrame_new_0 329
+#define wxMiniFrame_new_4 330
+#define wxMiniFrame_Create 331
+#define wxMiniFrame_destroy 332
+#define wxSplashScreen_new_0 333
+#define wxSplashScreen_new_6 334
+#define wxSplashScreen_destruct 335
+#define wxSplashScreen_GetSplashStyle 336
+#define wxSplashScreen_GetTimeout 337
+#define wxPanel_new_0 338
+#define wxPanel_new_6 339
+#define wxPanel_new_2 340
+#define wxPanel_destruct 341
+#define wxPanel_InitDialog 342
+#define wxPanel_SetFocusIgnoringChildren 343
+#define wxScrolledWindow_new_0 344
+#define wxScrolledWindow_new_2 345
+#define wxScrolledWindow_destruct 346
+#define wxScrolledWindow_CalcScrolledPosition_4 347
+#define wxScrolledWindow_CalcScrolledPosition_1 348
+#define wxScrolledWindow_CalcUnscrolledPosition_4 349
+#define wxScrolledWindow_CalcUnscrolledPosition_1 350
+#define wxScrolledWindow_EnableScrolling 351
+#define wxScrolledWindow_GetScrollPixelsPerUnit 352
+#define wxScrolledWindow_GetViewStart 353
+#define wxScrolledWindow_DoPrepareDC 354
+#define wxScrolledWindow_PrepareDC 355
+#define wxScrolledWindow_Scroll 356
+#define wxScrolledWindow_SetScrollbars 357
+#define wxScrolledWindow_SetScrollRate 358
+#define wxScrolledWindow_SetTargetWindow 359
+#define wxSashWindow_new_0 360
+#define wxSashWindow_new_2 361
+#define wxSashWindow_destruct 362
+#define wxSashWindow_GetSashVisible 363
+#define wxSashWindow_GetMaximumSizeX 364
+#define wxSashWindow_GetMaximumSizeY 365
+#define wxSashWindow_GetMinimumSizeX 366
+#define wxSashWindow_GetMinimumSizeY 367
+#define wxSashWindow_SetMaximumSizeX 368
+#define wxSashWindow_SetMaximumSizeY 369
+#define wxSashWindow_SetMinimumSizeX 370
+#define wxSashWindow_SetMinimumSizeY 371
+#define wxSashWindow_SetSashVisible 372
+#define wxSashLayoutWindow_new_0 373
+#define wxSashLayoutWindow_new_2 374
+#define wxSashLayoutWindow_Create 375
+#define wxSashLayoutWindow_GetAlignment 376
+#define wxSashLayoutWindow_GetOrientation 377
+#define wxSashLayoutWindow_SetAlignment 378
+#define wxSashLayoutWindow_SetDefaultSize 379
+#define wxSashLayoutWindow_SetOrientation 380
+#define wxSashLayoutWindow_destroy 381
+#define wxGrid_new_0 382
+#define wxGrid_new_3 383
+#define wxGrid_new_4 384
+#define wxGrid_destruct 385
+#define wxGrid_AppendCols 386
+#define wxGrid_AppendRows 387
+#define wxGrid_AutoSize 388
+#define wxGrid_AutoSizeColumn 389
+#define wxGrid_AutoSizeColumns 390
+#define wxGrid_AutoSizeRow 391
+#define wxGrid_AutoSizeRows 392
+#define wxGrid_BeginBatch 393
+#define wxGrid_BlockToDeviceRect 394
+#define wxGrid_CanDragColSize 395
+#define wxGrid_CanDragRowSize 396
+#define wxGrid_CanDragGridSize 397
+#define wxGrid_CanEnableCellControl 398
+#define wxGrid_CellToRect_2 399
+#define wxGrid_CellToRect_1 400
+#define wxGrid_ClearGrid 401
+#define wxGrid_ClearSelection 402
+#define wxGrid_CreateGrid 403
+#define wxGrid_DeleteCols 404
+#define wxGrid_DeleteRows 405
+#define wxGrid_DisableCellEditControl 406
+#define wxGrid_DisableDragColSize 407
+#define wxGrid_DisableDragGridSize 408
+#define wxGrid_DisableDragRowSize 409
+#define wxGrid_EnableCellEditControl 410
+#define wxGrid_EnableDragColSize 411
+#define wxGrid_EnableDragGridSize 412
+#define wxGrid_EnableDragRowSize 413
+#define wxGrid_EnableEditing 414
+#define wxGrid_EnableGridLines 415
+#define wxGrid_EndBatch 416
+#define wxGrid_Fit 417
+#define wxGrid_ForceRefresh 418
+#define wxGrid_GetBatchCount 419
+#define wxGrid_GetCellAlignment 420
+#define wxGrid_GetCellBackgroundColour 421
+#define wxGrid_GetCellEditor 422
+#define wxGrid_GetCellFont 423
+#define wxGrid_GetCellRenderer 424
+#define wxGrid_GetCellTextColour 425
+#define wxGrid_GetCellValue_2 426
+#define wxGrid_GetCellValue_1 427
+#define wxGrid_GetColLabelAlignment 428
+#define wxGrid_GetColLabelSize 429
+#define wxGrid_GetColLabelValue 430
+#define wxGrid_GetColMinimalAcceptableWidth 431
+#define wxGrid_GetDefaultCellAlignment 432
+#define wxGrid_GetDefaultCellBackgroundColour 433
+#define wxGrid_GetDefaultCellFont 434
+#define wxGrid_GetDefaultCellTextColour 435
+#define wxGrid_GetDefaultColLabelSize 436
+#define wxGrid_GetDefaultColSize 437
+#define wxGrid_GetDefaultEditor 438
+#define wxGrid_GetDefaultEditorForCell_2 439
+#define wxGrid_GetDefaultEditorForCell_1 440
+#define wxGrid_GetDefaultEditorForType 441
+#define wxGrid_GetDefaultRenderer 442
+#define wxGrid_GetDefaultRendererForCell 443
+#define wxGrid_GetDefaultRendererForType 444
+#define wxGrid_GetDefaultRowLabelSize 445
+#define wxGrid_GetDefaultRowSize 446
+#define wxGrid_GetGridCursorCol 447
+#define wxGrid_GetGridCursorRow 448
+#define wxGrid_GetGridLineColour 449
+#define wxGrid_GridLinesEnabled 450
+#define wxGrid_GetLabelBackgroundColour 451
+#define wxGrid_GetLabelFont 452
+#define wxGrid_GetLabelTextColour 453
+#define wxGrid_GetNumberCols 454
+#define wxGrid_GetNumberRows 455
+#define wxGrid_GetOrCreateCellAttr 456
+#define wxGrid_GetRowMinimalAcceptableHeight 457
+#define wxGrid_GetRowLabelAlignment 458
+#define wxGrid_GetRowLabelSize 459
+#define wxGrid_GetRowLabelValue 460
+#define wxGrid_GetRowSize 461
+#define wxGrid_GetScrollLineX 462
+#define wxGrid_GetScrollLineY 463
+#define wxGrid_GetSelectedCells 464
+#define wxGrid_GetSelectedCols 465
+#define wxGrid_GetSelectedRows 466
+#define wxGrid_GetSelectionBackground 467
+#define wxGrid_GetSelectionBlockTopLeft 468
+#define wxGrid_GetSelectionBlockBottomRight 469
+#define wxGrid_GetSelectionForeground 470
+#define wxGrid_GetViewWidth 471
+#define wxGrid_GetGridWindow 472
+#define wxGrid_GetGridRowLabelWindow 473
+#define wxGrid_GetGridColLabelWindow 474
+#define wxGrid_GetGridCornerLabelWindow 475
+#define wxGrid_HideCellEditControl 476
+#define wxGrid_InsertCols 477
+#define wxGrid_InsertRows 478
+#define wxGrid_IsCellEditControlEnabled 479
+#define wxGrid_IsCurrentCellReadOnly 480
+#define wxGrid_IsEditable 481
+#define wxGrid_IsInSelection_2 482
+#define wxGrid_IsInSelection_1 483
+#define wxGrid_IsReadOnly 484
+#define wxGrid_IsSelection 485
+#define wxGrid_IsVisible_3 486
+#define wxGrid_IsVisible_2 487
+#define wxGrid_MakeCellVisible_2 488
+#define wxGrid_MakeCellVisible_1 489
+#define wxGrid_MoveCursorDown 490
+#define wxGrid_MoveCursorLeft 491
+#define wxGrid_MoveCursorRight 492
+#define wxGrid_MoveCursorUp 493
+#define wxGrid_MoveCursorDownBlock 494
+#define wxGrid_MoveCursorLeftBlock 495
+#define wxGrid_MoveCursorRightBlock 496
+#define wxGrid_MoveCursorUpBlock 497
+#define wxGrid_MovePageDown 498
+#define wxGrid_MovePageUp 499
+#define wxGrid_RegisterDataType 500
+#define wxGrid_SaveEditControlValue 501
+#define wxGrid_SelectAll 502
+#define wxGrid_SelectBlock_5 503
+#define wxGrid_SelectBlock_3 504
+#define wxGrid_SelectCol 505
+#define wxGrid_SelectRow 506
+#define wxGrid_SetCellAlignment_4 507
+#define wxGrid_SetCellAlignment_3 508
+#define wxGrid_SetCellAlignment_1 509
+#define wxGrid_SetCellBackgroundColour_3_0 510
+#define wxGrid_SetCellBackgroundColour_1 511
+#define wxGrid_SetCellBackgroundColour_3_1 512
+#define wxGrid_SetCellEditor 513
+#define wxGrid_SetCellFont 514
+#define wxGrid_SetCellRenderer 515
+#define wxGrid_SetCellTextColour_3_0 516
+#define wxGrid_SetCellTextColour_3_1 517
+#define wxGrid_SetCellTextColour_1 518
+#define wxGrid_SetCellValue_3_0 519
+#define wxGrid_SetCellValue_2 520
+#define wxGrid_SetCellValue_3_1 521
+#define wxGrid_SetColAttr 522
+#define wxGrid_SetColFormatBool 523
+#define wxGrid_SetColFormatNumber 524
+#define wxGrid_SetColFormatFloat 525
+#define wxGrid_SetColFormatCustom 526
+#define wxGrid_SetColLabelAlignment 527
+#define wxGrid_SetColLabelSize 528
+#define wxGrid_SetColLabelValue 529
+#define wxGrid_SetColMinimalWidth 530
+#define wxGrid_SetColMinimalAcceptableWidth 531
+#define wxGrid_SetColSize 532
+#define wxGrid_SetDefaultCellAlignment 533
+#define wxGrid_SetDefaultCellBackgroundColour 534
+#define wxGrid_SetDefaultCellFont 535
+#define wxGrid_SetDefaultCellTextColour 536
+#define wxGrid_SetDefaultEditor 537
+#define wxGrid_SetDefaultRenderer 538
+#define wxGrid_SetDefaultColSize 539
+#define wxGrid_SetDefaultRowSize 540
+#define wxGrid_SetGridCursor 541
+#define wxGrid_SetGridLineColour 542
+#define wxGrid_SetLabelBackgroundColour 543
+#define wxGrid_SetLabelFont 544
+#define wxGrid_SetLabelTextColour 545
+#define wxGrid_SetMargins 546
+#define wxGrid_SetReadOnly 547
+#define wxGrid_SetRowAttr 548
+#define wxGrid_SetRowLabelAlignment 549
+#define wxGrid_SetRowLabelSize 550
+#define wxGrid_SetRowLabelValue 551
+#define wxGrid_SetRowMinimalHeight 552
+#define wxGrid_SetRowMinimalAcceptableHeight 553
+#define wxGrid_SetRowSize 554
+#define wxGrid_SetScrollLineX 555
+#define wxGrid_SetScrollLineY 556
+#define wxGrid_SetSelectionBackground 557
+#define wxGrid_SetSelectionForeground 558
+#define wxGrid_SetSelectionMode 559
+#define wxGrid_ShowCellEditControl 560
+#define wxGrid_XToCol 561
+#define wxGrid_XToEdgeOfCol 562
+#define wxGrid_YToEdgeOfRow 563
+#define wxGrid_YToRow 564
+#define wxGridCellRenderer_Draw 565
+#define wxGridCellRenderer_GetBestSize 566
+#define wxGridCellEditor_Create 567
+#define wxGridCellEditor_IsCreated 568
+#define wxGridCellEditor_SetSize 569
+#define wxGridCellEditor_Show 570
+#define wxGridCellEditor_PaintBackground 571
+#define wxGridCellEditor_BeginEdit 572
+#define wxGridCellEditor_EndEdit 573
+#define wxGridCellEditor_Reset 574
+#define wxGridCellEditor_StartingKey 575
+#define wxGridCellEditor_StartingClick 576
+#define wxGridCellEditor_HandleReturn 577
+#define wxGridCellBoolRenderer_new 578
+#define wxGridCellBoolRenderer_destroy 579
+#define wxGridCellBoolEditor_new 580
+#define wxGridCellBoolEditor_IsTrueValue 581
+#define wxGridCellBoolEditor_UseStringValues 582
+#define wxGridCellBoolEditor_destroy 583
+#define wxGridCellFloatRenderer_new 584
+#define wxGridCellFloatRenderer_GetPrecision 585
+#define wxGridCellFloatRenderer_GetWidth 586
+#define wxGridCellFloatRenderer_SetParameters 587
+#define wxGridCellFloatRenderer_SetPrecision 588
+#define wxGridCellFloatRenderer_SetWidth 589
+#define wxGridCellFloatRenderer_destroy 590
+#define wxGridCellFloatEditor_new 591
+#define wxGridCellFloatEditor_SetParameters 592
+#define wxGridCellFloatEditor_destroy 593
+#define wxGridCellStringRenderer_new 594
+#define wxGridCellStringRenderer_destroy 595
+#define wxGridCellTextEditor_new 596
+#define wxGridCellTextEditor_SetParameters 597
+#define wxGridCellTextEditor_destroy 598
+#define wxGridCellChoiceEditor_new 600
+#define wxGridCellChoiceEditor_SetParameters 601
+#define wxGridCellChoiceEditor_destroy 602
+#define wxGridCellNumberRenderer_new 603
+#define wxGridCellNumberRenderer_destroy 604
+#define wxGridCellNumberEditor_new 605
+#define wxGridCellNumberEditor_GetValue 606
+#define wxGridCellNumberEditor_SetParameters 607
+#define wxGridCellNumberEditor_destroy 608
+#define wxGridCellAttr_SetTextColour 609
+#define wxGridCellAttr_SetBackgroundColour 610
+#define wxGridCellAttr_SetFont 611
+#define wxGridCellAttr_SetAlignment 612
+#define wxGridCellAttr_SetReadOnly 613
+#define wxGridCellAttr_SetRenderer 614
+#define wxGridCellAttr_SetEditor 615
+#define wxGridCellAttr_HasTextColour 616
+#define wxGridCellAttr_HasBackgroundColour 617
+#define wxGridCellAttr_HasFont 618
+#define wxGridCellAttr_HasAlignment 619
+#define wxGridCellAttr_HasRenderer 620
+#define wxGridCellAttr_HasEditor 621
+#define wxGridCellAttr_GetTextColour 622
+#define wxGridCellAttr_GetBackgroundColour 623
+#define wxGridCellAttr_GetFont 624
+#define wxGridCellAttr_GetAlignment 625
+#define wxGridCellAttr_GetRenderer 626
+#define wxGridCellAttr_GetEditor 627
+#define wxGridCellAttr_IsReadOnly 628
+#define wxGridCellAttr_SetDefAttr 629
+#define wxDC_Blit 630
+#define wxDC_CalcBoundingBox 631
+#define wxDC_Clear 632
+#define wxDC_ComputeScaleAndOrigin 633
+#define wxDC_CrossHair 634
+#define wxDC_DestroyClippingRegion 635
+#define wxDC_DeviceToLogicalX 636
+#define wxDC_DeviceToLogicalXRel 637
+#define wxDC_DeviceToLogicalY 638
+#define wxDC_DeviceToLogicalYRel 639
+#define wxDC_DrawArc 640
+#define wxDC_DrawBitmap 641
+#define wxDC_DrawCheckMark 642
+#define wxDC_DrawCircle 643
+#define wxDC_DrawEllipse_2 645
+#define wxDC_DrawEllipse_1 646
+#define wxDC_DrawEllipticArc 647
+#define wxDC_DrawIcon 648
+#define wxDC_DrawLabel 649
+#define wxDC_DrawLine 650
+#define wxDC_DrawLines 651
+#define wxDC_DrawPolygon 653
+#define wxDC_DrawPoint 655
+#define wxDC_DrawRectangle_2 657
+#define wxDC_DrawRectangle_1 658
+#define wxDC_DrawRotatedText 659
+#define wxDC_DrawRoundedRectangle_3 661
+#define wxDC_DrawRoundedRectangle_2 662
+#define wxDC_DrawText 663
+#define wxDC_EndDoc 664
+#define wxDC_EndPage 665
+#define wxDC_FloodFill 666
+#define wxDC_GetBackground 667
+#define wxDC_GetBackgroundMode 668
+#define wxDC_GetBrush 669
+#define wxDC_GetCharHeight 670
+#define wxDC_GetCharWidth 671
+#define wxDC_GetClippingBox 672
+#define wxDC_GetFont 674
+#define wxDC_GetLayoutDirection 675
+#define wxDC_GetLogicalFunction 676
+#define wxDC_GetMapMode 677
+#define wxDC_GetMultiLineTextExtent_4 678
+#define wxDC_GetMultiLineTextExtent_1 679
+#define wxDC_GetPartialTextExtents 680
+#define wxDC_GetPen 681
+#define wxDC_GetPixel 682
+#define wxDC_GetPPI 683
+#define wxDC_GetSize 685
+#define wxDC_GetSizeMM 687
+#define wxDC_GetTextBackground 688
+#define wxDC_GetTextExtent_4 689
+#define wxDC_GetTextExtent_1 690
+#define wxDC_GetTextForeground 692
+#define wxDC_GetUserScale 693
+#define wxDC_GradientFillConcentric_3 694
+#define wxDC_GradientFillConcentric_4 695
+#define wxDC_GradientFillLinear 696
+#define wxDC_LogicalToDeviceX 697
+#define wxDC_LogicalToDeviceXRel 698
+#define wxDC_LogicalToDeviceY 699
+#define wxDC_LogicalToDeviceYRel 700
+#define wxDC_MaxX 701
+#define wxDC_MaxY 702
+#define wxDC_MinX 703
+#define wxDC_MinY 704
+#define wxDC_IsOk 705
+#define wxDC_ResetBoundingBox 706
+#define wxDC_SetAxisOrientation 707
+#define wxDC_SetBackground 708
+#define wxDC_SetBackgroundMode 709
+#define wxDC_SetBrush 710
+#define wxDC_SetClippingRegion_2 712
+#define wxDC_SetClippingRegion_1_1 713
+#define wxDC_SetClippingRegion_1_0 714
+#define wxDC_SetDeviceOrigin 715
+#define wxDC_SetFont 716
+#define wxDC_SetLayoutDirection 717
+#define wxDC_SetLogicalFunction 718
+#define wxDC_SetMapMode 719
+#define wxDC_SetPalette 720
+#define wxDC_SetPen 721
+#define wxDC_SetTextBackground 722
+#define wxDC_SetTextForeground 723
+#define wxDC_SetUserScale 724
+#define wxDC_StartDoc 725
+#define wxDC_StartPage 726
+#define wxMirrorDC_new 727
+#define wxMirrorDC_destroy 728
+#define wxScreenDC_new 729
+#define wxScreenDC_destruct 730
+#define wxPostScriptDC_new_0 731
+#define wxPostScriptDC_new_1 732
+#define wxPostScriptDC_destruct 733
+#define wxPostScriptDC_SetResolution 734
+#define wxPostScriptDC_GetResolution 735
+#define wxWindowDC_new_0 736
+#define wxWindowDC_new_1 737
+#define wxWindowDC_destruct 738
+#define wxClientDC_new_0 739
+#define wxClientDC_new_1 740
+#define wxClientDC_destroy 741
+#define wxPaintDC_new_0 742
+#define wxPaintDC_new_1 743
+#define wxPaintDC_destroy 744
+#define wxMemoryDC_new_1_0 746
+#define wxMemoryDC_new_1_1 747
+#define wxMemoryDC_new_0 748
+#define wxMemoryDC_destruct 750
+#define wxMemoryDC_SelectObject 751
+#define wxMemoryDC_SelectObjectAsSource 752
+#define wxBufferedDC_new_0 753
+#define wxBufferedDC_new_2 754
+#define wxBufferedDC_new_3 755
+#define wxBufferedDC_destruct 756
+#define wxBufferedDC_Init_2 757
+#define wxBufferedDC_Init_3 758
+#define wxBufferedPaintDC_new_3 759
+#define wxBufferedPaintDC_new_2 760
+#define wxBufferedPaintDC_destruct 761
+#define wxGraphicsObject_destruct 762
+#define wxGraphicsObject_GetRenderer 763
+#define wxGraphicsObject_IsNull 764
+#define wxGraphicsContext_destruct 765
+#define wxGraphicsContext_Create_1_1 766
+#define wxGraphicsContext_Create_1_0 767
+#define wxGraphicsContext_Create_0 768
+#define wxGraphicsContext_CreatePen 769
+#define wxGraphicsContext_CreateBrush 770
+#define wxGraphicsContext_CreateRadialGradientBrush 771
+#define wxGraphicsContext_CreateLinearGradientBrush 772
+#define wxGraphicsContext_CreateFont 773
+#define wxGraphicsContext_CreateMatrix 774
+#define wxGraphicsContext_CreatePath 775
+#define wxGraphicsContext_Clip_1 776
+#define wxGraphicsContext_Clip_4 777
+#define wxGraphicsContext_ResetClip 778
+#define wxGraphicsContext_DrawBitmap 779
+#define wxGraphicsContext_DrawEllipse 780
+#define wxGraphicsContext_DrawIcon 781
+#define wxGraphicsContext_DrawLines 782
+#define wxGraphicsContext_DrawPath 783
+#define wxGraphicsContext_DrawRectangle 784
+#define wxGraphicsContext_DrawRoundedRectangle 785
+#define wxGraphicsContext_DrawText_3 786
+#define wxGraphicsContext_DrawText_4_0 787
+#define wxGraphicsContext_DrawText_4_1 788
+#define wxGraphicsContext_DrawText_5 789
+#define wxGraphicsContext_FillPath 790
+#define wxGraphicsContext_StrokePath 791
+#define wxGraphicsContext_GetPartialTextExtents 792
+#define wxGraphicsContext_GetTextExtent 793
+#define wxGraphicsContext_Rotate 794
+#define wxGraphicsContext_Scale 795
+#define wxGraphicsContext_Translate 796
+#define wxGraphicsContext_GetTransform 797
+#define wxGraphicsContext_SetTransform 798
+#define wxGraphicsContext_ConcatTransform 799
+#define wxGraphicsContext_SetBrush_1_1 800
+#define wxGraphicsContext_SetBrush_1_0 801
+#define wxGraphicsContext_SetFont_1 802
+#define wxGraphicsContext_SetFont_2 803
+#define wxGraphicsContext_SetPen_1_0 804
+#define wxGraphicsContext_SetPen_1_1 805
+#define wxGraphicsContext_StrokeLine 806
+#define wxGraphicsContext_StrokeLines 807
+#define wxGraphicsMatrix_Concat 809
+#define wxGraphicsMatrix_Get 811
+#define wxGraphicsMatrix_Invert 812
+#define wxGraphicsMatrix_IsEqual 813
+#define wxGraphicsMatrix_IsIdentity 815
+#define wxGraphicsMatrix_Rotate 816
+#define wxGraphicsMatrix_Scale 817
+#define wxGraphicsMatrix_Translate 818
+#define wxGraphicsMatrix_Set 819
+#define wxGraphicsMatrix_TransformPoint 820
+#define wxGraphicsMatrix_TransformDistance 821
+#define wxGraphicsPath_MoveToPoint_2 822
+#define wxGraphicsPath_MoveToPoint_1 823
+#define wxGraphicsPath_AddArc_6 824
+#define wxGraphicsPath_AddArc_5 825
+#define wxGraphicsPath_AddArcToPoint 826
+#define wxGraphicsPath_AddCircle 827
+#define wxGraphicsPath_AddCurveToPoint_6 828
+#define wxGraphicsPath_AddCurveToPoint_3 829
+#define wxGraphicsPath_AddEllipse 830
+#define wxGraphicsPath_AddLineToPoint_2 831
+#define wxGraphicsPath_AddLineToPoint_1 832
+#define wxGraphicsPath_AddPath 833
+#define wxGraphicsPath_AddQuadCurveToPoint 834
+#define wxGraphicsPath_AddRectangle 835
+#define wxGraphicsPath_AddRoundedRectangle 836
+#define wxGraphicsPath_CloseSubpath 837
+#define wxGraphicsPath_Contains_3 838
+#define wxGraphicsPath_Contains_2 839
+#define wxGraphicsPath_GetBox 841
+#define wxGraphicsPath_GetCurrentPoint 843
+#define wxGraphicsPath_Transform 844
+#define wxGraphicsRenderer_GetDefaultRenderer 845
+#define wxGraphicsRenderer_CreateContext_1_1 846
+#define wxGraphicsRenderer_CreateContext_1_0 847
+#define wxGraphicsRenderer_CreatePen 848
+#define wxGraphicsRenderer_CreateBrush 849
+#define wxGraphicsRenderer_CreateLinearGradientBrush 850
+#define wxGraphicsRenderer_CreateRadialGradientBrush 851
+#define wxGraphicsRenderer_CreateFont 852
+#define wxGraphicsRenderer_CreateMatrix 853
+#define wxGraphicsRenderer_CreatePath 854
+#define wxMenuBar_new_1 856
+#define wxMenuBar_new_0 858
+#define wxMenuBar_destruct 860
+#define wxMenuBar_Append 861
+#define wxMenuBar_Check 862
+#define wxMenuBar_Enable_2 863
+#define wxMenuBar_Enable_1 864
+#define wxMenuBar_EnableTop 865
+#define wxMenuBar_FindMenu 866
+#define wxMenuBar_FindMenuItem 867
+#define wxMenuBar_FindItem 868
+#define wxMenuBar_GetHelpString 869
+#define wxMenuBar_GetLabel_1 870
+#define wxMenuBar_GetLabel_0 871
+#define wxMenuBar_GetLabelTop 872
+#define wxMenuBar_GetMenu 873
+#define wxMenuBar_GetMenuCount 874
+#define wxMenuBar_Insert 875
+#define wxMenuBar_IsChecked 876
+#define wxMenuBar_IsEnabled_1 877
+#define wxMenuBar_IsEnabled_0 878
+#define wxMenuBar_Remove 879
+#define wxMenuBar_Replace 880
+#define wxMenuBar_SetHelpString 881
+#define wxMenuBar_SetLabel_2 882
+#define wxMenuBar_SetLabel_1 883
+#define wxMenuBar_SetLabelTop 884
+#define wxControl_GetLabel 885
+#define wxControl_SetLabel 886
+#define wxControlWithItems_Append_1 887
+#define wxControlWithItems_Append_2 888
+#define wxControlWithItems_appendStrings_1 889
+#define wxControlWithItems_Clear 890
+#define wxControlWithItems_Delete 891
+#define wxControlWithItems_FindString 892
+#define wxControlWithItems_getClientData 893
+#define wxControlWithItems_setClientData 894
+#define wxControlWithItems_GetCount 895
+#define wxControlWithItems_GetSelection 896
+#define wxControlWithItems_GetString 897
+#define wxControlWithItems_GetStringSelection 898
+#define wxControlWithItems_Insert_2 899
+#define wxControlWithItems_Insert_3 900
+#define wxControlWithItems_IsEmpty 901
+#define wxControlWithItems_Select 902
+#define wxControlWithItems_SetSelection 903
+#define wxControlWithItems_SetString 904
+#define wxControlWithItems_SetStringSelection 905
+#define wxMenu_new_2 908
+#define wxMenu_new_1 909
+#define wxMenu_destruct 911
+#define wxMenu_Append_3 912
+#define wxMenu_Append_1 913
+#define wxMenu_Append_4_0 914
+#define wxMenu_Append_4_1 915
+#define wxMenu_AppendCheckItem 916
+#define wxMenu_AppendRadioItem 917
+#define wxMenu_AppendSeparator 918
+#define wxMenu_Break 919
+#define wxMenu_Check 920
+#define wxMenu_Delete_1_0 921
+#define wxMenu_Delete_1_1 922
+#define wxMenu_Destroy_1_0 923
+#define wxMenu_Destroy_1_1 924
+#define wxMenu_Enable 925
+#define wxMenu_FindItem_1 926
+#define wxMenu_FindItem_2 927
+#define wxMenu_FindItemByPosition 928
+#define wxMenu_GetHelpString 929
+#define wxMenu_GetLabel 930
+#define wxMenu_GetMenuItemCount 931
+#define wxMenu_GetMenuItems 932
+#define wxMenu_GetTitle 934
+#define wxMenu_Insert_2 935
+#define wxMenu_Insert_3 936
+#define wxMenu_Insert_5_1 937
+#define wxMenu_Insert_5_0 938
+#define wxMenu_InsertCheckItem 939
+#define wxMenu_InsertRadioItem 940
+#define wxMenu_InsertSeparator 941
+#define wxMenu_IsChecked 942
+#define wxMenu_IsEnabled 943
+#define wxMenu_Prepend_1 944
+#define wxMenu_Prepend_2 945
+#define wxMenu_Prepend_4_1 946
+#define wxMenu_Prepend_4_0 947
+#define wxMenu_PrependCheckItem 948
+#define wxMenu_PrependRadioItem 949
+#define wxMenu_PrependSeparator 950
+#define wxMenu_Remove_1_0 951
+#define wxMenu_Remove_1_1 952
+#define wxMenu_SetHelpString 953
+#define wxMenu_SetLabel 954
+#define wxMenu_SetTitle 955
+#define wxMenuItem_new 956
+#define wxMenuItem_destruct 958
+#define wxMenuItem_Check 959
+#define wxMenuItem_Enable 960
+#define wxMenuItem_GetBitmap 961
+#define wxMenuItem_GetHelp 962
+#define wxMenuItem_GetId 963
+#define wxMenuItem_GetKind 964
+#define wxMenuItem_GetLabel 965
+#define wxMenuItem_GetLabelFromText 966
+#define wxMenuItem_GetMenu 967
+#define wxMenuItem_GetText 968
+#define wxMenuItem_GetSubMenu 969
+#define wxMenuItem_IsCheckable 970
+#define wxMenuItem_IsChecked 971
+#define wxMenuItem_IsEnabled 972
+#define wxMenuItem_IsSeparator 973
+#define wxMenuItem_IsSubMenu 974
+#define wxMenuItem_SetBitmap 975
+#define wxMenuItem_SetHelp 976
+#define wxMenuItem_SetMenu 977
+#define wxMenuItem_SetSubMenu 978
+#define wxMenuItem_SetText 979
+#define wxToolBar_AddControl 980
+#define wxToolBar_AddSeparator 981
+#define wxToolBar_AddTool_5 982
+#define wxToolBar_AddTool_4_0 983
+#define wxToolBar_AddTool_1 984
+#define wxToolBar_AddTool_4_1 985
+#define wxToolBar_AddTool_3 986
+#define wxToolBar_AddTool_6 987
+#define wxToolBar_AddCheckTool 988
+#define wxToolBar_AddRadioTool 989
+#define wxToolBar_AddStretchableSpace 990
+#define wxToolBar_InsertStretchableSpace 991
+#define wxToolBar_DeleteTool 992
+#define wxToolBar_DeleteToolByPos 993
+#define wxToolBar_EnableTool 994
+#define wxToolBar_FindById 995
+#define wxToolBar_FindControl 996
+#define wxToolBar_FindToolForPosition 997
+#define wxToolBar_GetToolSize 998
+#define wxToolBar_GetToolBitmapSize 999
+#define wxToolBar_GetMargins 1000
+#define wxToolBar_GetToolEnabled 1001
+#define wxToolBar_GetToolLongHelp 1002
+#define wxToolBar_GetToolPacking 1003
+#define wxToolBar_GetToolPos 1004
+#define wxToolBar_GetToolSeparation 1005
+#define wxToolBar_GetToolShortHelp 1006
+#define wxToolBar_GetToolState 1007
+#define wxToolBar_InsertControl 1008
+#define wxToolBar_InsertSeparator 1009
+#define wxToolBar_InsertTool_5 1010
+#define wxToolBar_InsertTool_2 1011
+#define wxToolBar_InsertTool_4 1012
+#define wxToolBar_Realize 1013
+#define wxToolBar_RemoveTool 1014
+#define wxToolBar_SetMargins 1015
+#define wxToolBar_SetToolBitmapSize 1016
+#define wxToolBar_SetToolLongHelp 1017
+#define wxToolBar_SetToolPacking 1018
+#define wxToolBar_SetToolShortHelp 1019
+#define wxToolBar_SetToolSeparation 1020
+#define wxToolBar_ToggleTool 1021
+#define wxStatusBar_new_0 1023
+#define wxStatusBar_new_2 1024
+#define wxStatusBar_destruct 1026
+#define wxStatusBar_Create 1027
+#define wxStatusBar_GetFieldRect 1028
+#define wxStatusBar_GetFieldsCount 1029
+#define wxStatusBar_GetStatusText 1030
+#define wxStatusBar_PopStatusText 1031
+#define wxStatusBar_PushStatusText 1032
+#define wxStatusBar_SetFieldsCount 1033
+#define wxStatusBar_SetMinHeight 1034
+#define wxStatusBar_SetStatusText 1035
+#define wxStatusBar_SetStatusWidths 1036
+#define wxStatusBar_SetStatusStyles 1037
+#define wxBitmap_new_0 1038
+#define wxBitmap_new_3 1039
+#define wxBitmap_new_4 1040
+#define wxBitmap_new_2_0 1041
+#define wxBitmap_new_2_1 1042
+#define wxBitmap_destruct 1043
+#define wxBitmap_ConvertToImage 1044
+#define wxBitmap_CopyFromIcon 1045
+#define wxBitmap_Create 1046
+#define wxBitmap_GetDepth 1047
+#define wxBitmap_GetHeight 1048
+#define wxBitmap_GetPalette 1049
+#define wxBitmap_GetMask 1050
+#define wxBitmap_GetWidth 1051
+#define wxBitmap_GetSubBitmap 1052
+#define wxBitmap_LoadFile 1053
+#define wxBitmap_Ok 1054
+#define wxBitmap_SaveFile 1055
+#define wxBitmap_SetDepth 1056
+#define wxBitmap_SetHeight 1057
+#define wxBitmap_SetMask 1058
+#define wxBitmap_SetPalette 1059
+#define wxBitmap_SetWidth 1060
+#define wxIcon_new_0 1061
+#define wxIcon_new_2 1062
+#define wxIcon_new_1 1063
+#define wxIcon_CopyFromBitmap 1064
+#define wxIcon_destroy 1065
+#define wxIconBundle_new_0 1066
+#define wxIconBundle_new_2 1067
+#define wxIconBundle_new_1_0 1068
+#define wxIconBundle_new_1_1 1069
+#define wxIconBundle_destruct 1070
+#define wxIconBundle_AddIcon_2 1071
+#define wxIconBundle_AddIcon_1 1072
+#define wxIconBundle_GetIcon_1_1 1073
+#define wxIconBundle_GetIcon_1_0 1074
+#define wxCursor_new_0 1075
+#define wxCursor_new_1_0 1076
+#define wxCursor_new_1_1 1077
+#define wxCursor_new_4 1078
+#define wxCursor_destruct 1079
+#define wxCursor_Ok 1080
+#define wxMask_new_0 1081
+#define wxMask_new_2_1 1082
+#define wxMask_new_2_0 1083
+#define wxMask_new_1 1084
+#define wxMask_destruct 1085
+#define wxMask_Create_2_1 1086
+#define wxMask_Create_2_0 1087
+#define wxMask_Create_1 1088
+#define wxImage_new_0 1089
+#define wxImage_new_3_0 1090
+#define wxImage_new_4 1091
+#define wxImage_new_5 1092
+#define wxImage_new_2 1093
+#define wxImage_new_3_1 1094
+#define wxImage_Blur 1095
+#define wxImage_BlurHorizontal 1096
+#define wxImage_BlurVertical 1097
+#define wxImage_ConvertAlphaToMask 1098
+#define wxImage_ConvertToGreyscale 1099
+#define wxImage_ConvertToMono 1100
+#define wxImage_Copy 1101
+#define wxImage_Create_3 1102
+#define wxImage_Create_4 1103
+#define wxImage_Create_5 1104
+#define wxImage_Destroy 1105
+#define wxImage_FindFirstUnusedColour 1106
+#define wxImage_GetImageExtWildcard 1107
+#define wxImage_GetAlpha_2 1108
+#define wxImage_GetAlpha_0 1109
+#define wxImage_GetBlue 1110
+#define wxImage_GetData 1111
+#define wxImage_GetGreen 1112
+#define wxImage_GetImageCount 1113
+#define wxImage_GetHeight 1114
+#define wxImage_GetMaskBlue 1115
+#define wxImage_GetMaskGreen 1116
+#define wxImage_GetMaskRed 1117
+#define wxImage_GetOrFindMaskColour 1118
+#define wxImage_GetPalette 1119
+#define wxImage_GetRed 1120
+#define wxImage_GetSubImage 1121
+#define wxImage_GetWidth 1122
+#define wxImage_HasAlpha 1123
+#define wxImage_HasMask 1124
+#define wxImage_GetOption 1125
+#define wxImage_GetOptionInt 1126
+#define wxImage_HasOption 1127
+#define wxImage_InitAlpha 1128
+#define wxImage_InitStandardHandlers 1129
+#define wxImage_IsTransparent 1130
+#define wxImage_LoadFile_2 1131
+#define wxImage_LoadFile_3 1132
+#define wxImage_Ok 1133
+#define wxImage_RemoveHandler 1134
+#define wxImage_Mirror 1135
+#define wxImage_Replace 1136
+#define wxImage_Rescale 1137
+#define wxImage_Resize 1138
+#define wxImage_Rotate 1139
+#define wxImage_RotateHue 1140
+#define wxImage_Rotate90 1141
+#define wxImage_SaveFile_1 1142
+#define wxImage_SaveFile_2_0 1143
+#define wxImage_SaveFile_2_1 1144
+#define wxImage_Scale 1145
+#define wxImage_Size 1146
+#define wxImage_SetAlpha_3 1147
+#define wxImage_SetAlpha_2 1148
+#define wxImage_SetData_2 1149
+#define wxImage_SetData_4 1150
+#define wxImage_SetMask 1151
+#define wxImage_SetMaskColour 1152
+#define wxImage_SetMaskFromImage 1153
+#define wxImage_SetOption_2_1 1154
+#define wxImage_SetOption_2_0 1155
+#define wxImage_SetPalette 1156
+#define wxImage_SetRGB_5 1157
+#define wxImage_SetRGB_4 1158
+#define wxImage_destroy 1159
+#define wxBrush_new_0 1160
+#define wxBrush_new_2 1161
+#define wxBrush_new_1 1162
+#define wxBrush_destruct 1164
+#define wxBrush_GetColour 1165
+#define wxBrush_GetStipple 1166
+#define wxBrush_GetStyle 1167
+#define wxBrush_IsHatch 1168
+#define wxBrush_IsOk 1169
+#define wxBrush_SetColour_1 1170
+#define wxBrush_SetColour_3 1171
+#define wxBrush_SetStipple 1172
+#define wxBrush_SetStyle 1173
+#define wxPen_new_0 1174
+#define wxPen_new_2 1175
+#define wxPen_destruct 1176
+#define wxPen_GetCap 1177
+#define wxPen_GetColour 1178
+#define wxPen_GetJoin 1179
+#define wxPen_GetStyle 1180
+#define wxPen_GetWidth 1181
+#define wxPen_IsOk 1182
+#define wxPen_SetCap 1183
+#define wxPen_SetColour_1 1184
+#define wxPen_SetColour_3 1185
+#define wxPen_SetJoin 1186
+#define wxPen_SetStyle 1187
+#define wxPen_SetWidth 1188
+#define wxRegion_new_0 1189
+#define wxRegion_new_4 1190
+#define wxRegion_new_2 1191
+#define wxRegion_new_1_1 1192
+#define wxRegion_new_1_0 1194
+#define wxRegion_destruct 1196
+#define wxRegion_Clear 1197
+#define wxRegion_Contains_2 1198
+#define wxRegion_Contains_1_0 1199
+#define wxRegion_Contains_4 1200
+#define wxRegion_Contains_1_1 1201
+#define wxRegion_ConvertToBitmap 1202
+#define wxRegion_GetBox 1203
+#define wxRegion_Intersect_4 1204
+#define wxRegion_Intersect_1_1 1205
+#define wxRegion_Intersect_1_0 1206
+#define wxRegion_IsEmpty 1207
+#define wxRegion_Subtract_4 1208
+#define wxRegion_Subtract_1_1 1209
+#define wxRegion_Subtract_1_0 1210
+#define wxRegion_Offset_2 1211
+#define wxRegion_Offset_1 1212
+#define wxRegion_Union_4 1213
+#define wxRegion_Union_1_2 1214
+#define wxRegion_Union_1_1 1215
+#define wxRegion_Union_1_0 1216
+#define wxRegion_Union_3 1217
+#define wxRegion_Xor_4 1218
+#define wxRegion_Xor_1_1 1219
+#define wxRegion_Xor_1_0 1220
+#define wxAcceleratorTable_new_0 1221
+#define wxAcceleratorTable_new_2 1222
+#define wxAcceleratorTable_destruct 1223
+#define wxAcceleratorTable_Ok 1224
+#define wxAcceleratorEntry_new_1_0 1225
+#define wxAcceleratorEntry_new_1_1 1226
+#define wxAcceleratorEntry_GetCommand 1227
+#define wxAcceleratorEntry_GetFlags 1228
+#define wxAcceleratorEntry_GetKeyCode 1229
+#define wxAcceleratorEntry_Set 1230
+#define wxAcceleratorEntry_destroy 1231
+#define wxCaret_new_3 1236
+#define wxCaret_new_2 1237
+#define wxCaret_destruct 1239
+#define wxCaret_Create_3 1240
+#define wxCaret_Create_2 1241
+#define wxCaret_GetBlinkTime 1242
+#define wxCaret_GetPosition 1244
+#define wxCaret_GetSize 1246
+#define wxCaret_GetWindow 1247
+#define wxCaret_Hide 1248
+#define wxCaret_IsOk 1249
+#define wxCaret_IsVisible 1250
+#define wxCaret_Move_2 1251
+#define wxCaret_Move_1 1252
+#define wxCaret_SetBlinkTime 1253
+#define wxCaret_SetSize_2 1254
+#define wxCaret_SetSize_1 1255
+#define wxCaret_Show 1256
+#define wxSizer_Add_2_1 1257
+#define wxSizer_Add_2_0 1258
+#define wxSizer_Add_3 1259
+#define wxSizer_Add_2_3 1260
+#define wxSizer_Add_2_2 1261
+#define wxSizer_AddSpacer 1262
+#define wxSizer_AddStretchSpacer 1263
+#define wxSizer_CalcMin 1264
+#define wxSizer_Clear 1265
+#define wxSizer_Detach_1_2 1266
+#define wxSizer_Detach_1_1 1267
+#define wxSizer_Detach_1_0 1268
+#define wxSizer_Fit 1269
+#define wxSizer_FitInside 1270
+#define wxSizer_GetChildren 1271
+#define wxSizer_GetItem_2_1 1272
+#define wxSizer_GetItem_2_0 1273
+#define wxSizer_GetItem_1 1274
+#define wxSizer_GetSize 1275
+#define wxSizer_GetPosition 1276
+#define wxSizer_GetMinSize 1277
+#define wxSizer_Hide_2_0 1278
+#define wxSizer_Hide_2_1 1279
+#define wxSizer_Hide_1 1280
+#define wxSizer_Insert_3_1 1281
+#define wxSizer_Insert_3_0 1282
+#define wxSizer_Insert_4 1283
+#define wxSizer_Insert_3_3 1284
+#define wxSizer_Insert_3_2 1285
+#define wxSizer_Insert_2 1286
+#define wxSizer_InsertSpacer 1287
+#define wxSizer_InsertStretchSpacer 1288
+#define wxSizer_IsShown_1_2 1289
+#define wxSizer_IsShown_1_1 1290
+#define wxSizer_IsShown_1_0 1291
+#define wxSizer_Layout 1292
+#define wxSizer_Prepend_2_1 1293
+#define wxSizer_Prepend_2_0 1294
+#define wxSizer_Prepend_3 1295
+#define wxSizer_Prepend_2_3 1296
+#define wxSizer_Prepend_2_2 1297
+#define wxSizer_Prepend_1 1298
+#define wxSizer_PrependSpacer 1299
+#define wxSizer_PrependStretchSpacer 1300
+#define wxSizer_RecalcSizes 1301
+#define wxSizer_Remove_1_1 1302
+#define wxSizer_Remove_1_0 1303
+#define wxSizer_Replace_3_1 1304
+#define wxSizer_Replace_3_0 1305
+#define wxSizer_Replace_2 1306
+#define wxSizer_SetDimension 1307
+#define wxSizer_SetMinSize_2 1308
+#define wxSizer_SetMinSize_1 1309
+#define wxSizer_SetItemMinSize_3_2 1310
+#define wxSizer_SetItemMinSize_2_2 1311
+#define wxSizer_SetItemMinSize_3_1 1312
+#define wxSizer_SetItemMinSize_2_1 1313
+#define wxSizer_SetItemMinSize_3_0 1314
+#define wxSizer_SetItemMinSize_2_0 1315
+#define wxSizer_SetSizeHints 1316
+#define wxSizer_SetVirtualSizeHints 1317
+#define wxSizer_Show_2_2 1318
+#define wxSizer_Show_2_1 1319
+#define wxSizer_Show_2_0 1320
+#define wxSizer_Show_1 1321
+#define wxSizerFlags_new 1322
+#define wxSizerFlags_Align 1323
+#define wxSizerFlags_Border_2 1324
+#define wxSizerFlags_Border_1 1325
+#define wxSizerFlags_Center 1326
+#define wxSizerFlags_Centre 1327
+#define wxSizerFlags_Expand 1328
+#define wxSizerFlags_Left 1329
+#define wxSizerFlags_Proportion 1330
+#define wxSizerFlags_Right 1331
+#define wxSizerFlags_destroy 1332
+#define wxSizerItem_new_5_1 1333
+#define wxSizerItem_new_2_1 1334
+#define wxSizerItem_new_5_0 1335
+#define wxSizerItem_new_2_0 1336
+#define wxSizerItem_new_6 1337
+#define wxSizerItem_new_3 1338
+#define wxSizerItem_new_0 1339
+#define wxSizerItem_destruct 1340
+#define wxSizerItem_CalcMin 1341
+#define wxSizerItem_DeleteWindows 1342
+#define wxSizerItem_DetachSizer 1343
+#define wxSizerItem_GetBorder 1344
+#define wxSizerItem_GetFlag 1345
+#define wxSizerItem_GetMinSize 1346
+#define wxSizerItem_GetPosition 1347
+#define wxSizerItem_GetProportion 1348
+#define wxSizerItem_GetRatio 1349
+#define wxSizerItem_GetRect 1350
+#define wxSizerItem_GetSize 1351
+#define wxSizerItem_GetSizer 1352
+#define wxSizerItem_GetSpacer 1353
+#define wxSizerItem_GetUserData 1354
+#define wxSizerItem_GetWindow 1355
+#define wxSizerItem_IsSizer 1356
+#define wxSizerItem_IsShown 1357
+#define wxSizerItem_IsSpacer 1358
+#define wxSizerItem_IsWindow 1359
+#define wxSizerItem_SetBorder 1360
+#define wxSizerItem_SetDimension 1361
+#define wxSizerItem_SetFlag 1362
+#define wxSizerItem_SetInitSize 1363
+#define wxSizerItem_SetMinSize_1 1364
+#define wxSizerItem_SetMinSize_2 1365
+#define wxSizerItem_SetProportion 1366
+#define wxSizerItem_SetRatio_2 1367
+#define wxSizerItem_SetRatio_1_1 1368
+#define wxSizerItem_SetRatio_1_0 1369
+#define wxSizerItem_SetSizer 1370
+#define wxSizerItem_SetSpacer_1 1371
+#define wxSizerItem_SetSpacer_2 1372
+#define wxSizerItem_SetWindow 1373
+#define wxSizerItem_Show 1374
+#define wxBoxSizer_new 1375
+#define wxBoxSizer_GetOrientation 1376
+#define wxBoxSizer_destroy 1377
+#define wxStaticBoxSizer_new_2 1378
+#define wxStaticBoxSizer_new_3 1379
+#define wxStaticBoxSizer_GetStaticBox 1380
+#define wxStaticBoxSizer_destroy 1381
+#define wxGridSizer_new_4 1382
+#define wxGridSizer_new_2 1383
+#define wxGridSizer_GetCols 1384
+#define wxGridSizer_GetHGap 1385
+#define wxGridSizer_GetRows 1386
+#define wxGridSizer_GetVGap 1387
+#define wxGridSizer_SetCols 1388
+#define wxGridSizer_SetHGap 1389
+#define wxGridSizer_SetRows 1390
+#define wxGridSizer_SetVGap 1391
+#define wxGridSizer_destroy 1392
+#define wxFlexGridSizer_new_4 1393
+#define wxFlexGridSizer_new_2 1394
+#define wxFlexGridSizer_AddGrowableCol 1395
+#define wxFlexGridSizer_AddGrowableRow 1396
+#define wxFlexGridSizer_GetFlexibleDirection 1397
+#define wxFlexGridSizer_GetNonFlexibleGrowMode 1398
+#define wxFlexGridSizer_RemoveGrowableCol 1399
+#define wxFlexGridSizer_RemoveGrowableRow 1400
+#define wxFlexGridSizer_SetFlexibleDirection 1401
+#define wxFlexGridSizer_SetNonFlexibleGrowMode 1402
+#define wxFlexGridSizer_destroy 1403
+#define wxGridBagSizer_new 1404
+#define wxGridBagSizer_Add_3_2 1405
+#define wxGridBagSizer_Add_3_1 1406
+#define wxGridBagSizer_Add_4 1407
+#define wxGridBagSizer_Add_1_0 1408
+#define wxGridBagSizer_Add_2_1 1409
+#define wxGridBagSizer_Add_2_0 1410
+#define wxGridBagSizer_Add_3_0 1411
+#define wxGridBagSizer_Add_1_1 1412
+#define wxGridBagSizer_CalcMin 1413
+#define wxGridBagSizer_CheckForIntersection_2 1414
+#define wxGridBagSizer_CheckForIntersection_3 1415
+#define wxGridBagSizer_FindItem_1_1 1416
+#define wxGridBagSizer_FindItem_1_0 1417
+#define wxGridBagSizer_FindItemAtPoint 1418
+#define wxGridBagSizer_FindItemAtPosition 1419
+#define wxGridBagSizer_FindItemWithData 1420
+#define wxGridBagSizer_GetCellSize 1421
+#define wxGridBagSizer_GetEmptyCellSize 1422
+#define wxGridBagSizer_GetItemPosition_1_2 1423
+#define wxGridBagSizer_GetItemPosition_1_1 1424
+#define wxGridBagSizer_GetItemPosition_1_0 1425
+#define wxGridBagSizer_GetItemSpan_1_2 1426
+#define wxGridBagSizer_GetItemSpan_1_1 1427
+#define wxGridBagSizer_GetItemSpan_1_0 1428
+#define wxGridBagSizer_SetEmptyCellSize 1429
+#define wxGridBagSizer_SetItemPosition_2_2 1430
+#define wxGridBagSizer_SetItemPosition_2_1 1431
+#define wxGridBagSizer_SetItemPosition_2_0 1432
+#define wxGridBagSizer_SetItemSpan_2_2 1433
+#define wxGridBagSizer_SetItemSpan_2_1 1434
+#define wxGridBagSizer_SetItemSpan_2_0 1435
+#define wxGridBagSizer_destroy 1436
+#define wxStdDialogButtonSizer_new 1437
+#define wxStdDialogButtonSizer_AddButton 1438
+#define wxStdDialogButtonSizer_Realize 1439
+#define wxStdDialogButtonSizer_SetAffirmativeButton 1440
+#define wxStdDialogButtonSizer_SetCancelButton 1441
+#define wxStdDialogButtonSizer_SetNegativeButton 1442
+#define wxStdDialogButtonSizer_destroy 1443
+#define wxFont_new_0 1444
+#define wxFont_new_1 1445
+#define wxFont_new_5 1446
+#define wxFont_destruct 1448
+#define wxFont_IsFixedWidth 1449
+#define wxFont_GetDefaultEncoding 1450
+#define wxFont_GetFaceName 1451
+#define wxFont_GetFamily 1452
+#define wxFont_GetNativeFontInfoDesc 1453
+#define wxFont_GetNativeFontInfoUserDesc 1454
+#define wxFont_GetPointSize 1455
+#define wxFont_GetStyle 1456
+#define wxFont_GetUnderlined 1457
+#define wxFont_GetWeight 1458
+#define wxFont_Ok 1459
+#define wxFont_SetDefaultEncoding 1460
+#define wxFont_SetFaceName 1461
+#define wxFont_SetFamily 1462
+#define wxFont_SetPointSize 1463
+#define wxFont_SetStyle 1464
+#define wxFont_SetUnderlined 1465
+#define wxFont_SetWeight 1466
+#define wxToolTip_Enable 1467
+#define wxToolTip_SetDelay 1468
+#define wxToolTip_new 1469
+#define wxToolTip_SetTip 1470
+#define wxToolTip_GetTip 1471
+#define wxToolTip_GetWindow 1472
+#define wxToolTip_destroy 1473
+#define wxButton_new_3 1475
+#define wxButton_new_0 1476
+#define wxButton_destruct 1477
+#define wxButton_Create 1478
+#define wxButton_GetDefaultSize 1479
+#define wxButton_SetDefault 1480
+#define wxButton_SetLabel 1481
+#define wxBitmapButton_new_4 1483
+#define wxBitmapButton_new_0 1484
+#define wxBitmapButton_Create 1485
+#define wxBitmapButton_GetBitmapDisabled 1486
+#define wxBitmapButton_GetBitmapFocus 1488
+#define wxBitmapButton_GetBitmapLabel 1490
+#define wxBitmapButton_GetBitmapSelected 1492
+#define wxBitmapButton_SetBitmapDisabled 1494
+#define wxBitmapButton_SetBitmapFocus 1495
+#define wxBitmapButton_SetBitmapLabel 1496
+#define wxBitmapButton_SetBitmapSelected 1497
+#define wxBitmapButton_destroy 1498
+#define wxToggleButton_new_0 1499
+#define wxToggleButton_new_4 1500
+#define wxToggleButton_Create 1501
+#define wxToggleButton_GetValue 1502
+#define wxToggleButton_SetValue 1503
+#define wxToggleButton_destroy 1504
+#define wxCalendarCtrl_new_0 1505
+#define wxCalendarCtrl_new_3 1506
+#define wxCalendarCtrl_Create 1507
+#define wxCalendarCtrl_destruct 1508
+#define wxCalendarCtrl_SetDate 1509
+#define wxCalendarCtrl_GetDate 1510
+#define wxCalendarCtrl_EnableYearChange 1511
+#define wxCalendarCtrl_EnableMonthChange 1512
+#define wxCalendarCtrl_EnableHolidayDisplay 1513
+#define wxCalendarCtrl_SetHeaderColours 1514
+#define wxCalendarCtrl_GetHeaderColourFg 1515
+#define wxCalendarCtrl_GetHeaderColourBg 1516
+#define wxCalendarCtrl_SetHighlightColours 1517
+#define wxCalendarCtrl_GetHighlightColourFg 1518
+#define wxCalendarCtrl_GetHighlightColourBg 1519
+#define wxCalendarCtrl_SetHolidayColours 1520
+#define wxCalendarCtrl_GetHolidayColourFg 1521
+#define wxCalendarCtrl_GetHolidayColourBg 1522
+#define wxCalendarCtrl_GetAttr 1523
+#define wxCalendarCtrl_SetAttr 1524
+#define wxCalendarCtrl_SetHoliday 1525
+#define wxCalendarCtrl_ResetAttr 1526
+#define wxCalendarCtrl_HitTest 1527
+#define wxCalendarDateAttr_new_0 1528
+#define wxCalendarDateAttr_new_2_1 1529
+#define wxCalendarDateAttr_new_2_0 1530
+#define wxCalendarDateAttr_SetTextColour 1531
+#define wxCalendarDateAttr_SetBackgroundColour 1532
+#define wxCalendarDateAttr_SetBorderColour 1533
+#define wxCalendarDateAttr_SetFont 1534
+#define wxCalendarDateAttr_SetBorder 1535
+#define wxCalendarDateAttr_SetHoliday 1536
+#define wxCalendarDateAttr_HasTextColour 1537
+#define wxCalendarDateAttr_HasBackgroundColour 1538
+#define wxCalendarDateAttr_HasBorderColour 1539
+#define wxCalendarDateAttr_HasFont 1540
+#define wxCalendarDateAttr_HasBorder 1541
+#define wxCalendarDateAttr_IsHoliday 1542
+#define wxCalendarDateAttr_GetTextColour 1543
+#define wxCalendarDateAttr_GetBackgroundColour 1544
+#define wxCalendarDateAttr_GetBorderColour 1545
+#define wxCalendarDateAttr_GetFont 1546
+#define wxCalendarDateAttr_GetBorder 1547
+#define wxCalendarDateAttr_destroy 1548
+#define wxCheckBox_new_4 1550
+#define wxCheckBox_new_0 1551
+#define wxCheckBox_Create 1552
+#define wxCheckBox_GetValue 1553
+#define wxCheckBox_Get3StateValue 1554
+#define wxCheckBox_Is3rdStateAllowedForUser 1555
+#define wxCheckBox_Is3State 1556
+#define wxCheckBox_IsChecked 1557
+#define wxCheckBox_SetValue 1558
+#define wxCheckBox_Set3StateValue 1559
+#define wxCheckBox_destroy 1560
+#define wxCheckListBox_new_0 1561
+#define wxCheckListBox_new_3 1563
+#define wxCheckListBox_Check 1564
+#define wxCheckListBox_IsChecked 1565
+#define wxCheckListBox_destroy 1566
+#define wxChoice_new_3 1569
+#define wxChoice_new_0 1570
+#define wxChoice_destruct 1572
+#define wxChoice_Create 1574
+#define wxChoice_Delete 1575
+#define wxChoice_GetColumns 1576
+#define wxChoice_SetColumns 1577
+#define wxComboBox_new_0 1578
+#define wxComboBox_new_3 1580
+#define wxComboBox_destruct 1581
+#define wxComboBox_Create 1583
+#define wxComboBox_CanCopy 1584
+#define wxComboBox_CanCut 1585
+#define wxComboBox_CanPaste 1586
+#define wxComboBox_CanRedo 1587
+#define wxComboBox_CanUndo 1588
+#define wxComboBox_Copy 1589
+#define wxComboBox_Cut 1590
+#define wxComboBox_GetInsertionPoint 1591
+#define wxComboBox_GetLastPosition 1592
+#define wxComboBox_GetValue 1593
+#define wxComboBox_Paste 1594
+#define wxComboBox_Redo 1595
+#define wxComboBox_Replace 1596
+#define wxComboBox_Remove 1597
+#define wxComboBox_SetInsertionPoint 1598
+#define wxComboBox_SetInsertionPointEnd 1599
+#define wxComboBox_SetSelection_1 1600
+#define wxComboBox_SetSelection_2 1601
+#define wxComboBox_SetValue 1602
+#define wxComboBox_Undo 1603
+#define wxGauge_new_0 1604
+#define wxGauge_new_4 1605
+#define wxGauge_Create 1606
+#define wxGauge_GetRange 1607
+#define wxGauge_GetValue 1608
+#define wxGauge_IsVertical 1609
+#define wxGauge_SetRange 1610
+#define wxGauge_SetValue 1611
+#define wxGauge_Pulse 1612
+#define wxGauge_destroy 1613
+#define wxGenericDirCtrl_new_0 1614
+#define wxGenericDirCtrl_new_2 1615
+#define wxGenericDirCtrl_destruct 1616
+#define wxGenericDirCtrl_Create 1617
+#define wxGenericDirCtrl_Init 1618
+#define wxGenericDirCtrl_CollapseTree 1619
+#define wxGenericDirCtrl_ExpandPath 1620
+#define wxGenericDirCtrl_GetDefaultPath 1621
+#define wxGenericDirCtrl_GetPath 1622
+#define wxGenericDirCtrl_GetFilePath 1623
+#define wxGenericDirCtrl_GetFilter 1624
+#define wxGenericDirCtrl_GetFilterIndex 1625
+#define wxGenericDirCtrl_GetRootId 1626
+#define wxGenericDirCtrl_GetTreeCtrl 1627
+#define wxGenericDirCtrl_ReCreateTree 1628
+#define wxGenericDirCtrl_SetDefaultPath 1629
+#define wxGenericDirCtrl_SetFilter 1630
+#define wxGenericDirCtrl_SetFilterIndex 1631
+#define wxGenericDirCtrl_SetPath 1632
+#define wxStaticBox_new_4 1634
+#define wxStaticBox_new_0 1635
+#define wxStaticBox_Create 1636
+#define wxStaticBox_destroy 1637
+#define wxStaticLine_new_2 1639
+#define wxStaticLine_new_0 1640
+#define wxStaticLine_Create 1641
+#define wxStaticLine_IsVertical 1642
+#define wxStaticLine_GetDefaultSize 1643
+#define wxStaticLine_destroy 1644
+#define wxListBox_new_3 1647
+#define wxListBox_new_0 1648
+#define wxListBox_destruct 1650
+#define wxListBox_Create 1652
+#define wxListBox_Deselect 1653
+#define wxListBox_GetSelections 1654
+#define wxListBox_InsertItems 1655
+#define wxListBox_IsSelected 1656
+#define wxListBox_Set 1657
+#define wxListBox_HitTest 1658
+#define wxListBox_SetFirstItem_1_0 1659
+#define wxListBox_SetFirstItem_1_1 1660
+#define wxListCtrl_new_0 1661
+#define wxListCtrl_new_2 1662
+#define wxListCtrl_Arrange 1663
+#define wxListCtrl_AssignImageList 1664
+#define wxListCtrl_ClearAll 1665
+#define wxListCtrl_Create 1666
+#define wxListCtrl_DeleteAllItems 1667
+#define wxListCtrl_DeleteColumn 1668
+#define wxListCtrl_DeleteItem 1669
+#define wxListCtrl_EditLabel 1670
+#define wxListCtrl_EnsureVisible 1671
+#define wxListCtrl_FindItem_3_0 1672
+#define wxListCtrl_FindItem_3_1 1673
+#define wxListCtrl_GetColumn 1674
+#define wxListCtrl_GetColumnCount 1675
+#define wxListCtrl_GetColumnWidth 1676
+#define wxListCtrl_GetCountPerPage 1677
+#define wxListCtrl_GetEditControl 1678
+#define wxListCtrl_GetImageList 1679
+#define wxListCtrl_GetItem 1680
+#define wxListCtrl_GetItemBackgroundColour 1681
+#define wxListCtrl_GetItemCount 1682
+#define wxListCtrl_GetItemData 1683
+#define wxListCtrl_GetItemFont 1684
+#define wxListCtrl_GetItemPosition 1685
+#define wxListCtrl_GetItemRect 1686
+#define wxListCtrl_GetItemSpacing 1687
+#define wxListCtrl_GetItemState 1688
+#define wxListCtrl_GetItemText 1689
+#define wxListCtrl_GetItemTextColour 1690
+#define wxListCtrl_GetNextItem 1691
+#define wxListCtrl_GetSelectedItemCount 1692
+#define wxListCtrl_GetTextColour 1693
+#define wxListCtrl_GetTopItem 1694
+#define wxListCtrl_GetViewRect 1695
+#define wxListCtrl_HitTest 1696
+#define wxListCtrl_InsertColumn_2 1697
+#define wxListCtrl_InsertColumn_3 1698
+#define wxListCtrl_InsertItem_1 1699
+#define wxListCtrl_InsertItem_2_1 1700
+#define wxListCtrl_InsertItem_2_0 1701
+#define wxListCtrl_InsertItem_3 1702
+#define wxListCtrl_RefreshItem 1703
+#define wxListCtrl_RefreshItems 1704
+#define wxListCtrl_ScrollList 1705
+#define wxListCtrl_SetBackgroundColour 1706
+#define wxListCtrl_SetColumn 1707
+#define wxListCtrl_SetColumnWidth 1708
+#define wxListCtrl_SetImageList 1709
+#define wxListCtrl_SetItem_1 1710
+#define wxListCtrl_SetItem_4 1711
+#define wxListCtrl_SetItemBackgroundColour 1712
+#define wxListCtrl_SetItemCount 1713
+#define wxListCtrl_SetItemData 1714
+#define wxListCtrl_SetItemFont 1715
+#define wxListCtrl_SetItemImage 1716
+#define wxListCtrl_SetItemColumnImage 1717
+#define wxListCtrl_SetItemPosition 1718
+#define wxListCtrl_SetItemState 1719
+#define wxListCtrl_SetItemText 1720
+#define wxListCtrl_SetItemTextColour 1721
+#define wxListCtrl_SetSingleStyle 1722
+#define wxListCtrl_SetTextColour 1723
+#define wxListCtrl_SetWindowStyleFlag 1724
+#define wxListCtrl_SortItems 1725
+#define wxListCtrl_destroy 1726
+#define wxListView_ClearColumnImage 1727
+#define wxListView_Focus 1728
+#define wxListView_GetFirstSelected 1729
+#define wxListView_GetFocusedItem 1730
+#define wxListView_GetNextSelected 1731
+#define wxListView_IsSelected 1732
+#define wxListView_Select 1733
+#define wxListView_SetColumnImage 1734
+#define wxListItem_new_0 1735
+#define wxListItem_new_1 1736
+#define wxListItem_destruct 1737
+#define wxListItem_Clear 1738
+#define wxListItem_GetAlign 1739
+#define wxListItem_GetBackgroundColour 1740
+#define wxListItem_GetColumn 1741
+#define wxListItem_GetFont 1742
+#define wxListItem_GetId 1743
+#define wxListItem_GetImage 1744
+#define wxListItem_GetMask 1745
+#define wxListItem_GetState 1746
+#define wxListItem_GetText 1747
+#define wxListItem_GetTextColour 1748
+#define wxListItem_GetWidth 1749
+#define wxListItem_SetAlign 1750
+#define wxListItem_SetBackgroundColour 1751
+#define wxListItem_SetColumn 1752
+#define wxListItem_SetFont 1753
+#define wxListItem_SetId 1754
+#define wxListItem_SetImage 1755
+#define wxListItem_SetMask 1756
+#define wxListItem_SetState 1757
+#define wxListItem_SetStateMask 1758
+#define wxListItem_SetText 1759
+#define wxListItem_SetTextColour 1760
+#define wxListItem_SetWidth 1761
+#define wxListItemAttr_new_0 1762
+#define wxListItemAttr_new_3 1763
+#define wxListItemAttr_GetBackgroundColour 1764
+#define wxListItemAttr_GetFont 1765
+#define wxListItemAttr_GetTextColour 1766
+#define wxListItemAttr_HasBackgroundColour 1767
+#define wxListItemAttr_HasFont 1768
+#define wxListItemAttr_HasTextColour 1769
+#define wxListItemAttr_SetBackgroundColour 1770
+#define wxListItemAttr_SetFont 1771
+#define wxListItemAttr_SetTextColour 1772
+#define wxListItemAttr_destroy 1773
+#define wxImageList_new_0 1774
+#define wxImageList_new_3 1775
+#define wxImageList_Add_1 1776
+#define wxImageList_Add_2_0 1777
+#define wxImageList_Add_2_1 1778
+#define wxImageList_Create 1779
+#define wxImageList_Draw 1781
+#define wxImageList_GetBitmap 1782
+#define wxImageList_GetIcon 1783
+#define wxImageList_GetImageCount 1784
+#define wxImageList_GetSize 1785
+#define wxImageList_Remove 1786
+#define wxImageList_RemoveAll 1787
+#define wxImageList_Replace_2 1788
+#define wxImageList_Replace_3 1789
+#define wxImageList_destroy 1790
+#define wxTextAttr_new_0 1791
+#define wxTextAttr_new_2 1792
+#define wxTextAttr_GetAlignment 1793
+#define wxTextAttr_GetBackgroundColour 1794
+#define wxTextAttr_GetFont 1795
+#define wxTextAttr_GetLeftIndent 1796
+#define wxTextAttr_GetLeftSubIndent 1797
+#define wxTextAttr_GetRightIndent 1798
+#define wxTextAttr_GetTabs 1799
+#define wxTextAttr_GetTextColour 1800
+#define wxTextAttr_HasBackgroundColour 1801
+#define wxTextAttr_HasFont 1802
+#define wxTextAttr_HasTextColour 1803
+#define wxTextAttr_GetFlags 1804
+#define wxTextAttr_IsDefault 1805
+#define wxTextAttr_SetAlignment 1806
+#define wxTextAttr_SetBackgroundColour 1807
+#define wxTextAttr_SetFlags 1808
+#define wxTextAttr_SetFont 1809
+#define wxTextAttr_SetLeftIndent 1810
+#define wxTextAttr_SetRightIndent 1811
+#define wxTextAttr_SetTabs 1812
+#define wxTextAttr_SetTextColour 1813
+#define wxTextAttr_destroy 1814
+#define wxTextCtrl_new_3 1816
+#define wxTextCtrl_new_0 1817
+#define wxTextCtrl_destruct 1819
+#define wxTextCtrl_AppendText 1820
+#define wxTextCtrl_CanCopy 1821
+#define wxTextCtrl_CanCut 1822
+#define wxTextCtrl_CanPaste 1823
+#define wxTextCtrl_CanRedo 1824
+#define wxTextCtrl_CanUndo 1825
+#define wxTextCtrl_Clear 1826
+#define wxTextCtrl_Copy 1827
+#define wxTextCtrl_Create 1828
+#define wxTextCtrl_Cut 1829
+#define wxTextCtrl_DiscardEdits 1830
+#define wxTextCtrl_ChangeValue 1831
+#define wxTextCtrl_EmulateKeyPress 1832
+#define wxTextCtrl_GetDefaultStyle 1833
+#define wxTextCtrl_GetInsertionPoint 1834
+#define wxTextCtrl_GetLastPosition 1835
+#define wxTextCtrl_GetLineLength 1836
+#define wxTextCtrl_GetLineText 1837
+#define wxTextCtrl_GetNumberOfLines 1838
+#define wxTextCtrl_GetRange 1839
+#define wxTextCtrl_GetSelection 1840
+#define wxTextCtrl_GetStringSelection 1841
+#define wxTextCtrl_GetStyle 1842
+#define wxTextCtrl_GetValue 1843
+#define wxTextCtrl_IsEditable 1844
+#define wxTextCtrl_IsModified 1845
+#define wxTextCtrl_IsMultiLine 1846
+#define wxTextCtrl_IsSingleLine 1847
+#define wxTextCtrl_LoadFile 1848
+#define wxTextCtrl_MarkDirty 1849
+#define wxTextCtrl_Paste 1850
+#define wxTextCtrl_PositionToXY 1851
+#define wxTextCtrl_Redo 1852
+#define wxTextCtrl_Remove 1853
+#define wxTextCtrl_Replace 1854
+#define wxTextCtrl_SaveFile 1855
+#define wxTextCtrl_SetDefaultStyle 1856
+#define wxTextCtrl_SetEditable 1857
+#define wxTextCtrl_SetInsertionPoint 1858
+#define wxTextCtrl_SetInsertionPointEnd 1859
+#define wxTextCtrl_SetMaxLength 1861
+#define wxTextCtrl_SetSelection 1862
+#define wxTextCtrl_SetStyle 1863
+#define wxTextCtrl_SetValue 1864
+#define wxTextCtrl_ShowPosition 1865
+#define wxTextCtrl_Undo 1866
+#define wxTextCtrl_WriteText 1867
+#define wxTextCtrl_XYToPosition 1868
+#define wxNotebook_new_0 1871
+#define wxNotebook_new_3 1872
+#define wxNotebook_destruct 1873
+#define wxNotebook_AddPage 1874
+#define wxNotebook_AdvanceSelection 1875
+#define wxNotebook_AssignImageList 1876
+#define wxNotebook_Create 1877
+#define wxNotebook_DeleteAllPages 1878
+#define wxNotebook_DeletePage 1879
+#define wxNotebook_RemovePage 1880
+#define wxNotebook_GetCurrentPage 1881
+#define wxNotebook_GetImageList 1882
+#define wxNotebook_GetPage 1884
+#define wxNotebook_GetPageCount 1885
+#define wxNotebook_GetPageImage 1886
+#define wxNotebook_GetPageText 1887
+#define wxNotebook_GetRowCount 1888
+#define wxNotebook_GetSelection 1889
+#define wxNotebook_GetThemeBackgroundColour 1890
+#define wxNotebook_HitTest 1892
+#define wxNotebook_InsertPage 1894
+#define wxNotebook_SetImageList 1895
+#define wxNotebook_SetPadding 1896
+#define wxNotebook_SetPageSize 1897
+#define wxNotebook_SetPageImage 1898
+#define wxNotebook_SetPageText 1899
+#define wxNotebook_SetSelection 1900
+#define wxNotebook_ChangeSelection 1901
+#define wxChoicebook_new_0 1902
+#define wxChoicebook_new_3 1903
+#define wxChoicebook_AddPage 1904
+#define wxChoicebook_AdvanceSelection 1905
+#define wxChoicebook_AssignImageList 1906
+#define wxChoicebook_Create 1907
+#define wxChoicebook_DeleteAllPages 1908
+#define wxChoicebook_DeletePage 1909
+#define wxChoicebook_RemovePage 1910
+#define wxChoicebook_GetCurrentPage 1911
+#define wxChoicebook_GetImageList 1912
+#define wxChoicebook_GetPage 1914
+#define wxChoicebook_GetPageCount 1915
+#define wxChoicebook_GetPageImage 1916
+#define wxChoicebook_GetPageText 1917
+#define wxChoicebook_GetSelection 1918
+#define wxChoicebook_HitTest 1919
+#define wxChoicebook_InsertPage 1920
+#define wxChoicebook_SetImageList 1921
+#define wxChoicebook_SetPageSize 1922
+#define wxChoicebook_SetPageImage 1923
+#define wxChoicebook_SetPageText 1924
+#define wxChoicebook_SetSelection 1925
+#define wxChoicebook_ChangeSelection 1926
+#define wxChoicebook_destroy 1927
+#define wxToolbook_new_0 1928
+#define wxToolbook_new_3 1929
+#define wxToolbook_AddPage 1930
+#define wxToolbook_AdvanceSelection 1931
+#define wxToolbook_AssignImageList 1932
+#define wxToolbook_Create 1933
+#define wxToolbook_DeleteAllPages 1934
+#define wxToolbook_DeletePage 1935
+#define wxToolbook_RemovePage 1936
+#define wxToolbook_GetCurrentPage 1937
+#define wxToolbook_GetImageList 1938
+#define wxToolbook_GetPage 1940
+#define wxToolbook_GetPageCount 1941
+#define wxToolbook_GetPageImage 1942
+#define wxToolbook_GetPageText 1943
+#define wxToolbook_GetSelection 1944
+#define wxToolbook_HitTest 1946
+#define wxToolbook_InsertPage 1947
+#define wxToolbook_SetImageList 1948
+#define wxToolbook_SetPageSize 1949
+#define wxToolbook_SetPageImage 1950
+#define wxToolbook_SetPageText 1951
+#define wxToolbook_SetSelection 1952
+#define wxToolbook_ChangeSelection 1953
+#define wxToolbook_destroy 1954
+#define wxListbook_new_0 1955
+#define wxListbook_new_3 1956
+#define wxListbook_AddPage 1957
+#define wxListbook_AdvanceSelection 1958
+#define wxListbook_AssignImageList 1959
+#define wxListbook_Create 1960
+#define wxListbook_DeleteAllPages 1961
+#define wxListbook_DeletePage 1962
+#define wxListbook_RemovePage 1963
+#define wxListbook_GetCurrentPage 1964
+#define wxListbook_GetImageList 1965
+#define wxListbook_GetPage 1967
+#define wxListbook_GetPageCount 1968
+#define wxListbook_GetPageImage 1969
+#define wxListbook_GetPageText 1970
+#define wxListbook_GetSelection 1971
+#define wxListbook_HitTest 1973
+#define wxListbook_InsertPage 1974
+#define wxListbook_SetImageList 1975
+#define wxListbook_SetPageSize 1976
+#define wxListbook_SetPageImage 1977
+#define wxListbook_SetPageText 1978
+#define wxListbook_SetSelection 1979
+#define wxListbook_ChangeSelection 1980
+#define wxListbook_destroy 1981
+#define wxTreebook_new_0 1982
+#define wxTreebook_new_3 1983
+#define wxTreebook_AddPage 1984
+#define wxTreebook_AdvanceSelection 1985
+#define wxTreebook_AssignImageList 1986
+#define wxTreebook_Create 1987
+#define wxTreebook_DeleteAllPages 1988
+#define wxTreebook_DeletePage 1989
+#define wxTreebook_RemovePage 1990
+#define wxTreebook_GetCurrentPage 1991
+#define wxTreebook_GetImageList 1992
+#define wxTreebook_GetPage 1994
+#define wxTreebook_GetPageCount 1995
+#define wxTreebook_GetPageImage 1996
+#define wxTreebook_GetPageText 1997
+#define wxTreebook_GetSelection 1998
+#define wxTreebook_ExpandNode 1999
+#define wxTreebook_IsNodeExpanded 2000
+#define wxTreebook_HitTest 2002
+#define wxTreebook_InsertPage 2003
+#define wxTreebook_InsertSubPage 2004
+#define wxTreebook_SetImageList 2005
+#define wxTreebook_SetPageSize 2006
+#define wxTreebook_SetPageImage 2007
+#define wxTreebook_SetPageText 2008
+#define wxTreebook_SetSelection 2009
+#define wxTreebook_ChangeSelection 2010
+#define wxTreebook_destroy 2011
+#define wxTreeCtrl_new_2 2014
+#define wxTreeCtrl_new_0 2015
+#define wxTreeCtrl_destruct 2017
+#define wxTreeCtrl_AddRoot 2018
+#define wxTreeCtrl_AppendItem 2019
+#define wxTreeCtrl_AssignImageList 2020
+#define wxTreeCtrl_AssignStateImageList 2021
+#define wxTreeCtrl_Collapse 2022
+#define wxTreeCtrl_CollapseAndReset 2023
+#define wxTreeCtrl_Create 2024
+#define wxTreeCtrl_Delete 2025
+#define wxTreeCtrl_DeleteAllItems 2026
+#define wxTreeCtrl_DeleteChildren 2027
+#define wxTreeCtrl_EditLabel 2028
+#define wxTreeCtrl_EnsureVisible 2029
+#define wxTreeCtrl_Expand 2030
+#define wxTreeCtrl_GetBoundingRect 2031
+#define wxTreeCtrl_GetChildrenCount 2033
+#define wxTreeCtrl_GetCount 2034
+#define wxTreeCtrl_GetEditControl 2035
+#define wxTreeCtrl_GetFirstChild 2036
+#define wxTreeCtrl_GetNextChild 2037
+#define wxTreeCtrl_GetFirstVisibleItem 2038
+#define wxTreeCtrl_GetImageList 2039
+#define wxTreeCtrl_GetIndent 2040
+#define wxTreeCtrl_GetItemBackgroundColour 2041
+#define wxTreeCtrl_GetItemData 2042
+#define wxTreeCtrl_GetItemFont 2043
+#define wxTreeCtrl_GetItemImage_1 2044
+#define wxTreeCtrl_GetItemImage_2 2045
+#define wxTreeCtrl_GetItemText 2046
+#define wxTreeCtrl_GetItemTextColour 2047
+#define wxTreeCtrl_GetLastChild 2048
+#define wxTreeCtrl_GetNextSibling 2049
+#define wxTreeCtrl_GetNextVisible 2050
+#define wxTreeCtrl_GetItemParent 2051
+#define wxTreeCtrl_GetPrevSibling 2052
+#define wxTreeCtrl_GetPrevVisible 2053
+#define wxTreeCtrl_GetRootItem 2054
+#define wxTreeCtrl_GetSelection 2055
+#define wxTreeCtrl_GetSelections 2056
+#define wxTreeCtrl_GetStateImageList 2057
+#define wxTreeCtrl_HitTest 2058
+#define wxTreeCtrl_InsertItem 2060
+#define wxTreeCtrl_IsBold 2061
+#define wxTreeCtrl_IsExpanded 2062
+#define wxTreeCtrl_IsSelected 2063
+#define wxTreeCtrl_IsVisible 2064
+#define wxTreeCtrl_ItemHasChildren 2065
+#define wxTreeCtrl_IsTreeItemIdOk 2066
+#define wxTreeCtrl_PrependItem 2067
+#define wxTreeCtrl_ScrollTo 2068
+#define wxTreeCtrl_SelectItem_1 2069
+#define wxTreeCtrl_SelectItem_2 2070
+#define wxTreeCtrl_SetIndent 2071
+#define wxTreeCtrl_SetImageList 2072
+#define wxTreeCtrl_SetItemBackgroundColour 2073
+#define wxTreeCtrl_SetItemBold 2074
+#define wxTreeCtrl_SetItemData 2075
+#define wxTreeCtrl_SetItemDropHighlight 2076
+#define wxTreeCtrl_SetItemFont 2077
+#define wxTreeCtrl_SetItemHasChildren 2078
+#define wxTreeCtrl_SetItemImage_2 2079
+#define wxTreeCtrl_SetItemImage_3 2080
+#define wxTreeCtrl_SetItemText 2081
+#define wxTreeCtrl_SetItemTextColour 2082
+#define wxTreeCtrl_SetStateImageList 2083
+#define wxTreeCtrl_SetWindowStyle 2084
+#define wxTreeCtrl_SortChildren 2085
+#define wxTreeCtrl_Toggle 2086
+#define wxTreeCtrl_ToggleItemSelection 2087
+#define wxTreeCtrl_Unselect 2088
+#define wxTreeCtrl_UnselectAll 2089
+#define wxTreeCtrl_UnselectItem 2090
+#define wxScrollBar_new_0 2091
+#define wxScrollBar_new_3 2092
+#define wxScrollBar_destruct 2093
+#define wxScrollBar_Create 2094
+#define wxScrollBar_GetRange 2095
+#define wxScrollBar_GetPageSize 2096
+#define wxScrollBar_GetThumbPosition 2097
+#define wxScrollBar_GetThumbSize 2098
+#define wxScrollBar_SetThumbPosition 2099
+#define wxScrollBar_SetScrollbar 2100
+#define wxSpinButton_new_2 2102
+#define wxSpinButton_new_0 2103
+#define wxSpinButton_Create 2104
+#define wxSpinButton_GetMax 2105
+#define wxSpinButton_GetMin 2106
+#define wxSpinButton_GetValue 2107
+#define wxSpinButton_SetRange 2108
+#define wxSpinButton_SetValue 2109
+#define wxSpinButton_destroy 2110
+#define wxSpinCtrl_new_0 2111
+#define wxSpinCtrl_new_2 2112
+#define wxSpinCtrl_Create 2114
+#define wxSpinCtrl_SetValue_1_1 2117
+#define wxSpinCtrl_SetValue_1_0 2118
+#define wxSpinCtrl_GetValue 2120
+#define wxSpinCtrl_SetRange 2122
+#define wxSpinCtrl_SetSelection 2123
+#define wxSpinCtrl_GetMin 2125
+#define wxSpinCtrl_GetMax 2127
+#define wxSpinCtrl_destroy 2128
+#define wxStaticText_new_0 2129
+#define wxStaticText_new_4 2130
+#define wxStaticText_Create 2131
+#define wxStaticText_GetLabel 2132
+#define wxStaticText_SetLabel 2133
+#define wxStaticText_Wrap 2134
+#define wxStaticText_destroy 2135
+#define wxStaticBitmap_new_0 2136
+#define wxStaticBitmap_new_4 2137
+#define wxStaticBitmap_Create 2138
+#define wxStaticBitmap_GetBitmap 2139
+#define wxStaticBitmap_SetBitmap 2140
+#define wxStaticBitmap_destroy 2141
+#define wxRadioBox_new 2142
+#define wxRadioBox_destruct 2144
+#define wxRadioBox_Create 2145
+#define wxRadioBox_Enable_2 2146
+#define wxRadioBox_Enable_1 2147
+#define wxRadioBox_GetSelection 2148
+#define wxRadioBox_GetString 2149
+#define wxRadioBox_SetSelection 2150
+#define wxRadioBox_Show_2 2151
+#define wxRadioBox_Show_1 2152
+#define wxRadioBox_GetColumnCount 2153
+#define wxRadioBox_GetItemHelpText 2154
+#define wxRadioBox_GetItemToolTip 2155
+#define wxRadioBox_GetItemFromPoint 2157
+#define wxRadioBox_GetRowCount 2158
+#define wxRadioBox_IsItemEnabled 2159
+#define wxRadioBox_IsItemShown 2160
+#define wxRadioBox_SetItemHelpText 2161
+#define wxRadioBox_SetItemToolTip 2162
+#define wxRadioButton_new_0 2163
+#define wxRadioButton_new_4 2164
+#define wxRadioButton_Create 2165
+#define wxRadioButton_GetValue 2166
+#define wxRadioButton_SetValue 2167
+#define wxRadioButton_destroy 2168
+#define wxSlider_new_6 2170
+#define wxSlider_new_0 2171
+#define wxSlider_Create 2172
+#define wxSlider_GetLineSize 2173
+#define wxSlider_GetMax 2174
+#define wxSlider_GetMin 2175
+#define wxSlider_GetPageSize 2176
+#define wxSlider_GetThumbLength 2177
+#define wxSlider_GetValue 2178
+#define wxSlider_SetLineSize 2179
+#define wxSlider_SetPageSize 2180
+#define wxSlider_SetRange 2181
+#define wxSlider_SetThumbLength 2182
+#define wxSlider_SetValue 2183
+#define wxSlider_destroy 2184
+#define wxDialog_new_4 2186
+#define wxDialog_new_0 2187
+#define wxDialog_destruct 2189
+#define wxDialog_Create 2190
+#define wxDialog_CreateButtonSizer 2191
+#define wxDialog_CreateStdDialogButtonSizer 2192
+#define wxDialog_EndModal 2193
+#define wxDialog_GetAffirmativeId 2194
+#define wxDialog_GetReturnCode 2195
+#define wxDialog_IsModal 2196
+#define wxDialog_SetAffirmativeId 2197
+#define wxDialog_SetReturnCode 2198
+#define wxDialog_Show 2199
+#define wxDialog_ShowModal 2200
+#define wxColourDialog_new_0 2201
+#define wxColourDialog_new_2 2202
+#define wxColourDialog_destruct 2203
+#define wxColourDialog_Create 2204
+#define wxColourDialog_GetColourData 2205
+#define wxColourData_new_0 2206
+#define wxColourData_new_1 2207
+#define wxColourData_destruct 2208
+#define wxColourData_GetChooseFull 2209
+#define wxColourData_GetColour 2210
+#define wxColourData_GetCustomColour 2212
+#define wxColourData_SetChooseFull 2213
+#define wxColourData_SetColour 2214
+#define wxColourData_SetCustomColour 2215
+#define wxPalette_new_0 2216
+#define wxPalette_new_4 2217
+#define wxPalette_destruct 2219
+#define wxPalette_Create 2220
+#define wxPalette_GetColoursCount 2221
+#define wxPalette_GetPixel 2222
+#define wxPalette_GetRGB 2223
+#define wxPalette_IsOk 2224
+#define wxDirDialog_new 2228
+#define wxDirDialog_destruct 2229
+#define wxDirDialog_GetPath 2230
+#define wxDirDialog_GetMessage 2231
+#define wxDirDialog_SetMessage 2232
+#define wxDirDialog_SetPath 2233
+#define wxFileDialog_new 2237
+#define wxFileDialog_destruct 2238
+#define wxFileDialog_GetDirectory 2239
+#define wxFileDialog_GetFilename 2240
+#define wxFileDialog_GetFilenames 2241
+#define wxFileDialog_GetFilterIndex 2242
+#define wxFileDialog_GetMessage 2243
+#define wxFileDialog_GetPath 2244
+#define wxFileDialog_GetPaths 2245
+#define wxFileDialog_GetWildcard 2246
+#define wxFileDialog_SetDirectory 2247
+#define wxFileDialog_SetFilename 2248
+#define wxFileDialog_SetFilterIndex 2249
+#define wxFileDialog_SetMessage 2250
+#define wxFileDialog_SetPath 2251
+#define wxFileDialog_SetWildcard 2252
+#define wxPickerBase_SetInternalMargin 2253
+#define wxPickerBase_GetInternalMargin 2254
+#define wxPickerBase_SetTextCtrlProportion 2255
+#define wxPickerBase_SetPickerCtrlProportion 2256
+#define wxPickerBase_GetTextCtrlProportion 2257
+#define wxPickerBase_GetPickerCtrlProportion 2258
+#define wxPickerBase_HasTextCtrl 2259
+#define wxPickerBase_GetTextCtrl 2260
+#define wxPickerBase_IsTextCtrlGrowable 2261
+#define wxPickerBase_SetPickerCtrlGrowable 2262
+#define wxPickerBase_SetTextCtrlGrowable 2263
+#define wxPickerBase_IsPickerCtrlGrowable 2264
+#define wxFilePickerCtrl_new_0 2265
+#define wxFilePickerCtrl_new_3 2266
+#define wxFilePickerCtrl_Create 2267
+#define wxFilePickerCtrl_GetPath 2268
+#define wxFilePickerCtrl_SetPath 2269
+#define wxFilePickerCtrl_destroy 2270
+#define wxDirPickerCtrl_new_0 2271
+#define wxDirPickerCtrl_new_3 2272
+#define wxDirPickerCtrl_Create 2273
+#define wxDirPickerCtrl_GetPath 2274
+#define wxDirPickerCtrl_SetPath 2275
+#define wxDirPickerCtrl_destroy 2276
+#define wxColourPickerCtrl_new_0 2277
+#define wxColourPickerCtrl_new_3 2278
+#define wxColourPickerCtrl_Create 2279
+#define wxColourPickerCtrl_GetColour 2280
+#define wxColourPickerCtrl_SetColour_1_1 2281
+#define wxColourPickerCtrl_SetColour_1_0 2282
+#define wxColourPickerCtrl_destroy 2283
+#define wxDatePickerCtrl_new_0 2284
+#define wxDatePickerCtrl_new_3 2285
+#define wxDatePickerCtrl_GetRange 2286
+#define wxDatePickerCtrl_GetValue 2287
+#define wxDatePickerCtrl_SetRange 2288
+#define wxDatePickerCtrl_SetValue 2289
+#define wxDatePickerCtrl_destroy 2290
+#define wxFontPickerCtrl_new_0 2291
+#define wxFontPickerCtrl_new_3 2292
+#define wxFontPickerCtrl_Create 2293
+#define wxFontPickerCtrl_GetSelectedFont 2294
+#define wxFontPickerCtrl_SetSelectedFont 2295
+#define wxFontPickerCtrl_GetMaxPointSize 2296
+#define wxFontPickerCtrl_SetMaxPointSize 2297
+#define wxFontPickerCtrl_destroy 2298
+#define wxFindReplaceDialog_new_0 2301
+#define wxFindReplaceDialog_new_4 2302
+#define wxFindReplaceDialog_destruct 2303
+#define wxFindReplaceDialog_Create 2304
+#define wxFindReplaceDialog_GetData 2305
+#define wxFindReplaceData_new_0 2306
+#define wxFindReplaceData_new_1 2307
+#define wxFindReplaceData_GetFindString 2308
+#define wxFindReplaceData_GetReplaceString 2309
+#define wxFindReplaceData_GetFlags 2310
+#define wxFindReplaceData_SetFlags 2311
+#define wxFindReplaceData_SetFindString 2312
+#define wxFindReplaceData_SetReplaceString 2313
+#define wxFindReplaceData_destroy 2314
+#define wxMultiChoiceDialog_new_0 2315
+#define wxMultiChoiceDialog_new_5 2317
+#define wxMultiChoiceDialog_GetSelections 2318
+#define wxMultiChoiceDialog_SetSelections 2319
+#define wxMultiChoiceDialog_destroy 2320
+#define wxSingleChoiceDialog_new_0 2321
+#define wxSingleChoiceDialog_new_5 2323
+#define wxSingleChoiceDialog_GetSelection 2324
+#define wxSingleChoiceDialog_GetStringSelection 2325
+#define wxSingleChoiceDialog_SetSelection 2326
+#define wxSingleChoiceDialog_destroy 2327
+#define wxTextEntryDialog_new 2328
+#define wxTextEntryDialog_GetValue 2329
+#define wxTextEntryDialog_SetValue 2330
+#define wxTextEntryDialog_destroy 2331
+#define wxPasswordEntryDialog_new 2332
+#define wxPasswordEntryDialog_destroy 2333
+#define wxFontData_new_0 2334
+#define wxFontData_new_1 2335
+#define wxFontData_destruct 2336
+#define wxFontData_EnableEffects 2337
+#define wxFontData_GetAllowSymbols 2338
+#define wxFontData_GetColour 2339
+#define wxFontData_GetChosenFont 2340
+#define wxFontData_GetEnableEffects 2341
+#define wxFontData_GetInitialFont 2342
+#define wxFontData_GetShowHelp 2343
+#define wxFontData_SetAllowSymbols 2344
+#define wxFontData_SetChosenFont 2345
+#define wxFontData_SetColour 2346
+#define wxFontData_SetInitialFont 2347
+#define wxFontData_SetRange 2348
+#define wxFontData_SetShowHelp 2349
+#define wxFontDialog_new_0 2353
+#define wxFontDialog_new_2 2355
+#define wxFontDialog_Create 2357
+#define wxFontDialog_GetFontData 2358
+#define wxFontDialog_destroy 2360
+#define wxProgressDialog_new 2361
+#define wxProgressDialog_destruct 2362
+#define wxProgressDialog_Resume 2363
+#define wxProgressDialog_Update_2 2364
+#define wxProgressDialog_Update_0 2365
+#define wxMessageDialog_new 2366
+#define wxMessageDialog_destruct 2367
+#define wxPageSetupDialog_new 2368
+#define wxPageSetupDialog_destruct 2369
+#define wxPageSetupDialog_GetPageSetupData 2370
+#define wxPageSetupDialog_ShowModal 2371
+#define wxPageSetupDialogData_new_0 2372
+#define wxPageSetupDialogData_new_1_0 2373
+#define wxPageSetupDialogData_new_1_1 2374
+#define wxPageSetupDialogData_destruct 2375
+#define wxPageSetupDialogData_EnableHelp 2376
+#define wxPageSetupDialogData_EnableMargins 2377
+#define wxPageSetupDialogData_EnableOrientation 2378
+#define wxPageSetupDialogData_EnablePaper 2379
+#define wxPageSetupDialogData_EnablePrinter 2380
+#define wxPageSetupDialogData_GetDefaultMinMargins 2381
+#define wxPageSetupDialogData_GetEnableMargins 2382
+#define wxPageSetupDialogData_GetEnableOrientation 2383
+#define wxPageSetupDialogData_GetEnablePaper 2384
+#define wxPageSetupDialogData_GetEnablePrinter 2385
+#define wxPageSetupDialogData_GetEnableHelp 2386
+#define wxPageSetupDialogData_GetDefaultInfo 2387
+#define wxPageSetupDialogData_GetMarginTopLeft 2388
+#define wxPageSetupDialogData_GetMarginBottomRight 2389
+#define wxPageSetupDialogData_GetMinMarginTopLeft 2390
+#define wxPageSetupDialogData_GetMinMarginBottomRight 2391
+#define wxPageSetupDialogData_GetPaperId 2392
+#define wxPageSetupDialogData_GetPaperSize 2393
+#define wxPageSetupDialogData_GetPrintData 2395
+#define wxPageSetupDialogData_IsOk 2396
+#define wxPageSetupDialogData_SetDefaultInfo 2397
+#define wxPageSetupDialogData_SetDefaultMinMargins 2398
+#define wxPageSetupDialogData_SetMarginTopLeft 2399
+#define wxPageSetupDialogData_SetMarginBottomRight 2400
+#define wxPageSetupDialogData_SetMinMarginTopLeft 2401
+#define wxPageSetupDialogData_SetMinMarginBottomRight 2402
+#define wxPageSetupDialogData_SetPaperId 2403
+#define wxPageSetupDialogData_SetPaperSize_1_1 2404
+#define wxPageSetupDialogData_SetPaperSize_1_0 2405
+#define wxPageSetupDialogData_SetPrintData 2406
+#define wxPrintDialog_new_2_0 2407
+#define wxPrintDialog_new_2_1 2408
+#define wxPrintDialog_destruct 2409
+#define wxPrintDialog_GetPrintDialogData 2410
+#define wxPrintDialog_GetPrintDC 2411
+#define wxPrintDialogData_new_0 2412
+#define wxPrintDialogData_new_1_1 2413
+#define wxPrintDialogData_new_1_0 2414
+#define wxPrintDialogData_destruct 2415
+#define wxPrintDialogData_EnableHelp 2416
+#define wxPrintDialogData_EnablePageNumbers 2417
+#define wxPrintDialogData_EnablePrintToFile 2418
+#define wxPrintDialogData_EnableSelection 2419
+#define wxPrintDialogData_GetAllPages 2420
+#define wxPrintDialogData_GetCollate 2421
+#define wxPrintDialogData_GetFromPage 2422
+#define wxPrintDialogData_GetMaxPage 2423
+#define wxPrintDialogData_GetMinPage 2424
+#define wxPrintDialogData_GetNoCopies 2425
+#define wxPrintDialogData_GetPrintData 2426
+#define wxPrintDialogData_GetPrintToFile 2427
+#define wxPrintDialogData_GetSelection 2428
+#define wxPrintDialogData_GetToPage 2429
+#define wxPrintDialogData_IsOk 2430
+#define wxPrintDialogData_SetCollate 2431
+#define wxPrintDialogData_SetFromPage 2432
+#define wxPrintDialogData_SetMaxPage 2433
+#define wxPrintDialogData_SetMinPage 2434
+#define wxPrintDialogData_SetNoCopies 2435
+#define wxPrintDialogData_SetPrintData 2436
+#define wxPrintDialogData_SetPrintToFile 2437
+#define wxPrintDialogData_SetSelection 2438
+#define wxPrintDialogData_SetToPage 2439
+#define wxPrintData_new_0 2440
+#define wxPrintData_new_1 2441
+#define wxPrintData_destruct 2442
+#define wxPrintData_GetCollate 2443
+#define wxPrintData_GetBin 2444
+#define wxPrintData_GetColour 2445
+#define wxPrintData_GetDuplex 2446
+#define wxPrintData_GetNoCopies 2447
+#define wxPrintData_GetOrientation 2448
+#define wxPrintData_GetPaperId 2449
+#define wxPrintData_GetPrinterName 2450
+#define wxPrintData_GetQuality 2451
+#define wxPrintData_IsOk 2452
+#define wxPrintData_SetBin 2453
+#define wxPrintData_SetCollate 2454
+#define wxPrintData_SetColour 2455
+#define wxPrintData_SetDuplex 2456
+#define wxPrintData_SetNoCopies 2457
+#define wxPrintData_SetOrientation 2458
+#define wxPrintData_SetPaperId 2459
+#define wxPrintData_SetPrinterName 2460
+#define wxPrintData_SetQuality 2461
+#define wxPrintPreview_new_2 2464
+#define wxPrintPreview_new_3 2465
+#define wxPrintPreview_destruct 2467
+#define wxPrintPreview_GetCanvas 2468
+#define wxPrintPreview_GetCurrentPage 2469
+#define wxPrintPreview_GetFrame 2470
+#define wxPrintPreview_GetMaxPage 2471
+#define wxPrintPreview_GetMinPage 2472
+#define wxPrintPreview_GetPrintout 2473
+#define wxPrintPreview_GetPrintoutForPrinting 2474
+#define wxPrintPreview_IsOk 2475
+#define wxPrintPreview_PaintPage 2476
+#define wxPrintPreview_Print 2477
+#define wxPrintPreview_RenderPage 2478
+#define wxPrintPreview_SetCanvas 2479
+#define wxPrintPreview_SetCurrentPage 2480
+#define wxPrintPreview_SetFrame 2481
+#define wxPrintPreview_SetPrintout 2482
+#define wxPrintPreview_SetZoom 2483
+#define wxPreviewFrame_new 2484
+#define wxPreviewFrame_destruct 2485
+#define wxPreviewFrame_CreateControlBar 2486
+#define wxPreviewFrame_CreateCanvas 2487
+#define wxPreviewFrame_Initialize 2488
+#define wxPreviewFrame_OnCloseWindow 2489
+#define wxPreviewControlBar_new 2490
+#define wxPreviewControlBar_destruct 2491
+#define wxPreviewControlBar_CreateButtons 2492
+#define wxPreviewControlBar_GetPrintPreview 2493
+#define wxPreviewControlBar_GetZoomControl 2494
+#define wxPreviewControlBar_SetZoomControl 2495
+#define wxPrinter_new 2497
+#define wxPrinter_CreateAbortWindow 2498
+#define wxPrinter_GetAbort 2499
+#define wxPrinter_GetLastError 2500
+#define wxPrinter_GetPrintDialogData 2501
+#define wxPrinter_Print 2502
+#define wxPrinter_PrintDialog 2503
+#define wxPrinter_ReportError 2504
+#define wxPrinter_Setup 2505
+#define wxPrinter_destroy 2506
+#define wxXmlResource_new_1 2507
+#define wxXmlResource_new_2 2508
+#define wxXmlResource_destruct 2509
+#define wxXmlResource_AttachUnknownControl 2510
+#define wxXmlResource_ClearHandlers 2511
+#define wxXmlResource_CompareVersion 2512
+#define wxXmlResource_Get 2513
+#define wxXmlResource_GetFlags 2514
+#define wxXmlResource_GetVersion 2515
+#define wxXmlResource_GetXRCID 2516
+#define wxXmlResource_InitAllHandlers 2517
+#define wxXmlResource_Load 2518
+#define wxXmlResource_LoadBitmap 2519
+#define wxXmlResource_LoadDialog_2 2520
+#define wxXmlResource_LoadDialog_3 2521
+#define wxXmlResource_LoadFrame_2 2522
+#define wxXmlResource_LoadFrame_3 2523
+#define wxXmlResource_LoadIcon 2524
+#define wxXmlResource_LoadMenu 2525
+#define wxXmlResource_LoadMenuBar_2 2526
+#define wxXmlResource_LoadMenuBar_1 2527
+#define wxXmlResource_LoadPanel_2 2528
+#define wxXmlResource_LoadPanel_3 2529
+#define wxXmlResource_LoadToolBar 2530
+#define wxXmlResource_Set 2531
+#define wxXmlResource_SetFlags 2532
+#define wxXmlResource_Unload 2533
+#define wxXmlResource_xrcctrl 2534
+#define wxHtmlEasyPrinting_new 2535
+#define wxHtmlEasyPrinting_destruct 2536
+#define wxHtmlEasyPrinting_GetPrintData 2537
+#define wxHtmlEasyPrinting_GetPageSetupData 2538
+#define wxHtmlEasyPrinting_PreviewFile 2539
+#define wxHtmlEasyPrinting_PreviewText 2540
+#define wxHtmlEasyPrinting_PrintFile 2541
+#define wxHtmlEasyPrinting_PrintText 2542
+#define wxHtmlEasyPrinting_PageSetup 2543
+#define wxHtmlEasyPrinting_SetFonts 2544
+#define wxHtmlEasyPrinting_SetHeader 2545
+#define wxHtmlEasyPrinting_SetFooter 2546
+#define wxGLCanvas_new_2 2548
+#define wxGLCanvas_new_3_1 2549
+#define wxGLCanvas_new_3_0 2550
+#define wxGLCanvas_GetContext 2551
+#define wxGLCanvas_SetCurrent 2553
+#define wxGLCanvas_SwapBuffers 2554
+#define wxGLCanvas_destroy 2555
+#define wxAuiManager_new 2556
+#define wxAuiManager_destruct 2557
+#define wxAuiManager_AddPane_2_1 2558
+#define wxAuiManager_AddPane_3 2559
+#define wxAuiManager_AddPane_2_0 2560
+#define wxAuiManager_DetachPane 2561
+#define wxAuiManager_GetAllPanes 2562
+#define wxAuiManager_GetArtProvider 2563
+#define wxAuiManager_GetDockSizeConstraint 2564
+#define wxAuiManager_GetFlags 2565
+#define wxAuiManager_GetManagedWindow 2566
+#define wxAuiManager_GetManager 2567
+#define wxAuiManager_GetPane_1_1 2568
+#define wxAuiManager_GetPane_1_0 2569
+#define wxAuiManager_HideHint 2570
+#define wxAuiManager_InsertPane 2571
+#define wxAuiManager_LoadPaneInfo 2572
+#define wxAuiManager_LoadPerspective 2573
+#define wxAuiManager_SavePaneInfo 2574
+#define wxAuiManager_SavePerspective 2575
+#define wxAuiManager_SetArtProvider 2576
+#define wxAuiManager_SetDockSizeConstraint 2577
+#define wxAuiManager_SetFlags 2578
+#define wxAuiManager_SetManagedWindow 2579
+#define wxAuiManager_ShowHint 2580
+#define wxAuiManager_UnInit 2581
+#define wxAuiManager_Update 2582
+#define wxAuiPaneInfo_new_0 2583
+#define wxAuiPaneInfo_new_1 2584
+#define wxAuiPaneInfo_destruct 2585
+#define wxAuiPaneInfo_BestSize_1 2586
+#define wxAuiPaneInfo_BestSize_2 2587
+#define wxAuiPaneInfo_Bottom 2588
+#define wxAuiPaneInfo_BottomDockable 2589
+#define wxAuiPaneInfo_Caption 2590
+#define wxAuiPaneInfo_CaptionVisible 2591
+#define wxAuiPaneInfo_Centre 2592
+#define wxAuiPaneInfo_CentrePane 2593
+#define wxAuiPaneInfo_CloseButton 2594
+#define wxAuiPaneInfo_DefaultPane 2595
+#define wxAuiPaneInfo_DestroyOnClose 2596
+#define wxAuiPaneInfo_Direction 2597
+#define wxAuiPaneInfo_Dock 2598
+#define wxAuiPaneInfo_Dockable 2599
+#define wxAuiPaneInfo_Fixed 2600
+#define wxAuiPaneInfo_Float 2601
+#define wxAuiPaneInfo_Floatable 2602
+#define wxAuiPaneInfo_FloatingPosition_1 2603
+#define wxAuiPaneInfo_FloatingPosition_2 2604
+#define wxAuiPaneInfo_FloatingSize_1 2605
+#define wxAuiPaneInfo_FloatingSize_2 2606
+#define wxAuiPaneInfo_Gripper 2607
+#define wxAuiPaneInfo_GripperTop 2608
+#define wxAuiPaneInfo_HasBorder 2609
+#define wxAuiPaneInfo_HasCaption 2610
+#define wxAuiPaneInfo_HasCloseButton 2611
+#define wxAuiPaneInfo_HasFlag 2612
+#define wxAuiPaneInfo_HasGripper 2613
+#define wxAuiPaneInfo_HasGripperTop 2614
+#define wxAuiPaneInfo_HasMaximizeButton 2615
+#define wxAuiPaneInfo_HasMinimizeButton 2616
+#define wxAuiPaneInfo_HasPinButton 2617
+#define wxAuiPaneInfo_Hide 2618
+#define wxAuiPaneInfo_IsBottomDockable 2619
+#define wxAuiPaneInfo_IsDocked 2620
+#define wxAuiPaneInfo_IsFixed 2621
+#define wxAuiPaneInfo_IsFloatable 2622
+#define wxAuiPaneInfo_IsFloating 2623
+#define wxAuiPaneInfo_IsLeftDockable 2624
+#define wxAuiPaneInfo_IsMovable 2625
+#define wxAuiPaneInfo_IsOk 2626
+#define wxAuiPaneInfo_IsResizable 2627
+#define wxAuiPaneInfo_IsRightDockable 2628
+#define wxAuiPaneInfo_IsShown 2629
+#define wxAuiPaneInfo_IsToolbar 2630
+#define wxAuiPaneInfo_IsTopDockable 2631
+#define wxAuiPaneInfo_Layer 2632
+#define wxAuiPaneInfo_Left 2633
+#define wxAuiPaneInfo_LeftDockable 2634
+#define wxAuiPaneInfo_MaxSize_1 2635
+#define wxAuiPaneInfo_MaxSize_2 2636
+#define wxAuiPaneInfo_MaximizeButton 2637
+#define wxAuiPaneInfo_MinSize_1 2638
+#define wxAuiPaneInfo_MinSize_2 2639
+#define wxAuiPaneInfo_MinimizeButton 2640
+#define wxAuiPaneInfo_Movable 2641
+#define wxAuiPaneInfo_Name 2642
+#define wxAuiPaneInfo_PaneBorder 2643
+#define wxAuiPaneInfo_PinButton 2644
+#define wxAuiPaneInfo_Position 2645
+#define wxAuiPaneInfo_Resizable 2646
+#define wxAuiPaneInfo_Right 2647
+#define wxAuiPaneInfo_RightDockable 2648
+#define wxAuiPaneInfo_Row 2649
+#define wxAuiPaneInfo_SafeSet 2650
+#define wxAuiPaneInfo_SetFlag 2651
+#define wxAuiPaneInfo_Show 2652
+#define wxAuiPaneInfo_ToolbarPane 2653
+#define wxAuiPaneInfo_Top 2654
+#define wxAuiPaneInfo_TopDockable 2655
+#define wxAuiPaneInfo_Window 2656
+#define wxAuiPaneInfo_GetWindow 2657
+#define wxAuiPaneInfo_GetFrame 2658
+#define wxAuiPaneInfo_GetDirection 2659
+#define wxAuiPaneInfo_GetLayer 2660
+#define wxAuiPaneInfo_GetRow 2661
+#define wxAuiPaneInfo_GetPosition 2662
+#define wxAuiPaneInfo_GetFloatingPosition 2663
+#define wxAuiPaneInfo_GetFloatingSize 2664
+#define wxAuiNotebook_new_0 2665
+#define wxAuiNotebook_new_2 2666
+#define wxAuiNotebook_AddPage 2667
+#define wxAuiNotebook_Create 2668
+#define wxAuiNotebook_DeletePage 2669
+#define wxAuiNotebook_GetArtProvider 2670
+#define wxAuiNotebook_GetPage 2671
+#define wxAuiNotebook_GetPageBitmap 2672
+#define wxAuiNotebook_GetPageCount 2673
+#define wxAuiNotebook_GetPageIndex 2674
+#define wxAuiNotebook_GetPageText 2675
+#define wxAuiNotebook_GetSelection 2676
+#define wxAuiNotebook_InsertPage 2677
+#define wxAuiNotebook_RemovePage 2678
+#define wxAuiNotebook_SetArtProvider 2679
+#define wxAuiNotebook_SetFont 2680
+#define wxAuiNotebook_SetPageBitmap 2681
+#define wxAuiNotebook_SetPageText 2682
+#define wxAuiNotebook_SetSelection 2683
+#define wxAuiNotebook_SetTabCtrlHeight 2684
+#define wxAuiNotebook_SetUniformBitmapSize 2685
+#define wxAuiNotebook_destroy 2686
+#define wxAuiTabArt_SetFlags 2687
+#define wxAuiTabArt_SetMeasuringFont 2688
+#define wxAuiTabArt_SetNormalFont 2689
+#define wxAuiTabArt_SetSelectedFont 2690
+#define wxAuiTabArt_SetColour 2691
+#define wxAuiTabArt_SetActiveColour 2692
+#define wxAuiDockArt_GetColour 2693
+#define wxAuiDockArt_GetFont 2694
+#define wxAuiDockArt_GetMetric 2695
+#define wxAuiDockArt_SetColour 2696
+#define wxAuiDockArt_SetFont 2697
+#define wxAuiDockArt_SetMetric 2698
+#define wxAuiSimpleTabArt_new 2699
+#define wxAuiSimpleTabArt_destroy 2700
+#define wxMDIParentFrame_new_0 2701
+#define wxMDIParentFrame_new_4 2702
+#define wxMDIParentFrame_destruct 2703
+#define wxMDIParentFrame_ActivateNext 2704
+#define wxMDIParentFrame_ActivatePrevious 2705
+#define wxMDIParentFrame_ArrangeIcons 2706
+#define wxMDIParentFrame_Cascade 2707
+#define wxMDIParentFrame_Create 2708
+#define wxMDIParentFrame_GetActiveChild 2709
+#define wxMDIParentFrame_GetClientWindow 2710
+#define wxMDIParentFrame_Tile 2711
+#define wxMDIChildFrame_new_0 2712
+#define wxMDIChildFrame_new_4 2713
+#define wxMDIChildFrame_destruct 2714
+#define wxMDIChildFrame_Activate 2715
+#define wxMDIChildFrame_Create 2716
+#define wxMDIChildFrame_Maximize 2717
+#define wxMDIChildFrame_Restore 2718
+#define wxMDIClientWindow_new_0 2719
+#define wxMDIClientWindow_new_2 2720
+#define wxMDIClientWindow_destruct 2721
+#define wxMDIClientWindow_CreateClient 2722
+#define wxLayoutAlgorithm_new 2723
+#define wxLayoutAlgorithm_LayoutFrame 2724
+#define wxLayoutAlgorithm_LayoutMDIFrame 2725
+#define wxLayoutAlgorithm_LayoutWindow 2726
+#define wxLayoutAlgorithm_destroy 2727
+#define wxEvent_GetId 2728
+#define wxEvent_GetSkipped 2729
+#define wxEvent_GetTimestamp 2730
+#define wxEvent_IsCommandEvent 2731
+#define wxEvent_ResumePropagation 2732
+#define wxEvent_ShouldPropagate 2733
+#define wxEvent_Skip 2734
+#define wxEvent_StopPropagation 2735
+#define wxCommandEvent_getClientData 2736
+#define wxCommandEvent_GetExtraLong 2737
+#define wxCommandEvent_GetInt 2738
+#define wxCommandEvent_GetSelection 2739
+#define wxCommandEvent_GetString 2740
+#define wxCommandEvent_IsChecked 2741
+#define wxCommandEvent_IsSelection 2742
+#define wxCommandEvent_SetInt 2743
+#define wxCommandEvent_SetString 2744
+#define wxScrollEvent_GetOrientation 2745
+#define wxScrollEvent_GetPosition 2746
+#define wxScrollWinEvent_GetOrientation 2747
+#define wxScrollWinEvent_GetPosition 2748
+#define wxMouseEvent_AltDown 2749
+#define wxMouseEvent_Button 2750
+#define wxMouseEvent_ButtonDClick 2751
+#define wxMouseEvent_ButtonDown 2752
+#define wxMouseEvent_ButtonUp 2753
+#define wxMouseEvent_CmdDown 2754
+#define wxMouseEvent_ControlDown 2755
+#define wxMouseEvent_Dragging 2756
+#define wxMouseEvent_Entering 2757
+#define wxMouseEvent_GetButton 2758
+#define wxMouseEvent_GetPosition 2761
+#define wxMouseEvent_GetLogicalPosition 2762
+#define wxMouseEvent_GetLinesPerAction 2763
+#define wxMouseEvent_GetWheelRotation 2764
+#define wxMouseEvent_GetWheelDelta 2765
+#define wxMouseEvent_GetX 2766
+#define wxMouseEvent_GetY 2767
+#define wxMouseEvent_IsButton 2768
+#define wxMouseEvent_IsPageScroll 2769
+#define wxMouseEvent_Leaving 2770
+#define wxMouseEvent_LeftDClick 2771
+#define wxMouseEvent_LeftDown 2772
+#define wxMouseEvent_LeftIsDown 2773
+#define wxMouseEvent_LeftUp 2774
+#define wxMouseEvent_MetaDown 2775
+#define wxMouseEvent_MiddleDClick 2776
+#define wxMouseEvent_MiddleDown 2777
+#define wxMouseEvent_MiddleIsDown 2778
+#define wxMouseEvent_MiddleUp 2779
+#define wxMouseEvent_Moving 2780
+#define wxMouseEvent_RightDClick 2781
+#define wxMouseEvent_RightDown 2782
+#define wxMouseEvent_RightIsDown 2783
+#define wxMouseEvent_RightUp 2784
+#define wxMouseEvent_ShiftDown 2785
+#define wxSetCursorEvent_GetCursor 2786
+#define wxSetCursorEvent_GetX 2787
+#define wxSetCursorEvent_GetY 2788
+#define wxSetCursorEvent_HasCursor 2789
+#define wxSetCursorEvent_SetCursor 2790
+#define wxKeyEvent_AltDown 2791
+#define wxKeyEvent_CmdDown 2792
+#define wxKeyEvent_ControlDown 2793
+#define wxKeyEvent_GetKeyCode 2794
+#define wxKeyEvent_GetModifiers 2795
+#define wxKeyEvent_GetPosition 2798
+#define wxKeyEvent_GetRawKeyCode 2799
+#define wxKeyEvent_GetRawKeyFlags 2800
+#define wxKeyEvent_GetUnicodeKey 2801
+#define wxKeyEvent_GetX 2802
+#define wxKeyEvent_GetY 2803
+#define wxKeyEvent_HasModifiers 2804
+#define wxKeyEvent_MetaDown 2805
+#define wxKeyEvent_ShiftDown 2806
+#define wxSizeEvent_GetSize 2807
+#define wxMoveEvent_GetPosition 2808
+#define wxEraseEvent_GetDC 2809
+#define wxFocusEvent_GetWindow 2810
+#define wxChildFocusEvent_GetWindow 2811
+#define wxMenuEvent_GetMenu 2812
+#define wxMenuEvent_GetMenuId 2813
+#define wxMenuEvent_IsPopup 2814
+#define wxCloseEvent_CanVeto 2815
+#define wxCloseEvent_GetLoggingOff 2816
+#define wxCloseEvent_SetCanVeto 2817
+#define wxCloseEvent_SetLoggingOff 2818
+#define wxCloseEvent_Veto 2819
+#define wxShowEvent_SetShow 2820
+#define wxShowEvent_GetShow 2821
+#define wxIconizeEvent_Iconized 2822
+#define wxJoystickEvent_ButtonDown 2823
+#define wxJoystickEvent_ButtonIsDown 2824
+#define wxJoystickEvent_ButtonUp 2825
+#define wxJoystickEvent_GetButtonChange 2826
+#define wxJoystickEvent_GetButtonState 2827
+#define wxJoystickEvent_GetJoystick 2828
+#define wxJoystickEvent_GetPosition 2829
+#define wxJoystickEvent_GetZPosition 2830
+#define wxJoystickEvent_IsButton 2831
+#define wxJoystickEvent_IsMove 2832
+#define wxJoystickEvent_IsZMove 2833
+#define wxUpdateUIEvent_CanUpdate 2834
+#define wxUpdateUIEvent_Check 2835
+#define wxUpdateUIEvent_Enable 2836
+#define wxUpdateUIEvent_Show 2837
+#define wxUpdateUIEvent_GetChecked 2838
+#define wxUpdateUIEvent_GetEnabled 2839
+#define wxUpdateUIEvent_GetShown 2840
+#define wxUpdateUIEvent_GetSetChecked 2841
+#define wxUpdateUIEvent_GetSetEnabled 2842
+#define wxUpdateUIEvent_GetSetShown 2843
+#define wxUpdateUIEvent_GetSetText 2844
+#define wxUpdateUIEvent_GetText 2845
+#define wxUpdateUIEvent_GetMode 2846
+#define wxUpdateUIEvent_GetUpdateInterval 2847
+#define wxUpdateUIEvent_ResetUpdateTime 2848
+#define wxUpdateUIEvent_SetMode 2849
+#define wxUpdateUIEvent_SetText 2850
+#define wxUpdateUIEvent_SetUpdateInterval 2851
+#define wxMouseCaptureChangedEvent_GetCapturedWindow 2852
+#define wxPaletteChangedEvent_SetChangedWindow 2853
+#define wxPaletteChangedEvent_GetChangedWindow 2854
+#define wxQueryNewPaletteEvent_SetPaletteRealized 2855
+#define wxQueryNewPaletteEvent_GetPaletteRealized 2856
+#define wxNavigationKeyEvent_GetDirection 2857
+#define wxNavigationKeyEvent_SetDirection 2858
+#define wxNavigationKeyEvent_IsWindowChange 2859
+#define wxNavigationKeyEvent_SetWindowChange 2860
+#define wxNavigationKeyEvent_IsFromTab 2861
+#define wxNavigationKeyEvent_SetFromTab 2862
+#define wxNavigationKeyEvent_GetCurrentFocus 2863
+#define wxNavigationKeyEvent_SetCurrentFocus 2864
+#define wxHelpEvent_GetOrigin 2865
+#define wxHelpEvent_GetPosition 2866
+#define wxHelpEvent_SetOrigin 2867
+#define wxHelpEvent_SetPosition 2868
+#define wxContextMenuEvent_GetPosition 2869
+#define wxContextMenuEvent_SetPosition 2870
+#define wxIdleEvent_CanSend 2871
+#define wxIdleEvent_GetMode 2872
+#define wxIdleEvent_RequestMore 2873
+#define wxIdleEvent_MoreRequested 2874
+#define wxIdleEvent_SetMode 2875
+#define wxGridEvent_AltDown 2876
+#define wxGridEvent_ControlDown 2877
+#define wxGridEvent_GetCol 2878
+#define wxGridEvent_GetPosition 2879
+#define wxGridEvent_GetRow 2880
+#define wxGridEvent_MetaDown 2881
+#define wxGridEvent_Selecting 2882
+#define wxGridEvent_ShiftDown 2883
+#define wxNotifyEvent_Allow 2884
+#define wxNotifyEvent_IsAllowed 2885
+#define wxNotifyEvent_Veto 2886
+#define wxSashEvent_GetEdge 2887
+#define wxSashEvent_GetDragRect 2888
+#define wxSashEvent_GetDragStatus 2889
+#define wxListEvent_GetCacheFrom 2890
+#define wxListEvent_GetCacheTo 2891
+#define wxListEvent_GetKeyCode 2892
+#define wxListEvent_GetIndex 2893
+#define wxListEvent_GetColumn 2894
+#define wxListEvent_GetPoint 2895
+#define wxListEvent_GetLabel 2896
+#define wxListEvent_GetText 2897
+#define wxListEvent_GetImage 2898
+#define wxListEvent_GetData 2899
+#define wxListEvent_GetMask 2900
+#define wxListEvent_GetItem 2901
+#define wxListEvent_IsEditCancelled 2902
+#define wxDateEvent_GetDate 2903
+#define wxCalendarEvent_GetWeekDay 2904
+#define wxFileDirPickerEvent_GetPath 2905
+#define wxColourPickerEvent_GetColour 2906
+#define wxFontPickerEvent_GetFont 2907
+#define wxStyledTextEvent_GetPosition 2908
+#define wxStyledTextEvent_GetKey 2909
+#define wxStyledTextEvent_GetModifiers 2910
+#define wxStyledTextEvent_GetModificationType 2911
+#define wxStyledTextEvent_GetText 2912
+#define wxStyledTextEvent_GetLength 2913
+#define wxStyledTextEvent_GetLinesAdded 2914
+#define wxStyledTextEvent_GetLine 2915
+#define wxStyledTextEvent_GetFoldLevelNow 2916
+#define wxStyledTextEvent_GetFoldLevelPrev 2917
+#define wxStyledTextEvent_GetMargin 2918
+#define wxStyledTextEvent_GetMessage 2919
+#define wxStyledTextEvent_GetWParam 2920
+#define wxStyledTextEvent_GetLParam 2921
+#define wxStyledTextEvent_GetListType 2922
+#define wxStyledTextEvent_GetX 2923
+#define wxStyledTextEvent_GetY 2924
+#define wxStyledTextEvent_GetDragText 2925
+#define wxStyledTextEvent_GetDragAllowMove 2926
+#define wxStyledTextEvent_GetDragResult 2927
+#define wxStyledTextEvent_GetShift 2928
+#define wxStyledTextEvent_GetControl 2929
+#define wxStyledTextEvent_GetAlt 2930
+#define utils_wxGetKeyState 2931
+#define utils_wxGetMousePosition 2932
+#define utils_wxGetMouseState 2933
+#define utils_wxSetDetectableAutoRepeat 2934
+#define utils_wxBell 2935
+#define utils_wxFindMenuItemId 2936
+#define utils_wxGenericFindWindowAtPoint 2937
+#define utils_wxFindWindowAtPoint 2938
+#define utils_wxBeginBusyCursor 2939
+#define utils_wxEndBusyCursor 2940
+#define utils_wxIsBusy 2941
+#define utils_wxShutdown 2942
+#define utils_wxShell 2943
+#define utils_wxLaunchDefaultBrowser 2944
+#define utils_wxGetEmailAddress 2945
+#define utils_wxGetUserId 2946
+#define utils_wxGetHomeDir 2947
+#define utils_wxNewId 2948
+#define utils_wxRegisterId 2949
+#define utils_wxGetCurrentId 2950
+#define utils_wxGetOsDescription 2951
+#define utils_wxIsPlatformLittleEndian 2952
+#define utils_wxIsPlatform64Bit 2953
+#define gdicmn_wxDisplaySize 2954
+#define gdicmn_wxSetCursor 2955
+#define wxPrintout_new 2956
+#define wxPrintout_destruct 2957
+#define wxPrintout_GetDC 2958
+#define wxPrintout_GetPageSizeMM 2959
+#define wxPrintout_GetPageSizePixels 2960
+#define wxPrintout_GetPaperRectPixels 2961
+#define wxPrintout_GetPPIPrinter 2962
+#define wxPrintout_GetPPIScreen 2963
+#define wxPrintout_GetTitle 2964
+#define wxPrintout_IsPreview 2965
+#define wxPrintout_FitThisSizeToPaper 2966
+#define wxPrintout_FitThisSizeToPage 2967
+#define wxPrintout_FitThisSizeToPageMargins 2968
+#define wxPrintout_MapScreenSizeToPaper 2969
+#define wxPrintout_MapScreenSizeToPage 2970
+#define wxPrintout_MapScreenSizeToPageMargins 2971
+#define wxPrintout_MapScreenSizeToDevice 2972
+#define wxPrintout_GetLogicalPaperRect 2973
+#define wxPrintout_GetLogicalPageRect 2974
+#define wxPrintout_GetLogicalPageMarginsRect 2975
+#define wxPrintout_SetLogicalOrigin 2976
+#define wxPrintout_OffsetLogicalOrigin 2977
+#define wxStyledTextCtrl_new_2 2978
+#define wxStyledTextCtrl_new_0 2979
+#define wxStyledTextCtrl_destruct 2980
+#define wxStyledTextCtrl_Create 2981
+#define wxStyledTextCtrl_AddText 2982
+#define wxStyledTextCtrl_AddStyledText 2983
+#define wxStyledTextCtrl_InsertText 2984
+#define wxStyledTextCtrl_ClearAll 2985
+#define wxStyledTextCtrl_ClearDocumentStyle 2986
+#define wxStyledTextCtrl_GetLength 2987
+#define wxStyledTextCtrl_GetCharAt 2988
+#define wxStyledTextCtrl_GetCurrentPos 2989
+#define wxStyledTextCtrl_GetAnchor 2990
+#define wxStyledTextCtrl_GetStyleAt 2991
+#define wxStyledTextCtrl_Redo 2992
+#define wxStyledTextCtrl_SetUndoCollection 2993
+#define wxStyledTextCtrl_SelectAll 2994
+#define wxStyledTextCtrl_SetSavePoint 2995
+#define wxStyledTextCtrl_GetStyledText 2996
+#define wxStyledTextCtrl_CanRedo 2997
+#define wxStyledTextCtrl_MarkerLineFromHandle 2998
+#define wxStyledTextCtrl_MarkerDeleteHandle 2999
+#define wxStyledTextCtrl_GetUndoCollection 3000
+#define wxStyledTextCtrl_GetViewWhiteSpace 3001
+#define wxStyledTextCtrl_SetViewWhiteSpace 3002
+#define wxStyledTextCtrl_PositionFromPoint 3003
+#define wxStyledTextCtrl_PositionFromPointClose 3004
+#define wxStyledTextCtrl_GotoLine 3005
+#define wxStyledTextCtrl_GotoPos 3006
+#define wxStyledTextCtrl_SetAnchor 3007
+#define wxStyledTextCtrl_GetCurLine 3008
+#define wxStyledTextCtrl_GetEndStyled 3009
+#define wxStyledTextCtrl_ConvertEOLs 3010
+#define wxStyledTextCtrl_GetEOLMode 3011
+#define wxStyledTextCtrl_SetEOLMode 3012
+#define wxStyledTextCtrl_StartStyling 3013
+#define wxStyledTextCtrl_SetStyling 3014
+#define wxStyledTextCtrl_GetBufferedDraw 3015
+#define wxStyledTextCtrl_SetBufferedDraw 3016
+#define wxStyledTextCtrl_SetTabWidth 3017
+#define wxStyledTextCtrl_GetTabWidth 3018
+#define wxStyledTextCtrl_SetCodePage 3019
+#define wxStyledTextCtrl_MarkerDefine 3020
+#define wxStyledTextCtrl_MarkerSetForeground 3021
+#define wxStyledTextCtrl_MarkerSetBackground 3022
+#define wxStyledTextCtrl_MarkerAdd 3023
+#define wxStyledTextCtrl_MarkerDelete 3024
+#define wxStyledTextCtrl_MarkerDeleteAll 3025
+#define wxStyledTextCtrl_MarkerGet 3026
+#define wxStyledTextCtrl_MarkerNext 3027
+#define wxStyledTextCtrl_MarkerPrevious 3028
+#define wxStyledTextCtrl_MarkerDefineBitmap 3029
+#define wxStyledTextCtrl_MarkerAddSet 3030
+#define wxStyledTextCtrl_MarkerSetAlpha 3031
+#define wxStyledTextCtrl_SetMarginType 3032
+#define wxStyledTextCtrl_GetMarginType 3033
+#define wxStyledTextCtrl_SetMarginWidth 3034
+#define wxStyledTextCtrl_GetMarginWidth 3035
+#define wxStyledTextCtrl_SetMarginMask 3036
+#define wxStyledTextCtrl_GetMarginMask 3037
+#define wxStyledTextCtrl_SetMarginSensitive 3038
+#define wxStyledTextCtrl_GetMarginSensitive 3039
+#define wxStyledTextCtrl_StyleClearAll 3040
+#define wxStyledTextCtrl_StyleSetForeground 3041
+#define wxStyledTextCtrl_StyleSetBackground 3042
+#define wxStyledTextCtrl_StyleSetBold 3043
+#define wxStyledTextCtrl_StyleSetItalic 3044
+#define wxStyledTextCtrl_StyleSetSize 3045
+#define wxStyledTextCtrl_StyleSetFaceName 3046
+#define wxStyledTextCtrl_StyleSetEOLFilled 3047
+#define wxStyledTextCtrl_StyleResetDefault 3048
+#define wxStyledTextCtrl_StyleSetUnderline 3049
+#define wxStyledTextCtrl_StyleSetCase 3050
+#define wxStyledTextCtrl_StyleSetHotSpot 3051
+#define wxStyledTextCtrl_SetSelForeground 3052
+#define wxStyledTextCtrl_SetSelBackground 3053
+#define wxStyledTextCtrl_GetSelAlpha 3054
+#define wxStyledTextCtrl_SetSelAlpha 3055
+#define wxStyledTextCtrl_SetCaretForeground 3056
+#define wxStyledTextCtrl_CmdKeyAssign 3057
+#define wxStyledTextCtrl_CmdKeyClear 3058
+#define wxStyledTextCtrl_CmdKeyClearAll 3059
+#define wxStyledTextCtrl_SetStyleBytes 3060
+#define wxStyledTextCtrl_StyleSetVisible 3061
+#define wxStyledTextCtrl_GetCaretPeriod 3062
+#define wxStyledTextCtrl_SetCaretPeriod 3063
+#define wxStyledTextCtrl_SetWordChars 3064
+#define wxStyledTextCtrl_BeginUndoAction 3065
+#define wxStyledTextCtrl_EndUndoAction 3066
+#define wxStyledTextCtrl_IndicatorSetStyle 3067
+#define wxStyledTextCtrl_IndicatorGetStyle 3068
+#define wxStyledTextCtrl_IndicatorSetForeground 3069
+#define wxStyledTextCtrl_IndicatorGetForeground 3070
+#define wxStyledTextCtrl_SetWhitespaceForeground 3071
+#define wxStyledTextCtrl_SetWhitespaceBackground 3072
+#define wxStyledTextCtrl_GetStyleBits 3073
+#define wxStyledTextCtrl_SetLineState 3074
+#define wxStyledTextCtrl_GetLineState 3075
+#define wxStyledTextCtrl_GetMaxLineState 3076
+#define wxStyledTextCtrl_GetCaretLineVisible 3077
+#define wxStyledTextCtrl_SetCaretLineVisible 3078
+#define wxStyledTextCtrl_GetCaretLineBackground 3079
+#define wxStyledTextCtrl_SetCaretLineBackground 3080
+#define wxStyledTextCtrl_AutoCompShow 3081
+#define wxStyledTextCtrl_AutoCompCancel 3082
+#define wxStyledTextCtrl_AutoCompActive 3083
+#define wxStyledTextCtrl_AutoCompPosStart 3084
+#define wxStyledTextCtrl_AutoCompComplete 3085
+#define wxStyledTextCtrl_AutoCompStops 3086
+#define wxStyledTextCtrl_AutoCompSetSeparator 3087
+#define wxStyledTextCtrl_AutoCompGetSeparator 3088
+#define wxStyledTextCtrl_AutoCompSelect 3089
+#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3090
+#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3091
+#define wxStyledTextCtrl_AutoCompSetFillUps 3092
+#define wxStyledTextCtrl_AutoCompSetChooseSingle 3093
+#define wxStyledTextCtrl_AutoCompGetChooseSingle 3094
+#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3095
+#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3096
+#define wxStyledTextCtrl_UserListShow 3097
+#define wxStyledTextCtrl_AutoCompSetAutoHide 3098
+#define wxStyledTextCtrl_AutoCompGetAutoHide 3099
+#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3100
+#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3101
+#define wxStyledTextCtrl_RegisterImage 3102
+#define wxStyledTextCtrl_ClearRegisteredImages 3103
+#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3104
+#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3105
+#define wxStyledTextCtrl_AutoCompSetMaxWidth 3106
+#define wxStyledTextCtrl_AutoCompGetMaxWidth 3107
+#define wxStyledTextCtrl_AutoCompSetMaxHeight 3108
+#define wxStyledTextCtrl_AutoCompGetMaxHeight 3109
+#define wxStyledTextCtrl_SetIndent 3110
+#define wxStyledTextCtrl_GetIndent 3111
+#define wxStyledTextCtrl_SetUseTabs 3112
+#define wxStyledTextCtrl_GetUseTabs 3113
+#define wxStyledTextCtrl_SetLineIndentation 3114
+#define wxStyledTextCtrl_GetLineIndentation 3115
+#define wxStyledTextCtrl_GetLineIndentPosition 3116
+#define wxStyledTextCtrl_GetColumn 3117
+#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3118
+#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3119
+#define wxStyledTextCtrl_SetIndentationGuides 3120
+#define wxStyledTextCtrl_GetIndentationGuides 3121
+#define wxStyledTextCtrl_SetHighlightGuide 3122
+#define wxStyledTextCtrl_GetHighlightGuide 3123
+#define wxStyledTextCtrl_GetLineEndPosition 3124
+#define wxStyledTextCtrl_GetCodePage 3125
+#define wxStyledTextCtrl_GetCaretForeground 3126
+#define wxStyledTextCtrl_GetReadOnly 3127
+#define wxStyledTextCtrl_SetCurrentPos 3128
+#define wxStyledTextCtrl_SetSelectionStart 3129
+#define wxStyledTextCtrl_GetSelectionStart 3130
+#define wxStyledTextCtrl_SetSelectionEnd 3131
+#define wxStyledTextCtrl_GetSelectionEnd 3132
+#define wxStyledTextCtrl_SetPrintMagnification 3133
+#define wxStyledTextCtrl_GetPrintMagnification 3134
+#define wxStyledTextCtrl_SetPrintColourMode 3135
+#define wxStyledTextCtrl_GetPrintColourMode 3136
+#define wxStyledTextCtrl_FindText 3137
+#define wxStyledTextCtrl_FormatRange 3138
+#define wxStyledTextCtrl_GetFirstVisibleLine 3139
+#define wxStyledTextCtrl_GetLine 3140
+#define wxStyledTextCtrl_GetLineCount 3141
+#define wxStyledTextCtrl_SetMarginLeft 3142
+#define wxStyledTextCtrl_GetMarginLeft 3143
+#define wxStyledTextCtrl_SetMarginRight 3144
+#define wxStyledTextCtrl_GetMarginRight 3145
+#define wxStyledTextCtrl_GetModify 3146
+#define wxStyledTextCtrl_SetSelection 3147
+#define wxStyledTextCtrl_GetSelectedText 3148
+#define wxStyledTextCtrl_GetTextRange 3149
+#define wxStyledTextCtrl_HideSelection 3150
+#define wxStyledTextCtrl_LineFromPosition 3151
+#define wxStyledTextCtrl_PositionFromLine 3152
+#define wxStyledTextCtrl_LineScroll 3153
+#define wxStyledTextCtrl_EnsureCaretVisible 3154
+#define wxStyledTextCtrl_ReplaceSelection 3155
+#define wxStyledTextCtrl_SetReadOnly 3156
+#define wxStyledTextCtrl_CanPaste 3157
+#define wxStyledTextCtrl_CanUndo 3158
+#define wxStyledTextCtrl_EmptyUndoBuffer 3159
+#define wxStyledTextCtrl_Undo 3160
+#define wxStyledTextCtrl_Cut 3161
+#define wxStyledTextCtrl_Copy 3162
+#define wxStyledTextCtrl_Paste 3163
+#define wxStyledTextCtrl_Clear 3164
+#define wxStyledTextCtrl_SetText 3165
+#define wxStyledTextCtrl_GetText 3166
+#define wxStyledTextCtrl_GetTextLength 3167
+#define wxStyledTextCtrl_GetOvertype 3168
+#define wxStyledTextCtrl_SetCaretWidth 3169
+#define wxStyledTextCtrl_GetCaretWidth 3170
+#define wxStyledTextCtrl_SetTargetStart 3171
+#define wxStyledTextCtrl_GetTargetStart 3172
+#define wxStyledTextCtrl_SetTargetEnd 3173
+#define wxStyledTextCtrl_GetTargetEnd 3174
+#define wxStyledTextCtrl_ReplaceTarget 3175
+#define wxStyledTextCtrl_SearchInTarget 3176
+#define wxStyledTextCtrl_SetSearchFlags 3177
+#define wxStyledTextCtrl_GetSearchFlags 3178
+#define wxStyledTextCtrl_CallTipShow 3179
+#define wxStyledTextCtrl_CallTipCancel 3180
+#define wxStyledTextCtrl_CallTipActive 3181
+#define wxStyledTextCtrl_CallTipPosAtStart 3182
+#define wxStyledTextCtrl_CallTipSetHighlight 3183
+#define wxStyledTextCtrl_CallTipSetBackground 3184
+#define wxStyledTextCtrl_CallTipSetForeground 3185
+#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3186
+#define wxStyledTextCtrl_CallTipUseStyle 3187
+#define wxStyledTextCtrl_VisibleFromDocLine 3188
+#define wxStyledTextCtrl_DocLineFromVisible 3189
+#define wxStyledTextCtrl_WrapCount 3190
+#define wxStyledTextCtrl_SetFoldLevel 3191
+#define wxStyledTextCtrl_GetFoldLevel 3192
+#define wxStyledTextCtrl_GetLastChild 3193
+#define wxStyledTextCtrl_GetFoldParent 3194
+#define wxStyledTextCtrl_ShowLines 3195
+#define wxStyledTextCtrl_HideLines 3196
+#define wxStyledTextCtrl_GetLineVisible 3197
+#define wxStyledTextCtrl_SetFoldExpanded 3198
+#define wxStyledTextCtrl_GetFoldExpanded 3199
+#define wxStyledTextCtrl_ToggleFold 3200
+#define wxStyledTextCtrl_EnsureVisible 3201
+#define wxStyledTextCtrl_SetFoldFlags 3202
+#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3203
+#define wxStyledTextCtrl_SetTabIndents 3204
+#define wxStyledTextCtrl_GetTabIndents 3205
+#define wxStyledTextCtrl_SetBackSpaceUnIndents 3206
+#define wxStyledTextCtrl_GetBackSpaceUnIndents 3207
+#define wxStyledTextCtrl_SetMouseDwellTime 3208
+#define wxStyledTextCtrl_GetMouseDwellTime 3209
+#define wxStyledTextCtrl_WordStartPosition 3210
+#define wxStyledTextCtrl_WordEndPosition 3211
+#define wxStyledTextCtrl_SetWrapMode 3212
+#define wxStyledTextCtrl_GetWrapMode 3213
+#define wxStyledTextCtrl_SetWrapVisualFlags 3214
+#define wxStyledTextCtrl_GetWrapVisualFlags 3215
+#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3216
+#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3217
+#define wxStyledTextCtrl_SetWrapStartIndent 3218
+#define wxStyledTextCtrl_GetWrapStartIndent 3219
+#define wxStyledTextCtrl_SetLayoutCache 3220
+#define wxStyledTextCtrl_GetLayoutCache 3221
+#define wxStyledTextCtrl_SetScrollWidth 3222
+#define wxStyledTextCtrl_GetScrollWidth 3223
+#define wxStyledTextCtrl_TextWidth 3224
+#define wxStyledTextCtrl_GetEndAtLastLine 3225
+#define wxStyledTextCtrl_TextHeight 3226
+#define wxStyledTextCtrl_SetUseVerticalScrollBar 3227
+#define wxStyledTextCtrl_GetUseVerticalScrollBar 3228
+#define wxStyledTextCtrl_AppendText 3229
+#define wxStyledTextCtrl_GetTwoPhaseDraw 3230
+#define wxStyledTextCtrl_SetTwoPhaseDraw 3231
+#define wxStyledTextCtrl_TargetFromSelection 3232
+#define wxStyledTextCtrl_LinesJoin 3233
+#define wxStyledTextCtrl_LinesSplit 3234
+#define wxStyledTextCtrl_SetFoldMarginColour 3235
+#define wxStyledTextCtrl_SetFoldMarginHiColour 3236
+#define wxStyledTextCtrl_LineDown 3237
+#define wxStyledTextCtrl_LineDownExtend 3238
+#define wxStyledTextCtrl_LineUp 3239
+#define wxStyledTextCtrl_LineUpExtend 3240
+#define wxStyledTextCtrl_CharLeft 3241
+#define wxStyledTextCtrl_CharLeftExtend 3242
+#define wxStyledTextCtrl_CharRight 3243
+#define wxStyledTextCtrl_CharRightExtend 3244
+#define wxStyledTextCtrl_WordLeft 3245
+#define wxStyledTextCtrl_WordLeftExtend 3246
+#define wxStyledTextCtrl_WordRight 3247
+#define wxStyledTextCtrl_WordRightExtend 3248
+#define wxStyledTextCtrl_Home 3249
+#define wxStyledTextCtrl_HomeExtend 3250
+#define wxStyledTextCtrl_LineEnd 3251
+#define wxStyledTextCtrl_LineEndExtend 3252
+#define wxStyledTextCtrl_DocumentStart 3253
+#define wxStyledTextCtrl_DocumentStartExtend 3254
+#define wxStyledTextCtrl_DocumentEnd 3255
+#define wxStyledTextCtrl_DocumentEndExtend 3256
+#define wxStyledTextCtrl_PageUp 3257
+#define wxStyledTextCtrl_PageUpExtend 3258
+#define wxStyledTextCtrl_PageDown 3259
+#define wxStyledTextCtrl_PageDownExtend 3260
+#define wxStyledTextCtrl_EditToggleOvertype 3261
+#define wxStyledTextCtrl_Cancel 3262
+#define wxStyledTextCtrl_DeleteBack 3263
+#define wxStyledTextCtrl_Tab 3264
+#define wxStyledTextCtrl_BackTab 3265
+#define wxStyledTextCtrl_NewLine 3266
+#define wxStyledTextCtrl_FormFeed 3267
+#define wxStyledTextCtrl_VCHome 3268
+#define wxStyledTextCtrl_VCHomeExtend 3269
+#define wxStyledTextCtrl_ZoomIn 3270
+#define wxStyledTextCtrl_ZoomOut 3271
+#define wxStyledTextCtrl_DelWordLeft 3272
+#define wxStyledTextCtrl_DelWordRight 3273
+#define wxStyledTextCtrl_LineCut 3274
+#define wxStyledTextCtrl_LineDelete 3275
+#define wxStyledTextCtrl_LineTranspose 3276
+#define wxStyledTextCtrl_LineDuplicate 3277
+#define wxStyledTextCtrl_LowerCase 3278
+#define wxStyledTextCtrl_UpperCase 3279
+#define wxStyledTextCtrl_LineScrollDown 3280
+#define wxStyledTextCtrl_LineScrollUp 3281
+#define wxStyledTextCtrl_DeleteBackNotLine 3282
+#define wxStyledTextCtrl_HomeDisplay 3283
+#define wxStyledTextCtrl_HomeDisplayExtend 3284
+#define wxStyledTextCtrl_LineEndDisplay 3285
+#define wxStyledTextCtrl_LineEndDisplayExtend 3286
+#define wxStyledTextCtrl_HomeWrapExtend 3287
+#define wxStyledTextCtrl_LineEndWrap 3288
+#define wxStyledTextCtrl_LineEndWrapExtend 3289
+#define wxStyledTextCtrl_VCHomeWrap 3290
+#define wxStyledTextCtrl_VCHomeWrapExtend 3291
+#define wxStyledTextCtrl_LineCopy 3292
+#define wxStyledTextCtrl_MoveCaretInsideView 3293
+#define wxStyledTextCtrl_LineLength 3294
+#define wxStyledTextCtrl_BraceHighlight 3295
+#define wxStyledTextCtrl_BraceBadLight 3296
+#define wxStyledTextCtrl_BraceMatch 3297
+#define wxStyledTextCtrl_GetViewEOL 3298
+#define wxStyledTextCtrl_SetViewEOL 3299
+#define wxStyledTextCtrl_SetModEventMask 3300
+#define wxStyledTextCtrl_GetEdgeColumn 3301
+#define wxStyledTextCtrl_SetEdgeColumn 3302
+#define wxStyledTextCtrl_SetEdgeMode 3303
+#define wxStyledTextCtrl_GetEdgeMode 3304
+#define wxStyledTextCtrl_GetEdgeColour 3305
+#define wxStyledTextCtrl_SetEdgeColour 3306
+#define wxStyledTextCtrl_SearchAnchor 3307
+#define wxStyledTextCtrl_SearchNext 3308
+#define wxStyledTextCtrl_SearchPrev 3309
+#define wxStyledTextCtrl_LinesOnScreen 3310
+#define wxStyledTextCtrl_UsePopUp 3311
+#define wxStyledTextCtrl_SelectionIsRectangle 3312
+#define wxStyledTextCtrl_SetZoom 3313
+#define wxStyledTextCtrl_GetZoom 3314
+#define wxStyledTextCtrl_GetModEventMask 3315
+#define wxStyledTextCtrl_SetSTCFocus 3316
+#define wxStyledTextCtrl_GetSTCFocus 3317
+#define wxStyledTextCtrl_SetStatus 3318
+#define wxStyledTextCtrl_GetStatus 3319
+#define wxStyledTextCtrl_SetMouseDownCaptures 3320
+#define wxStyledTextCtrl_GetMouseDownCaptures 3321
+#define wxStyledTextCtrl_SetSTCCursor 3322
+#define wxStyledTextCtrl_GetSTCCursor 3323
+#define wxStyledTextCtrl_SetControlCharSymbol 3324
+#define wxStyledTextCtrl_GetControlCharSymbol 3325
+#define wxStyledTextCtrl_WordPartLeft 3326
+#define wxStyledTextCtrl_WordPartLeftExtend 3327
+#define wxStyledTextCtrl_WordPartRight 3328
+#define wxStyledTextCtrl_WordPartRightExtend 3329
+#define wxStyledTextCtrl_SetVisiblePolicy 3330
+#define wxStyledTextCtrl_DelLineLeft 3331
+#define wxStyledTextCtrl_DelLineRight 3332
+#define wxStyledTextCtrl_GetXOffset 3333
+#define wxStyledTextCtrl_ChooseCaretX 3334
+#define wxStyledTextCtrl_SetXCaretPolicy 3335
+#define wxStyledTextCtrl_SetYCaretPolicy 3336
+#define wxStyledTextCtrl_GetPrintWrapMode 3337
+#define wxStyledTextCtrl_SetHotspotActiveForeground 3338
+#define wxStyledTextCtrl_SetHotspotActiveBackground 3339
+#define wxStyledTextCtrl_SetHotspotActiveUnderline 3340
+#define wxStyledTextCtrl_SetHotspotSingleLine 3341
+#define wxStyledTextCtrl_ParaDownExtend 3342
+#define wxStyledTextCtrl_ParaUp 3343
+#define wxStyledTextCtrl_ParaUpExtend 3344
+#define wxStyledTextCtrl_PositionBefore 3345
+#define wxStyledTextCtrl_PositionAfter 3346
+#define wxStyledTextCtrl_CopyRange 3347
+#define wxStyledTextCtrl_CopyText 3348
+#define wxStyledTextCtrl_SetSelectionMode 3349
+#define wxStyledTextCtrl_GetSelectionMode 3350
+#define wxStyledTextCtrl_LineDownRectExtend 3351
+#define wxStyledTextCtrl_LineUpRectExtend 3352
+#define wxStyledTextCtrl_CharLeftRectExtend 3353
+#define wxStyledTextCtrl_CharRightRectExtend 3354
+#define wxStyledTextCtrl_HomeRectExtend 3355
+#define wxStyledTextCtrl_VCHomeRectExtend 3356
+#define wxStyledTextCtrl_LineEndRectExtend 3357
+#define wxStyledTextCtrl_PageUpRectExtend 3358
+#define wxStyledTextCtrl_PageDownRectExtend 3359
+#define wxStyledTextCtrl_StutteredPageUp 3360
+#define wxStyledTextCtrl_StutteredPageUpExtend 3361
+#define wxStyledTextCtrl_StutteredPageDown 3362
+#define wxStyledTextCtrl_StutteredPageDownExtend 3363
+#define wxStyledTextCtrl_WordLeftEnd 3364
+#define wxStyledTextCtrl_WordLeftEndExtend 3365
+#define wxStyledTextCtrl_WordRightEnd 3366
+#define wxStyledTextCtrl_WordRightEndExtend 3367
+#define wxStyledTextCtrl_SetWhitespaceChars 3368
+#define wxStyledTextCtrl_SetCharsDefault 3369
+#define wxStyledTextCtrl_AutoCompGetCurrent 3370
+#define wxStyledTextCtrl_Allocate 3371
+#define wxStyledTextCtrl_FindColumn 3372
+#define wxStyledTextCtrl_GetCaretSticky 3373
+#define wxStyledTextCtrl_SetCaretSticky 3374
+#define wxStyledTextCtrl_ToggleCaretSticky 3375
+#define wxStyledTextCtrl_SetPasteConvertEndings 3376
+#define wxStyledTextCtrl_GetPasteConvertEndings 3377
+#define wxStyledTextCtrl_SelectionDuplicate 3378
+#define wxStyledTextCtrl_SetCaretLineBackAlpha 3379
+#define wxStyledTextCtrl_GetCaretLineBackAlpha 3380
+#define wxStyledTextCtrl_StartRecord 3381
+#define wxStyledTextCtrl_StopRecord 3382
+#define wxStyledTextCtrl_SetLexer 3383
+#define wxStyledTextCtrl_GetLexer 3384
+#define wxStyledTextCtrl_Colourise 3385
+#define wxStyledTextCtrl_SetProperty 3386
+#define wxStyledTextCtrl_SetKeyWords 3387
+#define wxStyledTextCtrl_SetLexerLanguage 3388
+#define wxStyledTextCtrl_GetProperty 3389
+#define wxStyledTextCtrl_GetStyleBitsNeeded 3390
+#define wxStyledTextCtrl_GetCurrentLine 3391
+#define wxStyledTextCtrl_StyleSetSpec 3392
+#define wxStyledTextCtrl_StyleSetFont 3393
+#define wxStyledTextCtrl_StyleSetFontAttr 3394
+#define wxStyledTextCtrl_StyleSetCharacterSet 3395
+#define wxStyledTextCtrl_StyleSetFontEncoding 3396
+#define wxStyledTextCtrl_CmdKeyExecute 3397
+#define wxStyledTextCtrl_SetMargins 3398
+#define wxStyledTextCtrl_GetSelection 3399
+#define wxStyledTextCtrl_PointFromPosition 3400
+#define wxStyledTextCtrl_ScrollToLine 3401
+#define wxStyledTextCtrl_ScrollToColumn 3402
+#define wxStyledTextCtrl_SetVScrollBar 3403
+#define wxStyledTextCtrl_SetHScrollBar 3404
+#define wxStyledTextCtrl_GetLastKeydownProcessed 3405
+#define wxStyledTextCtrl_SetLastKeydownProcessed 3406
+#define wxStyledTextCtrl_SaveFile 3407
+#define wxStyledTextCtrl_LoadFile 3408
+#define wxStyledTextCtrl_DoDragOver 3409
+#define wxStyledTextCtrl_DoDropText 3410
+#define wxStyledTextCtrl_GetUseAntiAliasing 3411
+#define wxStyledTextCtrl_AddTextRaw 3412
+#define wxStyledTextCtrl_InsertTextRaw 3413
+#define wxStyledTextCtrl_GetCurLineRaw 3414
+#define wxStyledTextCtrl_GetLineRaw 3415
+#define wxStyledTextCtrl_GetSelectedTextRaw 3416
+#define wxStyledTextCtrl_GetTextRangeRaw 3417
+#define wxStyledTextCtrl_SetTextRaw 3418
+#define wxStyledTextCtrl_GetTextRaw 3419
+#define wxStyledTextCtrl_AppendTextRaw 3420
+#define wxArtProvider_GetBitmap 3421
+#define wxArtProvider_GetIcon 3422
+#define wxTreeEvent_GetKeyCode 3423
+#define wxTreeEvent_GetItem 3424
+#define wxTreeEvent_GetKeyEvent 3425
+#define wxTreeEvent_GetLabel 3426
+#define wxTreeEvent_GetOldItem 3427
+#define wxTreeEvent_GetPoint 3428
+#define wxTreeEvent_IsEditCancelled 3429
+#define wxTreeEvent_SetToolTip 3430
+#define wxNotebookEvent_GetOldSelection 3431
+#define wxNotebookEvent_GetSelection 3432
+#define wxNotebookEvent_SetOldSelection 3433
+#define wxNotebookEvent_SetSelection 3434
+#define wxFileDataObject_new 3435
+#define wxFileDataObject_AddFile 3436
+#define wxFileDataObject_GetFilenames 3437
+#define wxFileDataObject_destroy 3438
+#define wxTextDataObject_new 3439
+#define wxTextDataObject_GetTextLength 3440
+#define wxTextDataObject_GetText 3441
+#define wxTextDataObject_SetText 3442
+#define wxTextDataObject_destroy 3443
+#define wxBitmapDataObject_new_1_1 3444
+#define wxBitmapDataObject_new_1_0 3445
+#define wxBitmapDataObject_GetBitmap 3446
+#define wxBitmapDataObject_SetBitmap 3447
+#define wxBitmapDataObject_destroy 3448
+#define wxClipboard_new 3450
+#define wxClipboard_destruct 3451
+#define wxClipboard_AddData 3452
+#define wxClipboard_Clear 3453
+#define wxClipboard_Close 3454
+#define wxClipboard_Flush 3455
+#define wxClipboard_GetData 3456
+#define wxClipboard_IsOpened 3457
+#define wxClipboard_Open 3458
+#define wxClipboard_SetData 3459
+#define wxClipboard_UsePrimarySelection 3461
+#define wxClipboard_IsSupported 3462
+#define wxClipboard_Get 3463
+#define wxSpinEvent_GetPosition 3464
+#define wxSpinEvent_SetPosition 3465
+#define wxSplitterWindow_new_0 3466
+#define wxSplitterWindow_new_2 3467
+#define wxSplitterWindow_destruct 3468
+#define wxSplitterWindow_Create 3469
+#define wxSplitterWindow_GetMinimumPaneSize 3470
+#define wxSplitterWindow_GetSashGravity 3471
+#define wxSplitterWindow_GetSashPosition 3472
+#define wxSplitterWindow_GetSplitMode 3473
+#define wxSplitterWindow_GetWindow1 3474
+#define wxSplitterWindow_GetWindow2 3475
+#define wxSplitterWindow_Initialize 3476
+#define wxSplitterWindow_IsSplit 3477
+#define wxSplitterWindow_ReplaceWindow 3478
+#define wxSplitterWindow_SetSashGravity 3479
+#define wxSplitterWindow_SetSashPosition 3480
+#define wxSplitterWindow_SetSashSize 3481
+#define wxSplitterWindow_SetMinimumPaneSize 3482
+#define wxSplitterWindow_SetSplitMode 3483
+#define wxSplitterWindow_SplitHorizontally 3484
+#define wxSplitterWindow_SplitVertically 3485
+#define wxSplitterWindow_Unsplit 3486
+#define wxSplitterWindow_UpdateSize 3487
+#define wxSplitterEvent_GetSashPosition 3488
+#define wxSplitterEvent_GetX 3489
+#define wxSplitterEvent_GetY 3490
+#define wxSplitterEvent_GetWindowBeingRemoved 3491
+#define wxSplitterEvent_SetSashPosition 3492
+#define wxHtmlWindow_new_0 3493
+#define wxHtmlWindow_new_2 3494
+#define wxHtmlWindow_AppendToPage 3495
+#define wxHtmlWindow_GetOpenedAnchor 3496
+#define wxHtmlWindow_GetOpenedPage 3497
+#define wxHtmlWindow_GetOpenedPageTitle 3498
+#define wxHtmlWindow_GetRelatedFrame 3499
+#define wxHtmlWindow_HistoryBack 3500
+#define wxHtmlWindow_HistoryCanBack 3501
+#define wxHtmlWindow_HistoryCanForward 3502
+#define wxHtmlWindow_HistoryClear 3503
+#define wxHtmlWindow_HistoryForward 3504
+#define wxHtmlWindow_LoadFile 3505
+#define wxHtmlWindow_LoadPage 3506
+#define wxHtmlWindow_SelectAll 3507
+#define wxHtmlWindow_SelectionToText 3508
+#define wxHtmlWindow_SelectLine 3509
+#define wxHtmlWindow_SelectWord 3510
+#define wxHtmlWindow_SetBorders 3511
+#define wxHtmlWindow_SetFonts 3512
+#define wxHtmlWindow_SetPage 3513
+#define wxHtmlWindow_SetRelatedFrame 3514
+#define wxHtmlWindow_SetRelatedStatusBar 3515
+#define wxHtmlWindow_ToText 3516
+#define wxHtmlWindow_destroy 3517
+#define wxHtmlLinkEvent_GetLinkInfo 3518
+#define wxSystemSettings_GetColour 3519
+#define wxSystemSettings_GetFont 3520
+#define wxSystemSettings_GetMetric 3521
+#define wxSystemSettings_GetScreenType 3522
+#define wxSystemOptions_GetOption 3523
+#define wxSystemOptions_GetOptionInt 3524
+#define wxSystemOptions_HasOption 3525
+#define wxSystemOptions_IsFalse 3526
+#define wxSystemOptions_SetOption_2_1 3527
+#define wxSystemOptions_SetOption_2_0 3528
+#define wxAuiNotebookEvent_SetSelection 3529
+#define wxAuiNotebookEvent_GetSelection 3530
+#define wxAuiNotebookEvent_SetOldSelection 3531
+#define wxAuiNotebookEvent_GetOldSelection 3532
+#define wxAuiNotebookEvent_SetDragSource 3533
+#define wxAuiNotebookEvent_GetDragSource 3534
+#define wxAuiManagerEvent_SetManager 3535
+#define wxAuiManagerEvent_GetManager 3536
+#define wxAuiManagerEvent_SetPane 3537
+#define wxAuiManagerEvent_GetPane 3538
+#define wxAuiManagerEvent_SetButton 3539
+#define wxAuiManagerEvent_GetButton 3540
+#define wxAuiManagerEvent_SetDC 3541
+#define wxAuiManagerEvent_GetDC 3542
+#define wxAuiManagerEvent_Veto 3543
+#define wxAuiManagerEvent_GetVeto 3544
+#define wxAuiManagerEvent_SetCanVeto 3545
+#define wxAuiManagerEvent_CanVeto 3546
+#define wxLogNull_new 3547
+#define wxLogNull_destroy 3548
+#define wxTaskBarIcon_new 3549
+#define wxTaskBarIcon_destruct 3550
+#define wxTaskBarIcon_PopupMenu 3551
+#define wxTaskBarIcon_RemoveIcon 3552
+#define wxTaskBarIcon_SetIcon 3553
+#define wxLocale_new_0 3554
+#define wxLocale_new_2 3556
+#define wxLocale_destruct 3557
+#define wxLocale_Init 3559
+#define wxLocale_AddCatalog_1 3560
+#define wxLocale_AddCatalog_3 3561
+#define wxLocale_AddCatalogLookupPathPrefix 3562
+#define wxLocale_GetCanonicalName 3563
+#define wxLocale_GetLanguage 3564
+#define wxLocale_GetLanguageName 3565
+#define wxLocale_GetLocale 3566
+#define wxLocale_GetName 3567
+#define wxLocale_GetString_2 3568
+#define wxLocale_GetString_4 3569
+#define wxLocale_GetHeaderValue 3570
+#define wxLocale_GetSysName 3571
+#define wxLocale_GetSystemEncoding 3572
+#define wxLocale_GetSystemEncodingName 3573
+#define wxLocale_GetSystemLanguage 3574
+#define wxLocale_IsLoaded 3575
+#define wxLocale_IsOk 3576
+#define wxActivateEvent_GetActive 3577
+#define wxPopupWindow_new_2 3579
+#define wxPopupWindow_new_0 3580
+#define wxPopupWindow_destruct 3582
+#define wxPopupWindow_Create 3583
+#define wxPopupWindow_Position 3584
+#define wxPopupTransientWindow_new_0 3585
+#define wxPopupTransientWindow_new_2 3586
+#define wxPopupTransientWindow_destruct 3587
+#define wxPopupTransientWindow_Popup 3588
+#define wxPopupTransientWindow_Dismiss 3589
+#define wxOverlay_new 3590
+#define wxOverlay_destruct 3591
+#define wxOverlay_Reset 3592
+#define wxDCOverlay_new_6 3593
+#define wxDCOverlay_new_2 3594
+#define wxDCOverlay_destruct 3595
+#define wxDCOverlay_Clear 3596
+#define wxDropFilesEvent_GetPosition 3597
+#define wxDropFilesEvent_GetNumberOfFiles 3598
+#define wxDropFilesEvent_GetFiles 3599
diff --git a/lib/wx/c_src/wxe_main.cpp b/lib/wx/c_src/wxe_main.cpp
index 6fcde42eb5..c7565e33bd 100644
--- a/lib/wx/c_src/wxe_main.cpp
+++ b/lib/wx/c_src/wxe_main.cpp
@@ -67,6 +67,7 @@ int load_native_gui()
int start_native_gui(wxe_data *sd)
{
int res;
+ ErlDrvThreadOpts *opts = NULL;
wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m");
wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c");
@@ -78,8 +79,11 @@ int start_native_gui(wxe_data *sd)
res = erl_drv_steal_main_thread((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL);
#else
+ opts = erl_drv_thread_opts_create((char *)"wx thread");
+ opts->suggested_stack_size = 8192;
res = erl_drv_thread_create((char *)"wxwidgets",
- &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL);
+ &wxe_thread,wxe_main_loop,(void *) sd->pdl,opts);
+ erl_drv_thread_opts_destroy(opts);
#endif
if(res == 0) {
erl_drv_mutex_lock(wxe_status_m);
diff --git a/lib/wx/doc/specs/.gitignore b/lib/wx/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/wx/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile
index cae2f9fe4e..23890f47f0 100644
--- a/lib/wx/doc/src/Makefile
+++ b/lib/wx/doc/src/Makefile
@@ -63,10 +63,15 @@ 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 +=
+SPECS_FLAGS = -I../../include -I../../src
DVIPS_FLAGS +=
# ----------------------------------------------------
@@ -111,6 +116,7 @@ clean clean_docs:
rm -rf $(HTMLDIR)/*
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECDIR)/*
rm -f errs core *~ ../html/edoc-info
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 4f0e166924..9086117c81 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -32,6 +32,52 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Allow string arguments to be binaries as specified, i.e.
+ unicode:chardata().</p>
+ <p>
+ Own Id: OTP-13934 Aux Id: ERL-270 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add wxWindow:dragAcceptFiles/2 and wxDropFilesEvent to
+ support simple drag and drop from file browser.</p>
+ <p>
+ Own Id: OTP-13933</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Wx 1.7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Increased the stacksize for the wx thread. The default
+ stacksize on Windows is 1MB which is not enough if the
+ user created many nested dialogs.</p>
+ <p>
+ Own Id: OTP-13816</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/doc/src/specs.xml b/lib/wx/doc/src/specs.xml
new file mode 100644
index 0000000000..2e19baafc4
--- /dev/null
+++ b/lib/wx/doc/src/specs.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_wx.xml"/>
+ <xi:include href="../specs/specs_wx_object.xml"/>
+ <xi:include href="../specs/specs_wxAcceleratorEntry.xml"/>
+ <xi:include href="../specs/specs_wxAcceleratorTable.xml"/>
+ <xi:include href="../specs/specs_wxActivateEvent.xml"/>
+ <xi:include href="../specs/specs_wxArtProvider.xml"/>
+ <xi:include href="../specs/specs_wxAuiDockArt.xml"/>
+ <xi:include href="../specs/specs_wxAuiManager.xml"/>
+ <xi:include href="../specs/specs_wxAuiManagerEvent.xml"/>
+ <xi:include href="../specs/specs_wxAuiNotebook.xml"/>
+ <xi:include href="../specs/specs_wxAuiNotebookEvent.xml"/>
+ <xi:include href="../specs/specs_wxAuiPaneInfo.xml"/>
+ <xi:include href="../specs/specs_wxAuiSimpleTabArt.xml"/>
+ <xi:include href="../specs/specs_wxAuiTabArt.xml"/>
+ <xi:include href="../specs/specs_wxBitmapButton.xml"/>
+ <xi:include href="../specs/specs_wxBitmapDataObject.xml"/>
+ <xi:include href="../specs/specs_wxBitmap.xml"/>
+ <xi:include href="../specs/specs_wxBoxSizer.xml"/>
+ <xi:include href="../specs/specs_wxBrush.xml"/>
+ <xi:include href="../specs/specs_wxBufferedDC.xml"/>
+ <xi:include href="../specs/specs_wxBufferedPaintDC.xml"/>
+ <xi:include href="../specs/specs_wxButton.xml"/>
+ <xi:include href="../specs/specs_wxCalendarCtrl.xml"/>
+ <xi:include href="../specs/specs_wxCalendarDateAttr.xml"/>
+ <xi:include href="../specs/specs_wxCalendarEvent.xml"/>
+ <xi:include href="../specs/specs_wxCaret.xml"/>
+ <xi:include href="../specs/specs_wxCheckBox.xml"/>
+ <xi:include href="../specs/specs_wxCheckListBox.xml"/>
+ <xi:include href="../specs/specs_wxChildFocusEvent.xml"/>
+ <xi:include href="../specs/specs_wxChoicebook.xml"/>
+ <xi:include href="../specs/specs_wxChoice.xml"/>
+ <xi:include href="../specs/specs_wxClientDC.xml"/>
+ <xi:include href="../specs/specs_wxClipboard.xml"/>
+ <xi:include href="../specs/specs_wxClipboardTextEvent.xml"/>
+ <xi:include href="../specs/specs_wxCloseEvent.xml"/>
+ <xi:include href="../specs/specs_wxColourData.xml"/>
+ <xi:include href="../specs/specs_wxColourDialog.xml"/>
+ <xi:include href="../specs/specs_wxColourPickerCtrl.xml"/>
+ <xi:include href="../specs/specs_wxColourPickerEvent.xml"/>
+ <xi:include href="../specs/specs_wxComboBox.xml"/>
+ <xi:include href="../specs/specs_wxCommandEvent.xml"/>
+ <xi:include href="../specs/specs_wxContextMenuEvent.xml"/>
+ <xi:include href="../specs/specs_wxControl.xml"/>
+ <xi:include href="../specs/specs_wxControlWithItems.xml"/>
+ <xi:include href="../specs/specs_wxCursor.xml"/>
+ <xi:include href="../specs/specs_wxDataObject.xml"/>
+ <xi:include href="../specs/specs_wxDateEvent.xml"/>
+ <xi:include href="../specs/specs_wxDatePickerCtrl.xml"/>
+ <xi:include href="../specs/specs_wxDC.xml"/>
+ <xi:include href="../specs/specs_wxDCOverlay.xml"/>
+ <xi:include href="../specs/specs_wxDialog.xml"/>
+ <xi:include href="../specs/specs_wxDirDialog.xml"/>
+ <xi:include href="../specs/specs_wxDirPickerCtrl.xml"/>
+ <xi:include href="../specs/specs_wxDisplayChangedEvent.xml"/>
+ <xi:include href="../specs/specs_wxEraseEvent.xml"/>
+ <xi:include href="../specs/specs_wxEvent.xml"/>
+ <xi:include href="../specs/specs_wxEvtHandler.xml"/>
+ <xi:include href="../specs/specs_wxFileDataObject.xml"/>
+ <xi:include href="../specs/specs_wxFileDialog.xml"/>
+ <xi:include href="../specs/specs_wxFileDirPickerEvent.xml"/>
+ <xi:include href="../specs/specs_wxFilePickerCtrl.xml"/>
+ <xi:include href="../specs/specs_wxFindReplaceData.xml"/>
+ <xi:include href="../specs/specs_wxFindReplaceDialog.xml"/>
+ <xi:include href="../specs/specs_wxFlexGridSizer.xml"/>
+ <xi:include href="../specs/specs_wxFocusEvent.xml"/>
+ <xi:include href="../specs/specs_wxFontData.xml"/>
+ <xi:include href="../specs/specs_wxFontDialog.xml"/>
+ <xi:include href="../specs/specs_wxFont.xml"/>
+ <xi:include href="../specs/specs_wxFontPickerCtrl.xml"/>
+ <xi:include href="../specs/specs_wxFontPickerEvent.xml"/>
+ <xi:include href="../specs/specs_wxFrame.xml"/>
+ <xi:include href="../specs/specs_wxGauge.xml"/>
+ <xi:include href="../specs/specs_wxGBSizerItem.xml"/>
+ <xi:include href="../specs/specs_wxGenericDirCtrl.xml"/>
+ <xi:include href="../specs/specs_wxGLCanvas.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsBrush.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsContext.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsFont.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsMatrix.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsObject.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsPath.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsPen.xml"/>
+ <xi:include href="../specs/specs_wxGraphicsRenderer.xml"/>
+ <xi:include href="../specs/specs_wxGridBagSizer.xml"/>
+ <xi:include href="../specs/specs_wxGridCellAttr.xml"/>
+ <xi:include href="../specs/specs_wxGridCellBoolEditor.xml"/>
+ <xi:include href="../specs/specs_wxGridCellBoolRenderer.xml"/>
+ <xi:include href="../specs/specs_wxGridCellChoiceEditor.xml"/>
+ <xi:include href="../specs/specs_wxGridCellEditor.xml"/>
+ <xi:include href="../specs/specs_wxGridCellFloatEditor.xml"/>
+ <xi:include href="../specs/specs_wxGridCellFloatRenderer.xml"/>
+ <xi:include href="../specs/specs_wxGridCellNumberEditor.xml"/>
+ <xi:include href="../specs/specs_wxGridCellNumberRenderer.xml"/>
+ <xi:include href="../specs/specs_wxGridCellRenderer.xml"/>
+ <xi:include href="../specs/specs_wxGridCellStringRenderer.xml"/>
+ <xi:include href="../specs/specs_wxGridCellTextEditor.xml"/>
+ <xi:include href="../specs/specs_wxGrid.xml"/>
+ <xi:include href="../specs/specs_wxGridEvent.xml"/>
+ <xi:include href="../specs/specs_wxGridSizer.xml"/>
+ <xi:include href="../specs/specs_wxHelpEvent.xml"/>
+ <xi:include href="../specs/specs_wxHtmlEasyPrinting.xml"/>
+ <xi:include href="../specs/specs_wxHtmlLinkEvent.xml"/>
+ <xi:include href="../specs/specs_wxHtmlWindow.xml"/>
+ <xi:include href="../specs/specs_wxIconBundle.xml"/>
+ <xi:include href="../specs/specs_wxIcon.xml"/>
+ <xi:include href="../specs/specs_wxIconizeEvent.xml"/>
+ <xi:include href="../specs/specs_wxIdleEvent.xml"/>
+ <xi:include href="../specs/specs_wxImage.xml"/>
+ <xi:include href="../specs/specs_wxImageList.xml"/>
+ <xi:include href="../specs/specs_wxInitDialogEvent.xml"/>
+ <xi:include href="../specs/specs_wxJoystickEvent.xml"/>
+ <xi:include href="../specs/specs_wxKeyEvent.xml"/>
+ <xi:include href="../specs/specs_wxLayoutAlgorithm.xml"/>
+ <xi:include href="../specs/specs_wxListbook.xml"/>
+ <xi:include href="../specs/specs_wxListBox.xml"/>
+ <xi:include href="../specs/specs_wxListCtrl.xml"/>
+ <xi:include href="../specs/specs_wxListEvent.xml"/>
+ <xi:include href="../specs/specs_wxListItemAttr.xml"/>
+ <xi:include href="../specs/specs_wxListItem.xml"/>
+ <xi:include href="../specs/specs_wxListView.xml"/>
+ <xi:include href="../specs/specs_wxLocale.xml"/>
+ <xi:include href="../specs/specs_wxLogNull.xml"/>
+ <xi:include href="../specs/specs_wxMask.xml"/>
+ <xi:include href="../specs/specs_wxMaximizeEvent.xml"/>
+ <xi:include href="../specs/specs_wxMDIChildFrame.xml"/>
+ <xi:include href="../specs/specs_wxMDIClientWindow.xml"/>
+ <xi:include href="../specs/specs_wxMDIParentFrame.xml"/>
+ <xi:include href="../specs/specs_wxMemoryDC.xml"/>
+ <xi:include href="../specs/specs_wxMenuBar.xml"/>
+ <xi:include href="../specs/specs_wxMenu.xml"/>
+ <xi:include href="../specs/specs_wxMenuEvent.xml"/>
+ <xi:include href="../specs/specs_wxMenuItem.xml"/>
+ <xi:include href="../specs/specs_wxMessageDialog.xml"/>
+ <xi:include href="../specs/specs_wxMiniFrame.xml"/>
+ <xi:include href="../specs/specs_wxMirrorDC.xml"/>
+ <xi:include href="../specs/specs_wxMouseCaptureChangedEvent.xml"/>
+ <xi:include href="../specs/specs_wxMouseCaptureLostEvent.xml"/>
+ <xi:include href="../specs/specs_wxMouseEvent.xml"/>
+ <xi:include href="../specs/specs_wxMoveEvent.xml"/>
+ <xi:include href="../specs/specs_wxMultiChoiceDialog.xml"/>
+ <xi:include href="../specs/specs_wxNavigationKeyEvent.xml"/>
+ <xi:include href="../specs/specs_wxNotebook.xml"/>
+ <xi:include href="../specs/specs_wxNotebookEvent.xml"/>
+ <xi:include href="../specs/specs_wxNotifyEvent.xml"/>
+ <xi:include href="../specs/specs_wxOverlay.xml"/>
+ <xi:include href="../specs/specs_wxPageSetupDialogData.xml"/>
+ <xi:include href="../specs/specs_wxPageSetupDialog.xml"/>
+ <xi:include href="../specs/specs_wxPaintDC.xml"/>
+ <xi:include href="../specs/specs_wxPaintEvent.xml"/>
+ <xi:include href="../specs/specs_wxPaletteChangedEvent.xml"/>
+ <xi:include href="../specs/specs_wxPalette.xml"/>
+ <xi:include href="../specs/specs_wxPanel.xml"/>
+ <xi:include href="../specs/specs_wxPasswordEntryDialog.xml"/>
+ <xi:include href="../specs/specs_wxPen.xml"/>
+ <xi:include href="../specs/specs_wxPickerBase.xml"/>
+ <xi:include href="../specs/specs_wxPopupTransientWindow.xml"/>
+ <xi:include href="../specs/specs_wxPopupWindow.xml"/>
+ <xi:include href="../specs/specs_wxPostScriptDC.xml"/>
+ <xi:include href="../specs/specs_wxPreviewCanvas.xml"/>
+ <xi:include href="../specs/specs_wxPreviewControlBar.xml"/>
+ <xi:include href="../specs/specs_wxPreviewFrame.xml"/>
+ <xi:include href="../specs/specs_wxPrintData.xml"/>
+ <xi:include href="../specs/specs_wxPrintDialogData.xml"/>
+ <xi:include href="../specs/specs_wxPrintDialog.xml"/>
+ <xi:include href="../specs/specs_wxPrinter.xml"/>
+ <xi:include href="../specs/specs_wxPrintout.xml"/>
+ <xi:include href="../specs/specs_wxPrintPreview.xml"/>
+ <xi:include href="../specs/specs_wxProgressDialog.xml"/>
+ <xi:include href="../specs/specs_wxQueryNewPaletteEvent.xml"/>
+ <xi:include href="../specs/specs_wxRadioBox.xml"/>
+ <xi:include href="../specs/specs_wxRadioButton.xml"/>
+ <xi:include href="../specs/specs_wxRegion.xml"/>
+ <xi:include href="../specs/specs_wxSashEvent.xml"/>
+ <xi:include href="../specs/specs_wxSashLayoutWindow.xml"/>
+ <xi:include href="../specs/specs_wxSashWindow.xml"/>
+ <xi:include href="../specs/specs_wxScreenDC.xml"/>
+ <xi:include href="../specs/specs_wxScrollBar.xml"/>
+ <xi:include href="../specs/specs_wxScrolledWindow.xml"/>
+ <xi:include href="../specs/specs_wxScrollEvent.xml"/>
+ <xi:include href="../specs/specs_wxScrollWinEvent.xml"/>
+ <xi:include href="../specs/specs_wxSetCursorEvent.xml"/>
+ <xi:include href="../specs/specs_wxShowEvent.xml"/>
+ <xi:include href="../specs/specs_wxSingleChoiceDialog.xml"/>
+ <xi:include href="../specs/specs_wxSizeEvent.xml"/>
+ <xi:include href="../specs/specs_wxSizer.xml"/>
+ <xi:include href="../specs/specs_wxSizerFlags.xml"/>
+ <xi:include href="../specs/specs_wxSizerItem.xml"/>
+ <xi:include href="../specs/specs_wxSlider.xml"/>
+ <xi:include href="../specs/specs_wxSpinButton.xml"/>
+ <xi:include href="../specs/specs_wxSpinCtrl.xml"/>
+ <xi:include href="../specs/specs_wxSpinEvent.xml"/>
+ <xi:include href="../specs/specs_wxSplashScreen.xml"/>
+ <xi:include href="../specs/specs_wxSplitterEvent.xml"/>
+ <xi:include href="../specs/specs_wxSplitterWindow.xml"/>
+ <xi:include href="../specs/specs_wxStaticBitmap.xml"/>
+ <xi:include href="../specs/specs_wxStaticBox.xml"/>
+ <xi:include href="../specs/specs_wxStaticBoxSizer.xml"/>
+ <xi:include href="../specs/specs_wxStaticLine.xml"/>
+ <xi:include href="../specs/specs_wxStaticText.xml"/>
+ <xi:include href="../specs/specs_wxStatusBar.xml"/>
+ <xi:include href="../specs/specs_wxStdDialogButtonSizer.xml"/>
+ <xi:include href="../specs/specs_wxStyledTextCtrl.xml"/>
+ <xi:include href="../specs/specs_wxStyledTextEvent.xml"/>
+ <xi:include href="../specs/specs_wxSysColourChangedEvent.xml"/>
+ <xi:include href="../specs/specs_wxSystemOptions.xml"/>
+ <xi:include href="../specs/specs_wxSystemSettings.xml"/>
+ <xi:include href="../specs/specs_wxTaskBarIcon.xml"/>
+ <xi:include href="../specs/specs_wxTaskBarIconEvent.xml"/>
+ <xi:include href="../specs/specs_wxTextAttr.xml"/>
+ <xi:include href="../specs/specs_wxTextCtrl.xml"/>
+ <xi:include href="../specs/specs_wxTextDataObject.xml"/>
+ <xi:include href="../specs/specs_wxTextEntryDialog.xml"/>
+ <xi:include href="../specs/specs_wxToggleButton.xml"/>
+ <xi:include href="../specs/specs_wxToolBar.xml"/>
+ <xi:include href="../specs/specs_wxToolbook.xml"/>
+ <xi:include href="../specs/specs_wxToolTip.xml"/>
+ <xi:include href="../specs/specs_wxTopLevelWindow.xml"/>
+ <xi:include href="../specs/specs_wxTreebook.xml"/>
+ <xi:include href="../specs/specs_wxTreeCtrl.xml"/>
+ <xi:include href="../specs/specs_wxTreeEvent.xml"/>
+ <xi:include href="../specs/specs_wxUpdateUIEvent.xml"/>
+ <xi:include href="../specs/specs_wxWindowCreateEvent.xml"/>
+ <xi:include href="../specs/specs_wxWindowDC.xml"/>
+ <xi:include href="../specs/specs_wxWindowDestroyEvent.xml"/>
+ <xi:include href="../specs/specs_wxWindow.xml"/>
+ <xi:include href="../specs/specs_wxXmlResource.xml"/>
+ <xi:include href="../specs/specs_wx_misc.xml"/>
+ <xi:include href="../specs/specs_glu.xml"/>
+ <xi:include href="../specs/specs_gl.xml"/>
+</specs>
diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl
index 99c28b3177..8b7412017a 100644
--- a/lib/wx/examples/demo/demo.erl
+++ b/lib/wx/examples/demo/demo.erl
@@ -60,11 +60,15 @@ start_link() ->
start_link(Debug) ->
wx_object:start_link(?MODULE, Debug, []).
+format(#state{log=Log}, Str, Args) ->
+ wxTextCtrl:appendText(Log, io_lib:format(Str, Args)),
+ ok;
format(Config,Str,Args) ->
Log = proplists:get_value(log, Config),
wxTextCtrl:appendText(Log, io_lib:format(Str, Args)),
ok.
+
-define(DEBUG_NONE, 101).
-define(DEBUG_VERBOSE, 102).
-define(DEBUG_TRACE, 103).
@@ -97,7 +101,11 @@ init(Options) ->
wxFrame:connect(Frame, close_window),
_SB = wxFrame:createStatusBar(Frame,[]),
-
+
+ %% Setup on toplevel because stc seems to steal this on linux
+ wxFrame:dragAcceptFiles(Frame, true),
+ wxFrame:connect(Frame, drop_files),
+
%% T Uppersplitter
%% O Left | Right
%% P Widgets|Code | Demo
@@ -201,15 +209,15 @@ handle_info({'EXIT',_, shutdown}, State) ->
handle_info({'EXIT',_, normal}, State) ->
{noreply,State};
handle_info(Msg, State) ->
- io:format("Got Info ~p~n",[Msg]),
+ format(State, "Got Info ~p~n",[Msg]),
{noreply,State}.
handle_call(Msg, _From, State) ->
- io:format("Got Call ~p~n",[Msg]),
+ format(State, "Got Call ~p~n",[Msg]),
{reply,ok,State}.
handle_cast(Msg, State) ->
- io:format("Got cast ~p~n",[Msg]),
+ format(State, "Got cast ~p~n",[Msg]),
{noreply,State}.
%% Async Events are handled in handle_event as in handle_info
@@ -286,7 +294,7 @@ handle_event(#wx{event=#wxClose{}}, State = #state{win=Frame}) ->
ok = wxFrame:setStatusText(Frame, "Closing...",[]),
{stop, normal, State};
handle_event(Ev,State) ->
- io:format("~p Got event ~p ~n",[?MODULE, Ev]),
+ format(State, "~p Got event ~p ~n",[?MODULE, Ev]),
{noreply, State}.
code_change(_, _, State) ->
@@ -364,6 +372,7 @@ code_area(Parent) ->
?stc:setVisiblePolicy(Ed, Policy, 3),
%% ?stc:connect(Ed, stc_doubleclick),
+ %% ?stc:connect(Ed, std_do_drop, fun(Ev, Obj) -> io:format("Ev ~p ~p~n",[Ev,Obj]) end),
?stc:setReadOnly(Ed, true),
Ed.
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index af7cca7ed2..a14cc89cee 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -33,164 +33,157 @@
%% Here comes the definitions of all event records.
%% they contain the event type and possible some extra information.
--record(wxInitDialog, {type :: wxInitDialogEventType()}). %% Callback event: {@link wxInitDialogEvent}
--type wxInitDialogEventType() :: 'init_dialog'.
--type wxInitDialog() :: #wxInitDialog{}. %% Callback event: {@link wxInitDialogEvent}
+-record(wxActivate,{type :: wxActivateEventType(), %% Callback event: {@link wxActivateEvent}
+ active :: boolean()}).
+-type wxActivateEventType() :: 'activate' | 'activate_app' | 'hibernate'.
+-type wxActivate() :: #wxActivate{}. %% Callback event: {@link wxActivateEvent}
--record(wxClose, {type :: wxCloseEventType()}). %% Callback event: {@link wxCloseEvent}
--type wxCloseEventType() :: 'close_window' | 'end_session' | 'query_end_session'.
--type wxClose() :: #wxClose{}. %% Callback event: {@link wxCloseEvent}
+-record(wxAuiManager,{type :: wxAuiManagerEventType(), %% Callback event: {@link wxAuiManagerEvent}
+ manager :: wxAuiManager:wxAuiManager(),
+ pane :: wxAuiPaneInfo:wxAuiPaneInfo(),
+ button :: integer(),
+ veto_flag :: boolean(),
+ canveto_flag :: boolean(),
+ dc :: wxDC:wxDC()}).
+-type wxAuiManagerEventType() :: 'aui_pane_button' | 'aui_pane_close' | 'aui_pane_maximize' | 'aui_pane_restore' | 'aui_pane_activated' | 'aui_render' | 'aui_find_manager'.
+-type wxAuiManager() :: #wxAuiManager{}. %% Callback event: {@link wxAuiManagerEvent}
--record(wxStyledText,{type :: wxStyledTextEventType(), %% Callback event: {@link wxStyledTextEvent}
- position :: integer(),
- key :: integer(),
- modifiers :: integer(),
- modificationType :: integer(),
- text :: unicode:chardata(),
- length :: integer(),
- linesAdded :: integer(),
- line :: integer(),
- foldLevelNow :: integer(),
- foldLevelPrev :: integer(),
- margin :: integer(),
- message :: integer(),
- wParam :: integer(),
- lParam :: integer(),
- listType :: integer(),
- x :: integer(),
- y :: integer(),
- dragText :: unicode:chardata(),
- dragAllowMove :: boolean(),
- dragResult :: wx:wx_enum()}).
--type wxStyledTextEventType() :: 'stc_change' | 'stc_styleneeded' | 'stc_charadded' | 'stc_savepointreached' | 'stc_savepointleft' | 'stc_romodifyattempt' | 'stc_key' | 'stc_doubleclick' | 'stc_updateui' | 'stc_modified' | 'stc_macrorecord' | 'stc_marginclick' | 'stc_needshown' | 'stc_painted' | 'stc_userlistselection' | 'stc_uridropped' | 'stc_dwellstart' | 'stc_dwellend' | 'stc_start_drag' | 'stc_drag_over' | 'stc_do_drop' | 'stc_zoom' | 'stc_hotspot_click' | 'stc_hotspot_dclick' | 'stc_calltip_click' | 'stc_autocomp_selection'.
--type wxStyledText() :: #wxStyledText{}. %% Callback event: {@link wxStyledTextEvent}
+-record(wxAuiNotebook,{type :: wxAuiNotebookEventType(), %% Callback event: {@link wxAuiNotebookEvent}
+ old_selection :: integer(),
+ selection :: integer(),
+ drag_source :: wxAuiNotebook:wxAuiNotebook()}).
+-type wxAuiNotebookEventType() :: 'command_auinotebook_page_close' | 'command_auinotebook_page_changed' | 'command_auinotebook_page_changing' | 'command_auinotebook_button' | 'command_auinotebook_begin_drag' | 'command_auinotebook_end_drag' | 'command_auinotebook_drag_motion' | 'command_auinotebook_allow_dnd' | 'command_auinotebook_tab_middle_down' | 'command_auinotebook_tab_middle_up' | 'command_auinotebook_tab_right_down' | 'command_auinotebook_tab_right_up' | 'command_auinotebook_page_closed' | 'command_auinotebook_drag_done' | 'command_auinotebook_bg_dclick'.
+-type wxAuiNotebook() :: #wxAuiNotebook{}. %% Callback event: {@link wxAuiNotebookEvent}
--record(wxFileDirPicker,{type :: wxFileDirPickerEventType(), %% Callback event: {@link wxFileDirPickerEvent}
- path :: unicode:chardata()}).
--type wxFileDirPickerEventType() :: 'command_filepicker_changed' | 'command_dirpicker_changed'.
--type wxFileDirPicker() :: #wxFileDirPicker{}. %% Callback event: {@link wxFileDirPickerEvent}
+-record(wxCalendar,{type :: wxCalendarEventType(), %% Callback event: {@link wxCalendarEvent}
+ wday :: wx:wx_enum(),
+ date :: wx:wx_datetime()}).
+-type wxCalendarEventType() :: 'calendar_sel_changed' | 'calendar_day_changed' | 'calendar_month_changed' | 'calendar_year_changed' | 'calendar_doubleclicked' | 'calendar_weekday_clicked'.
+-type wxCalendar() :: #wxCalendar{}. %% Callback event: {@link wxCalendarEvent}
--record(wxNotebook,{type :: wxNotebookEventType(), %% Callback event: {@link wxNotebookEvent}
- nSel :: integer(),
- nOldSel :: integer()}).
--type wxNotebookEventType() :: 'command_notebook_page_changed' | 'command_notebook_page_changing'.
--type wxNotebook() :: #wxNotebook{}. %% Callback event: {@link wxNotebookEvent}
+-record(wxChildFocus, {type :: wxChildFocusEventType()}). %% Callback event: {@link wxChildFocusEvent}
+-type wxChildFocusEventType() :: 'child_focus'.
+-type wxChildFocus() :: #wxChildFocus{}. %% Callback event: {@link wxChildFocusEvent}
--record(wxIdle, {type :: wxIdleEventType()}). %% Callback event: {@link wxIdleEvent}
--type wxIdleEventType() :: 'idle'.
--type wxIdle() :: #wxIdle{}. %% Callback event: {@link wxIdleEvent}
+-record(wxClipboardText, {type :: wxClipboardTextEventType()}). %% Callback event: {@link wxClipboardTextEvent}
+-type wxClipboardTextEventType() :: 'command_text_copy' | 'command_text_cut' | 'command_text_paste'.
+-type wxClipboardText() :: #wxClipboardText{}. %% Callback event: {@link wxClipboardTextEvent}
+
+-record(wxClose, {type :: wxCloseEventType()}). %% Callback event: {@link wxCloseEvent}
+-type wxCloseEventType() :: 'close_window' | 'end_session' | 'query_end_session'.
+-type wxClose() :: #wxClose{}. %% Callback event: {@link wxCloseEvent}
-record(wxColourPicker,{type :: wxColourPickerEventType(), %% Callback event: {@link wxColourPickerEvent}
colour :: wx:wx_colour()}).
-type wxColourPickerEventType() :: 'command_colourpicker_changed'.
-type wxColourPicker() :: #wxColourPicker{}. %% Callback event: {@link wxColourPickerEvent}
--record(wxSplitter, {type :: wxSplitterEventType()}). %% Callback event: {@link wxSplitterEvent}
--type wxSplitterEventType() :: 'command_splitter_sash_pos_changed' | 'command_splitter_sash_pos_changing' | 'command_splitter_doubleclicked' | 'command_splitter_unsplit'.
--type wxSplitter() :: #wxSplitter{}. %% Callback event: {@link wxSplitterEvent}
+-record(wxCommand,{type :: wxCommandEventType(), %% Callback event: {@link wxCommandEvent}
+ cmdString :: unicode:chardata(),
+ commandInt :: integer(),
+ extraLong :: integer()}).
+-type wxCommandEventType() :: 'command_button_clicked' | 'command_checkbox_clicked' | 'command_choice_selected' | 'command_listbox_selected' | 'command_listbox_doubleclicked' | 'command_text_updated' | 'command_text_enter' | 'command_menu_selected' | 'command_slider_updated' | 'command_radiobox_selected' | 'command_radiobutton_selected' | 'command_scrollbar_updated' | 'command_vlbox_selected' | 'command_combobox_selected' | 'command_tool_rclicked' | 'command_tool_enter' | 'command_checklistbox_toggled' | 'command_togglebutton_clicked' | 'command_left_click' | 'command_left_dclick' | 'command_right_click' | 'command_set_focus' | 'command_kill_focus' | 'command_enter'.
+-type wxCommand() :: #wxCommand{}. %% Callback event: {@link wxCommandEvent}
--record(wxSash,{type :: wxSashEventType(), %% Callback event: {@link wxSashEvent}
- edge :: wx:wx_enum(),
- dragRect :: {X::integer(), Y::integer(), W::integer(), H::integer()},
- dragStatus :: wx:wx_enum()}).
--type wxSashEventType() :: 'sash_dragged'.
--type wxSash() :: #wxSash{}. %% Callback event: {@link wxSashEvent}
+-record(wxContextMenu,{type :: wxContextMenuEventType(), %% Callback event: {@link wxContextMenuEvent}
+ pos :: {X::integer(), Y::integer()}}).
+-type wxContextMenuEventType() :: 'context_menu'.
+-type wxContextMenu() :: #wxContextMenu{}. %% Callback event: {@link wxContextMenuEvent}
--record(wxHelp, {type :: wxHelpEventType()}). %% Callback event: {@link wxHelpEvent}
--type wxHelpEventType() :: 'help' | 'detailed_help'.
--type wxHelp() :: #wxHelp{}. %% Callback event: {@link wxHelpEvent}
+-record(wxDate,{type :: wxDateEventType(), %% Callback event: {@link wxDateEvent}
+ date :: wx:wx_datetime()}).
+-type wxDateEventType() :: 'date_changed'.
+-type wxDate() :: #wxDate{}. %% Callback event: {@link wxDateEvent}
-record(wxDisplayChanged, {type :: wxDisplayChangedEventType()}). %% Callback event: {@link wxDisplayChangedEvent}
-type wxDisplayChangedEventType() :: 'display_changed'.
-type wxDisplayChanged() :: #wxDisplayChanged{}. %% Callback event: {@link wxDisplayChangedEvent}
--record(wxMouseCaptureLost, {type :: wxMouseCaptureLostEventType()}). %% Callback event: {@link wxMouseCaptureLostEvent}
--type wxMouseCaptureLostEventType() :: 'mouse_capture_lost'.
--type wxMouseCaptureLost() :: #wxMouseCaptureLost{}. %% Callback event: {@link wxMouseCaptureLostEvent}
+-record(wxDropFiles,{type :: wxDropFilesEventType(), %% Callback event: {@link wxDropFilesEvent}
+ noFiles :: integer(),
+ pos :: {X::integer(), Y::integer()},
+ files :: [unicode:chardata()]}).
+-type wxDropFilesEventType() :: 'drop_files'.
+-type wxDropFiles() :: #wxDropFiles{}. %% Callback event: {@link wxDropFilesEvent}
--record(wxFontPicker,{type :: wxFontPickerEventType(), %% Callback event: {@link wxFontPickerEvent}
- font :: wxFont:wxFont()}).
--type wxFontPickerEventType() :: 'command_fontpicker_changed'.
--type wxFontPicker() :: #wxFontPicker{}. %% Callback event: {@link wxFontPickerEvent}
+-record(wxErase,{type :: wxEraseEventType(), %% Callback event: {@link wxEraseEvent}
+ dc :: wxDC:wxDC()}).
+-type wxEraseEventType() :: 'erase_background'.
+-type wxErase() :: #wxErase{}. %% Callback event: {@link wxEraseEvent}
+
+-record(wxFileDirPicker,{type :: wxFileDirPickerEventType(), %% Callback event: {@link wxFileDirPickerEvent}
+ path :: unicode:chardata()}).
+-type wxFileDirPickerEventType() :: 'command_filepicker_changed' | 'command_dirpicker_changed'.
+-type wxFileDirPicker() :: #wxFileDirPicker{}. %% Callback event: {@link wxFileDirPickerEvent}
-record(wxFocus,{type :: wxFocusEventType(), %% Callback event: {@link wxFocusEvent}
win :: wxWindow:wxWindow()}).
-type wxFocusEventType() :: 'set_focus' | 'kill_focus'.
-type wxFocus() :: #wxFocus{}. %% Callback event: {@link wxFocusEvent}
--record(wxPaletteChanged, {type :: wxPaletteChangedEventType()}). %% Callback event: {@link wxPaletteChangedEvent}
--type wxPaletteChangedEventType() :: 'palette_changed'.
--type wxPaletteChanged() :: #wxPaletteChanged{}. %% Callback event: {@link wxPaletteChangedEvent}
-
--record(wxScroll,{type :: wxScrollEventType(), %% Callback event: {@link wxScrollEvent}
- commandInt :: integer(),
- extraLong :: integer()}).
--type wxScrollEventType() :: 'scroll_top' | 'scroll_bottom' | 'scroll_lineup' | 'scroll_linedown' | 'scroll_pageup' | 'scroll_pagedown' | 'scroll_thumbtrack' | 'scroll_thumbrelease' | 'scroll_changed'.
--type wxScroll() :: #wxScroll{}. %% Callback event: {@link wxScrollEvent}
-
--record(wxChildFocus, {type :: wxChildFocusEventType()}). %% Callback event: {@link wxChildFocusEvent}
--type wxChildFocusEventType() :: 'child_focus'.
--type wxChildFocus() :: #wxChildFocus{}. %% Callback event: {@link wxChildFocusEvent}
-
--record(wxAuiNotebook,{type :: wxAuiNotebookEventType(), %% Callback event: {@link wxAuiNotebookEvent}
- old_selection :: integer(),
- selection :: integer(),
- drag_source :: wxAuiNotebook:wxAuiNotebook()}).
--type wxAuiNotebookEventType() :: 'command_auinotebook_page_close' | 'command_auinotebook_page_changed' | 'command_auinotebook_page_changing' | 'command_auinotebook_button' | 'command_auinotebook_begin_drag' | 'command_auinotebook_end_drag' | 'command_auinotebook_drag_motion' | 'command_auinotebook_allow_dnd' | 'command_auinotebook_tab_middle_down' | 'command_auinotebook_tab_middle_up' | 'command_auinotebook_tab_right_down' | 'command_auinotebook_tab_right_up' | 'command_auinotebook_page_closed' | 'command_auinotebook_drag_done' | 'command_auinotebook_bg_dclick'.
--type wxAuiNotebook() :: #wxAuiNotebook{}. %% Callback event: {@link wxAuiNotebookEvent}
-
--record(wxSize,{type :: wxSizeEventType(), %% Callback event: {@link wxSizeEvent}
- size :: {W::integer(), H::integer()},
- rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}).
--type wxSizeEventType() :: 'size'.
--type wxSize() :: #wxSize{}. %% Callback event: {@link wxSizeEvent}
-
--record(wxCommand,{type :: wxCommandEventType(), %% Callback event: {@link wxCommandEvent}
- cmdString :: unicode:chardata(),
- commandInt :: integer(),
- extraLong :: integer()}).
--type wxCommandEventType() :: 'command_button_clicked' | 'command_checkbox_clicked' | 'command_choice_selected' | 'command_listbox_selected' | 'command_listbox_doubleclicked' | 'command_text_updated' | 'command_text_enter' | 'command_menu_selected' | 'command_slider_updated' | 'command_radiobox_selected' | 'command_radiobutton_selected' | 'command_scrollbar_updated' | 'command_vlbox_selected' | 'command_combobox_selected' | 'command_tool_rclicked' | 'command_tool_enter' | 'command_checklistbox_toggled' | 'command_togglebutton_clicked' | 'command_left_click' | 'command_left_dclick' | 'command_right_click' | 'command_set_focus' | 'command_kill_focus' | 'command_enter'.
--type wxCommand() :: #wxCommand{}. %% Callback event: {@link wxCommandEvent}
-
--record(wxMaximize, {type :: wxMaximizeEventType()}). %% Callback event: {@link wxMaximizeEvent}
--type wxMaximizeEventType() :: 'maximize'.
--type wxMaximize() :: #wxMaximize{}. %% Callback event: {@link wxMaximizeEvent}
+-record(wxFontPicker,{type :: wxFontPickerEventType(), %% Callback event: {@link wxFontPickerEvent}
+ font :: wxFont:wxFont()}).
+-type wxFontPickerEventType() :: 'command_fontpicker_changed'.
+-type wxFontPicker() :: #wxFontPicker{}. %% Callback event: {@link wxFontPickerEvent}
--record(wxSpin,{type :: wxSpinEventType(), %% Callback event: {@link wxSpinEvent}
- commandInt :: integer()}).
--type wxSpinEventType() :: 'command_spinctrl_updated' | 'spin_up' | 'spin_down' | 'spin'.
--type wxSpin() :: #wxSpin{}. %% Callback event: {@link wxSpinEvent}
+-record(wxGrid,{type :: wxGridEventType(), %% Callback event: {@link wxGridEvent}
+ row :: integer(),
+ col :: integer(),
+ x :: integer(),
+ y :: integer(),
+ selecting :: boolean(),
+ control :: boolean(),
+ meta :: boolean(),
+ shift :: boolean(),
+ alt :: boolean()}).
+-type wxGridEventType() :: 'grid_cell_left_click' | 'grid_cell_right_click' | 'grid_cell_left_dclick' | 'grid_cell_right_dclick' | 'grid_label_left_click' | 'grid_label_right_click' | 'grid_label_left_dclick' | 'grid_label_right_dclick' | 'grid_row_size' | 'grid_col_size' | 'grid_range_select' | 'grid_cell_change' | 'grid_select_cell' | 'grid_editor_shown' | 'grid_editor_hidden' | 'grid_editor_created' | 'grid_cell_begin_drag'.
+-type wxGrid() :: #wxGrid{}. %% Callback event: {@link wxGridEvent}
--record(wxMenu,{type :: wxMenuEventType(), %% Callback event: {@link wxMenuEvent}
- menuId :: integer(),
- menu :: wxMenu:wxMenu()}).
--type wxMenuEventType() :: 'menu_open' | 'menu_close' | 'menu_highlight'.
--type wxMenu() :: #wxMenu{}. %% Callback event: {@link wxMenuEvent}
+-record(wxHelp, {type :: wxHelpEventType()}). %% Callback event: {@link wxHelpEvent}
+-type wxHelpEventType() :: 'help' | 'detailed_help'.
+-type wxHelp() :: #wxHelp{}. %% Callback event: {@link wxHelpEvent}
--record(wxShow,{type :: wxShowEventType(), %% Callback event: {@link wxShowEvent}
- show :: boolean()}).
--type wxShowEventType() :: 'show'.
--type wxShow() :: #wxShow{}. %% Callback event: {@link wxShowEvent}
+-record(wxHtmlLink,{type :: wxHtmlLinkEventType(), %% Callback event: {@link wxHtmlLinkEvent}
+ linkInfo :: wx:wx_wxHtmlLinkInfo()}).
+-type wxHtmlLinkEventType() :: 'command_html_link_clicked'.
+-type wxHtmlLink() :: #wxHtmlLink{}. %% Callback event: {@link wxHtmlLinkEvent}
--record(wxWindowDestroy, {type :: wxWindowDestroyEventType()}). %% Callback event: {@link wxWindowDestroyEvent}
--type wxWindowDestroyEventType() :: 'destroy'.
--type wxWindowDestroy() :: #wxWindowDestroy{}. %% Callback event: {@link wxWindowDestroyEvent}
+-record(wxIconize,{type :: wxIconizeEventType(), %% Callback event: {@link wxIconizeEvent}
+ iconized :: boolean()}).
+-type wxIconizeEventType() :: 'iconize'.
+-type wxIconize() :: #wxIconize{}. %% Callback event: {@link wxIconizeEvent}
--record(wxContextMenu,{type :: wxContextMenuEventType(), %% Callback event: {@link wxContextMenuEvent}
- pos :: {X::integer(), Y::integer()}}).
--type wxContextMenuEventType() :: 'context_menu'.
--type wxContextMenu() :: #wxContextMenu{}. %% Callback event: {@link wxContextMenuEvent}
+-record(wxIdle, {type :: wxIdleEventType()}). %% Callback event: {@link wxIdleEvent}
+-type wxIdleEventType() :: 'idle'.
+-type wxIdle() :: #wxIdle{}. %% Callback event: {@link wxIdleEvent}
--record(wxActivate,{type :: wxActivateEventType(), %% Callback event: {@link wxActivateEvent}
- active :: boolean()}).
--type wxActivateEventType() :: 'activate' | 'activate_app' | 'hibernate'.
--type wxActivate() :: #wxActivate{}. %% Callback event: {@link wxActivateEvent}
+-record(wxInitDialog, {type :: wxInitDialogEventType()}). %% Callback event: {@link wxInitDialogEvent}
+-type wxInitDialogEventType() :: 'init_dialog'.
+-type wxInitDialog() :: #wxInitDialog{}. %% Callback event: {@link wxInitDialogEvent}
--record(wxMove,{type :: wxMoveEventType(), %% Callback event: {@link wxMoveEvent}
+-record(wxJoystick,{type :: wxJoystickEventType(), %% Callback event: {@link wxJoystickEvent}
pos :: {X::integer(), Y::integer()},
- rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}).
--type wxMoveEventType() :: 'move'.
--type wxMove() :: #wxMove{}. %% Callback event: {@link wxMoveEvent}
+ zPosition :: integer(),
+ buttonChange :: integer(),
+ buttonState :: integer(),
+ joyStick :: integer()}).
+-type wxJoystickEventType() :: 'joy_button_down' | 'joy_button_up' | 'joy_move' | 'joy_zmove'.
+-type wxJoystick() :: #wxJoystick{}. %% Callback event: {@link wxJoystickEvent}
+
+-record(wxKey,{type :: wxKeyEventType(), %% Callback event: {@link wxKeyEvent}
+ x :: integer(),
+ y :: integer(),
+ keyCode :: integer(),
+ controlDown :: boolean(),
+ shiftDown :: boolean(),
+ altDown :: boolean(),
+ metaDown :: boolean(),
+ scanCode :: boolean(),
+ uniChar :: integer(),
+ rawCode :: integer(),
+ rawFlags :: integer()}).
+-type wxKeyEventType() :: 'char' | 'char_hook' | 'key_down' | 'key_up'.
+-type wxKey() :: #wxKey{}. %% Callback event: {@link wxKeyEvent}
-record(wxList,{type :: wxListEventType(), %% Callback event: {@link wxListEvent}
code :: integer(),
@@ -201,24 +194,23 @@
-type wxListEventType() :: 'command_list_begin_drag' | 'command_list_begin_rdrag' | 'command_list_begin_label_edit' | 'command_list_end_label_edit' | 'command_list_delete_item' | 'command_list_delete_all_items' | 'command_list_key_down' | 'command_list_insert_item' | 'command_list_col_click' | 'command_list_col_right_click' | 'command_list_col_begin_drag' | 'command_list_col_dragging' | 'command_list_col_end_drag' | 'command_list_item_selected' | 'command_list_item_deselected' | 'command_list_item_right_click' | 'command_list_item_middle_click' | 'command_list_item_activated' | 'command_list_item_focused' | 'command_list_cache_hint'.
-type wxList() :: #wxList{}. %% Callback event: {@link wxListEvent}
--record(wxClipboardText, {type :: wxClipboardTextEventType()}). %% Callback event: {@link wxClipboardTextEvent}
--type wxClipboardTextEventType() :: 'command_text_copy' | 'command_text_cut' | 'command_text_paste'.
--type wxClipboardText() :: #wxClipboardText{}. %% Callback event: {@link wxClipboardTextEvent}
+-record(wxMaximize, {type :: wxMaximizeEventType()}). %% Callback event: {@link wxMaximizeEvent}
+-type wxMaximizeEventType() :: 'maximize'.
+-type wxMaximize() :: #wxMaximize{}. %% Callback event: {@link wxMaximizeEvent}
--record(wxScrollWin,{type :: wxScrollWinEventType(), %% Callback event: {@link wxScrollWinEvent}
- commandInt :: integer(),
- extraLong :: integer()}).
--type wxScrollWinEventType() :: 'scrollwin_top' | 'scrollwin_bottom' | 'scrollwin_lineup' | 'scrollwin_linedown' | 'scrollwin_pageup' | 'scrollwin_pagedown' | 'scrollwin_thumbtrack' | 'scrollwin_thumbrelease'.
--type wxScrollWin() :: #wxScrollWin{}. %% Callback event: {@link wxScrollWinEvent}
+-record(wxMenu,{type :: wxMenuEventType(), %% Callback event: {@link wxMenuEvent}
+ menuId :: integer(),
+ menu :: wxMenu:wxMenu()}).
+-type wxMenuEventType() :: 'menu_open' | 'menu_close' | 'menu_highlight'.
+-type wxMenu() :: #wxMenu{}. %% Callback event: {@link wxMenuEvent}
--record(wxIconize,{type :: wxIconizeEventType(), %% Callback event: {@link wxIconizeEvent}
- iconized :: boolean()}).
--type wxIconizeEventType() :: 'iconize'.
--type wxIconize() :: #wxIconize{}. %% Callback event: {@link wxIconizeEvent}
+-record(wxMouseCaptureChanged, {type :: wxMouseCaptureChangedEventType()}). %% Callback event: {@link wxMouseCaptureChangedEvent}
+-type wxMouseCaptureChangedEventType() :: 'mouse_capture_changed'.
+-type wxMouseCaptureChanged() :: #wxMouseCaptureChanged{}. %% Callback event: {@link wxMouseCaptureChangedEvent}
--record(wxUpdateUI, {type :: wxUpdateUIEventType()}). %% Callback event: {@link wxUpdateUIEvent}
--type wxUpdateUIEventType() :: 'update_ui'.
--type wxUpdateUI() :: #wxUpdateUI{}. %% Callback event: {@link wxUpdateUIEvent}
+-record(wxMouseCaptureLost, {type :: wxMouseCaptureLostEventType()}). %% Callback event: {@link wxMouseCaptureLostEvent}
+-type wxMouseCaptureLostEventType() :: 'mouse_capture_lost'.
+-type wxMouseCaptureLost() :: #wxMouseCaptureLost{}. %% Callback event: {@link wxMouseCaptureLostEvent}
-record(wxMouse,{type :: wxMouseEventType(), %% Callback event: {@link wxMouseEvent}
x :: integer(),
@@ -236,16 +228,11 @@
-type wxMouseEventType() :: 'left_down' | 'left_up' | 'middle_down' | 'middle_up' | 'right_down' | 'right_up' | 'motion' | 'enter_window' | 'leave_window' | 'left_dclick' | 'middle_dclick' | 'right_dclick' | 'mousewheel'.
-type wxMouse() :: #wxMouse{}. %% Callback event: {@link wxMouseEvent}
--record(wxTree,{type :: wxTreeEventType(), %% Callback event: {@link wxTreeEvent}
- item :: integer(),
- itemOld :: integer(),
- pointDrag :: {X::integer(), Y::integer()}}).
--type wxTreeEventType() :: 'command_tree_begin_drag' | 'command_tree_begin_rdrag' | 'command_tree_begin_label_edit' | 'command_tree_end_label_edit' | 'command_tree_delete_item' | 'command_tree_get_info' | 'command_tree_set_info' | 'command_tree_item_expanded' | 'command_tree_item_expanding' | 'command_tree_item_collapsed' | 'command_tree_item_collapsing' | 'command_tree_sel_changed' | 'command_tree_sel_changing' | 'command_tree_key_down' | 'command_tree_item_activated' | 'command_tree_item_right_click' | 'command_tree_item_middle_click' | 'command_tree_end_drag' | 'command_tree_state_image_click' | 'command_tree_item_gettooltip' | 'command_tree_item_menu'.
--type wxTree() :: #wxTree{}. %% Callback event: {@link wxTreeEvent}
-
--record(wxSysColourChanged, {type :: wxSysColourChangedEventType()}). %% Callback event: {@link wxSysColourChangedEvent}
--type wxSysColourChangedEventType() :: 'sys_colour_changed'.
--type wxSysColourChanged() :: #wxSysColourChanged{}. %% Callback event: {@link wxSysColourChangedEvent}
+-record(wxMove,{type :: wxMoveEventType(), %% Callback event: {@link wxMoveEvent}
+ pos :: {X::integer(), Y::integer()},
+ rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}).
+-type wxMoveEventType() :: 'move'.
+-type wxMove() :: #wxMove{}. %% Callback event: {@link wxMoveEvent}
-record(wxNavigationKey,{type :: wxNavigationKeyEventType(), %% Callback event: {@link wxNavigationKeyEvent}
flags :: integer(),
@@ -253,103 +240,123 @@
-type wxNavigationKeyEventType() :: 'navigation_key'.
-type wxNavigationKey() :: #wxNavigationKey{}. %% Callback event: {@link wxNavigationKeyEvent}
+-record(wxNotebook,{type :: wxNotebookEventType(), %% Callback event: {@link wxNotebookEvent}
+ nSel :: integer(),
+ nOldSel :: integer()}).
+-type wxNotebookEventType() :: 'command_notebook_page_changed' | 'command_notebook_page_changing'.
+-type wxNotebook() :: #wxNotebook{}. %% Callback event: {@link wxNotebookEvent}
+
+-record(wxPaint, {type :: wxPaintEventType()}). %% Callback event: {@link wxPaintEvent}
+-type wxPaintEventType() :: 'paint'.
+-type wxPaint() :: #wxPaint{}. %% Callback event: {@link wxPaintEvent}
+
+-record(wxPaletteChanged, {type :: wxPaletteChangedEventType()}). %% Callback event: {@link wxPaletteChangedEvent}
+-type wxPaletteChangedEventType() :: 'palette_changed'.
+-type wxPaletteChanged() :: #wxPaletteChanged{}. %% Callback event: {@link wxPaletteChangedEvent}
+
-record(wxQueryNewPalette, {type :: wxQueryNewPaletteEventType()}). %% Callback event: {@link wxQueryNewPaletteEvent}
-type wxQueryNewPaletteEventType() :: 'query_new_palette'.
-type wxQueryNewPalette() :: #wxQueryNewPalette{}. %% Callback event: {@link wxQueryNewPaletteEvent}
--record(wxMouseCaptureChanged, {type :: wxMouseCaptureChangedEventType()}). %% Callback event: {@link wxMouseCaptureChangedEvent}
--type wxMouseCaptureChangedEventType() :: 'mouse_capture_changed'.
--type wxMouseCaptureChanged() :: #wxMouseCaptureChanged{}. %% Callback event: {@link wxMouseCaptureChangedEvent}
+-record(wxSash,{type :: wxSashEventType(), %% Callback event: {@link wxSashEvent}
+ edge :: wx:wx_enum(),
+ dragRect :: {X::integer(), Y::integer(), W::integer(), H::integer()},
+ dragStatus :: wx:wx_enum()}).
+-type wxSashEventType() :: 'sash_dragged'.
+-type wxSash() :: #wxSash{}. %% Callback event: {@link wxSashEvent}
--record(wxHtmlLink,{type :: wxHtmlLinkEventType(), %% Callback event: {@link wxHtmlLinkEvent}
- linkInfo :: wx:wx_wxHtmlLinkInfo()}).
--type wxHtmlLinkEventType() :: 'command_html_link_clicked'.
--type wxHtmlLink() :: #wxHtmlLink{}. %% Callback event: {@link wxHtmlLinkEvent}
+-record(wxScroll,{type :: wxScrollEventType(), %% Callback event: {@link wxScrollEvent}
+ commandInt :: integer(),
+ extraLong :: integer()}).
+-type wxScrollEventType() :: 'scroll_top' | 'scroll_bottom' | 'scroll_lineup' | 'scroll_linedown' | 'scroll_pageup' | 'scroll_pagedown' | 'scroll_thumbtrack' | 'scroll_thumbrelease' | 'scroll_changed'.
+-type wxScroll() :: #wxScroll{}. %% Callback event: {@link wxScrollEvent}
--record(wxKey,{type :: wxKeyEventType(), %% Callback event: {@link wxKeyEvent}
+-record(wxScrollWin,{type :: wxScrollWinEventType(), %% Callback event: {@link wxScrollWinEvent}
+ commandInt :: integer(),
+ extraLong :: integer()}).
+-type wxScrollWinEventType() :: 'scrollwin_top' | 'scrollwin_bottom' | 'scrollwin_lineup' | 'scrollwin_linedown' | 'scrollwin_pageup' | 'scrollwin_pagedown' | 'scrollwin_thumbtrack' | 'scrollwin_thumbrelease'.
+-type wxScrollWin() :: #wxScrollWin{}. %% Callback event: {@link wxScrollWinEvent}
+
+-record(wxSetCursor,{type :: wxSetCursorEventType(), %% Callback event: {@link wxSetCursorEvent}
x :: integer(),
y :: integer(),
- keyCode :: integer(),
- controlDown :: boolean(),
- shiftDown :: boolean(),
- altDown :: boolean(),
- metaDown :: boolean(),
- scanCode :: boolean(),
- uniChar :: integer(),
- rawCode :: integer(),
- rawFlags :: integer()}).
--type wxKeyEventType() :: 'char' | 'char_hook' | 'key_down' | 'key_up'.
--type wxKey() :: #wxKey{}. %% Callback event: {@link wxKeyEvent}
+ cursor :: wxCursor:wxCursor()}).
+-type wxSetCursorEventType() :: 'set_cursor'.
+-type wxSetCursor() :: #wxSetCursor{}. %% Callback event: {@link wxSetCursorEvent}
+
+-record(wxShow,{type :: wxShowEventType(), %% Callback event: {@link wxShowEvent}
+ show :: boolean()}).
+-type wxShowEventType() :: 'show'.
+-type wxShow() :: #wxShow{}. %% Callback event: {@link wxShowEvent}
+
+-record(wxSize,{type :: wxSizeEventType(), %% Callback event: {@link wxSizeEvent}
+ size :: {W::integer(), H::integer()},
+ rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}).
+-type wxSizeEventType() :: 'size'.
+-type wxSize() :: #wxSize{}. %% Callback event: {@link wxSizeEvent}
+
+-record(wxSpin,{type :: wxSpinEventType(), %% Callback event: {@link wxSpinEvent}
+ commandInt :: integer()}).
+-type wxSpinEventType() :: 'command_spinctrl_updated' | 'spin_up' | 'spin_down' | 'spin'.
+-type wxSpin() :: #wxSpin{}. %% Callback event: {@link wxSpinEvent}
+
+-record(wxSplitter, {type :: wxSplitterEventType()}). %% Callback event: {@link wxSplitterEvent}
+-type wxSplitterEventType() :: 'command_splitter_sash_pos_changed' | 'command_splitter_sash_pos_changing' | 'command_splitter_doubleclicked' | 'command_splitter_unsplit'.
+-type wxSplitter() :: #wxSplitter{}. %% Callback event: {@link wxSplitterEvent}
+
+-record(wxStyledText,{type :: wxStyledTextEventType(), %% Callback event: {@link wxStyledTextEvent}
+ position :: integer(),
+ key :: integer(),
+ modifiers :: integer(),
+ modificationType :: integer(),
+ text :: unicode:chardata(),
+ length :: integer(),
+ linesAdded :: integer(),
+ line :: integer(),
+ foldLevelNow :: integer(),
+ foldLevelPrev :: integer(),
+ margin :: integer(),
+ message :: integer(),
+ wParam :: integer(),
+ lParam :: integer(),
+ listType :: integer(),
+ x :: integer(),
+ y :: integer(),
+ dragText :: unicode:chardata(),
+ dragAllowMove :: boolean(),
+ dragResult :: wx:wx_enum()}).
+-type wxStyledTextEventType() :: 'stc_change' | 'stc_styleneeded' | 'stc_charadded' | 'stc_savepointreached' | 'stc_savepointleft' | 'stc_romodifyattempt' | 'stc_key' | 'stc_doubleclick' | 'stc_updateui' | 'stc_modified' | 'stc_macrorecord' | 'stc_marginclick' | 'stc_needshown' | 'stc_painted' | 'stc_userlistselection' | 'stc_uridropped' | 'stc_dwellstart' | 'stc_dwellend' | 'stc_start_drag' | 'stc_drag_over' | 'stc_do_drop' | 'stc_zoom' | 'stc_hotspot_click' | 'stc_hotspot_dclick' | 'stc_calltip_click' | 'stc_autocomp_selection'.
+-type wxStyledText() :: #wxStyledText{}. %% Callback event: {@link wxStyledTextEvent}
+
+-record(wxSysColourChanged, {type :: wxSysColourChangedEventType()}). %% Callback event: {@link wxSysColourChangedEvent}
+-type wxSysColourChangedEventType() :: 'sys_colour_changed'.
+-type wxSysColourChanged() :: #wxSysColourChanged{}. %% Callback event: {@link wxSysColourChangedEvent}
-record(wxTaskBarIcon, {type :: wxTaskBarIconEventType()}). %% Callback event: {@link wxTaskBarIconEvent}
-type wxTaskBarIconEventType() :: 'taskbar_move' | 'taskbar_left_down' | 'taskbar_left_up' | 'taskbar_right_down' | 'taskbar_right_up' | 'taskbar_left_dclick' | 'taskbar_right_dclick'.
-type wxTaskBarIcon() :: #wxTaskBarIcon{}. %% Callback event: {@link wxTaskBarIconEvent}
--record(wxGrid,{type :: wxGridEventType(), %% Callback event: {@link wxGridEvent}
- row :: integer(),
- col :: integer(),
- x :: integer(),
- y :: integer(),
- selecting :: boolean(),
- control :: boolean(),
- meta :: boolean(),
- shift :: boolean(),
- alt :: boolean()}).
--type wxGridEventType() :: 'grid_cell_left_click' | 'grid_cell_right_click' | 'grid_cell_left_dclick' | 'grid_cell_right_dclick' | 'grid_label_left_click' | 'grid_label_right_click' | 'grid_label_left_dclick' | 'grid_label_right_dclick' | 'grid_row_size' | 'grid_col_size' | 'grid_range_select' | 'grid_cell_change' | 'grid_select_cell' | 'grid_editor_shown' | 'grid_editor_hidden' | 'grid_editor_created' | 'grid_cell_begin_drag'.
--type wxGrid() :: #wxGrid{}. %% Callback event: {@link wxGridEvent}
+-record(wxTree,{type :: wxTreeEventType(), %% Callback event: {@link wxTreeEvent}
+ item :: integer(),
+ itemOld :: integer(),
+ pointDrag :: {X::integer(), Y::integer()}}).
+-type wxTreeEventType() :: 'command_tree_begin_drag' | 'command_tree_begin_rdrag' | 'command_tree_begin_label_edit' | 'command_tree_end_label_edit' | 'command_tree_delete_item' | 'command_tree_get_info' | 'command_tree_set_info' | 'command_tree_item_expanded' | 'command_tree_item_expanding' | 'command_tree_item_collapsed' | 'command_tree_item_collapsing' | 'command_tree_sel_changed' | 'command_tree_sel_changing' | 'command_tree_key_down' | 'command_tree_item_activated' | 'command_tree_item_right_click' | 'command_tree_item_middle_click' | 'command_tree_end_drag' | 'command_tree_state_image_click' | 'command_tree_item_gettooltip' | 'command_tree_item_menu'.
+-type wxTree() :: #wxTree{}. %% Callback event: {@link wxTreeEvent}
--record(wxCalendar,{type :: wxCalendarEventType(), %% Callback event: {@link wxCalendarEvent}
- wday :: wx:wx_enum(),
- date :: wx:wx_datetime()}).
--type wxCalendarEventType() :: 'calendar_sel_changed' | 'calendar_day_changed' | 'calendar_month_changed' | 'calendar_year_changed' | 'calendar_doubleclicked' | 'calendar_weekday_clicked'.
--type wxCalendar() :: #wxCalendar{}. %% Callback event: {@link wxCalendarEvent}
+-record(wxUpdateUI, {type :: wxUpdateUIEventType()}). %% Callback event: {@link wxUpdateUIEvent}
+-type wxUpdateUIEventType() :: 'update_ui'.
+-type wxUpdateUI() :: #wxUpdateUI{}. %% Callback event: {@link wxUpdateUIEvent}
-record(wxWindowCreate, {type :: wxWindowCreateEventType()}). %% Callback event: {@link wxWindowCreateEvent}
-type wxWindowCreateEventType() :: 'create'.
-type wxWindowCreate() :: #wxWindowCreate{}. %% Callback event: {@link wxWindowCreateEvent}
--record(wxDate,{type :: wxDateEventType(), %% Callback event: {@link wxDateEvent}
- date :: wx:wx_datetime()}).
--type wxDateEventType() :: 'date_changed'.
--type wxDate() :: #wxDate{}. %% Callback event: {@link wxDateEvent}
-
--record(wxAuiManager,{type :: wxAuiManagerEventType(), %% Callback event: {@link wxAuiManagerEvent}
- manager :: wxAuiManager:wxAuiManager(),
- pane :: wxAuiPaneInfo:wxAuiPaneInfo(),
- button :: integer(),
- veto_flag :: boolean(),
- canveto_flag :: boolean(),
- dc :: wxDC:wxDC()}).
--type wxAuiManagerEventType() :: 'aui_pane_button' | 'aui_pane_close' | 'aui_pane_maximize' | 'aui_pane_restore' | 'aui_pane_activated' | 'aui_render' | 'aui_find_manager'.
--type wxAuiManager() :: #wxAuiManager{}. %% Callback event: {@link wxAuiManagerEvent}
-
--record(wxJoystick,{type :: wxJoystickEventType(), %% Callback event: {@link wxJoystickEvent}
- pos :: {X::integer(), Y::integer()},
- zPosition :: integer(),
- buttonChange :: integer(),
- buttonState :: integer(),
- joyStick :: integer()}).
--type wxJoystickEventType() :: 'joy_button_down' | 'joy_button_up' | 'joy_move' | 'joy_zmove'.
--type wxJoystick() :: #wxJoystick{}. %% Callback event: {@link wxJoystickEvent}
-
--record(wxPaint, {type :: wxPaintEventType()}). %% Callback event: {@link wxPaintEvent}
--type wxPaintEventType() :: 'paint'.
--type wxPaint() :: #wxPaint{}. %% Callback event: {@link wxPaintEvent}
-
--record(wxErase,{type :: wxEraseEventType(), %% Callback event: {@link wxEraseEvent}
- dc :: wxDC:wxDC()}).
--type wxEraseEventType() :: 'erase_background'.
--type wxErase() :: #wxErase{}. %% Callback event: {@link wxEraseEvent}
-
--record(wxSetCursor,{type :: wxSetCursorEventType(), %% Callback event: {@link wxSetCursorEvent}
- x :: integer(),
- y :: integer(),
- cursor :: wxCursor:wxCursor()}).
--type wxSetCursorEventType() :: 'set_cursor'.
--type wxSetCursor() :: #wxSetCursor{}. %% Callback event: {@link wxSetCursorEvent}
+-record(wxWindowDestroy, {type :: wxWindowDestroyEventType()}). %% Callback event: {@link wxWindowDestroyEvent}
+-type wxWindowDestroyEventType() :: 'destroy'.
+-type wxWindowDestroy() :: #wxWindowDestroy{}. %% Callback event: {@link wxWindowDestroyEvent}
--type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMouseCaptureLost() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy().
--type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseCaptureLostEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType().
+-type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxDropFiles() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMouseCaptureLost() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy().
+-type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxDropFilesEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseCaptureLostEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType().
%% Hardcoded Records
-record(wxMouseState, {x :: integer(), y :: integer(),
@@ -4085,3 +4092,7 @@
-define(wxWINDOW_VARIANT_MINI, 2).
-define(wxWINDOW_VARIANT_LARGE, 3).
-define(wxWINDOW_VARIANT_MAX, 4).
+% From "xmlres.h": wxXmlResourceFlags
+-define(wxXRC_USE_LOCALE, 1).
+-define(wxXRC_NO_SUBCLASSING, 2).
+-define(wxXRC_NO_RELOADING, 4).
diff --git a/lib/wx/src/gen/gl.erl b/lib/wx/src/gen/gl.erl
index e10b99b10a..4a178ea1e4 100644
--- a/lib/wx/src/gen/gl.erl
+++ b/lib/wx/src/gen/gl.erl
@@ -283,7 +283,7 @@
call(Op, Args) ->
Port = get(opengl_port),
_ = erlang:port_control(Port,Op,Args),
- rec().
+ rec(Op).
%% @hidden
cast(Op, Args) ->
@@ -292,11 +292,15 @@ cast(Op, Args) ->
ok.
%% @hidden
-rec() ->
- receive
+rec(Op) ->
+ receive
{'_egl_result_', Res} -> Res;
- {'_egl_error_', Op, Res} -> error({error,Res,Op})
- end.
+ {'_egl_error_', Op, Res} -> error({error,Res,Op});
+ {'_egl_error_', Other, Res} ->
+ Err = io_lib:format("~p in op: ~p", [Res, Other]),
+ error_logger:error_report([{gl, error}, {message, lists:flatten(Err)}]),
+ rec(Op)
+ end.
%% @hidden
send_bin(Bin) when is_binary(Bin) ->
@@ -2949,8 +2953,9 @@ callList(List) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCallLists.xml">external</a> documentation.
-spec callLists(Lists) -> 'ok' when Lists :: [integer()].
callLists(Lists) ->
- cast(5108, <<(length(Lists)):?GLuint,
- (<< <<C:?GLuint>> || C <- Lists>>)/binary,0:(((1+length(Lists)) rem 2)*32)>>).
+ ListsLen = length(Lists),
+ cast(5108, <<ListsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Lists>>)/binary,0:(((1+ListsLen) rem 2)*32)>>).
%% @doc set the display-list base for
%%
@@ -6945,8 +6950,9 @@ genTextures(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteTextures.xml">external</a> documentation.
-spec deleteTextures(Textures) -> 'ok' when Textures :: [integer()].
deleteTextures(Textures) ->
- cast(5272, <<(length(Textures)):?GLuint,
- (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+length(Textures)) rem 2)*32)>>).
+ TexturesLen = length(Textures),
+ cast(5272, <<TexturesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+TexturesLen) rem 2)*32)>>).
%% @doc Bind a named texture to a texturing target
%%
@@ -7026,9 +7032,11 @@ bindTexture(Target,Texture) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPrioritizeTextures.xml">external</a> documentation.
-spec prioritizeTextures(Textures, Priorities) -> 'ok' when Textures :: [integer()],Priorities :: [clamp()].
prioritizeTextures(Textures,Priorities) ->
- cast(5274, <<(length(Textures)):?GLuint,
- (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+length(Textures)) rem 2)*32),(length(Priorities)):?GLuint,
- (<< <<C:?GLclampf>> || C <- Priorities>>)/binary,0:(((1+length(Priorities)) rem 2)*32)>>).
+ TexturesLen = length(Textures),
+ PrioritiesLen = length(Priorities),
+ cast(5274, <<TexturesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+TexturesLen) rem 2)*32),PrioritiesLen:?GLuint,
+ (<< <<C:?GLclampf>> || C <- Priorities>>)/binary,0:(((1+PrioritiesLen) rem 2)*32)>>).
%% @doc Determine if textures are loaded in texture memory
%%
@@ -7052,8 +7060,9 @@ prioritizeTextures(Textures,Priorities) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glAreTexturesResident.xml">external</a> documentation.
-spec areTexturesResident(Textures) -> {0|1,Residences :: [0|1]} when Textures :: [integer()].
areTexturesResident(Textures) ->
- call(5275, <<(length(Textures)):?GLuint,
- (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+length(Textures)) rem 2)*32)>>).
+ TexturesLen = length(Textures),
+ call(5275, <<TexturesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+TexturesLen) rem 2)*32)>>).
%% @doc Determine if a name corresponds to a texture
%%
@@ -9650,11 +9659,19 @@ blendFuncSeparate(SfactorRGB,DfactorRGB,SfactorAlpha,DfactorAlpha) ->
%%
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultiDrawArrays.xml">external</a> documentation.
--spec multiDrawArrays(Mode, First, Count) -> 'ok' when Mode :: enum(),First :: [integer()],Count :: [integer()].
+-spec multiDrawArrays(Mode, First, Count) -> 'ok' when Mode :: enum(),First :: [integer()]|mem(),Count :: [integer()]|mem().
+multiDrawArrays(Mode,First,Count) when is_list(First), is_list(Count) ->
+ FirstLen = length(First),
+ CountLen = length(Count),
+ cast(5395, <<Mode:?GLenum,FirstLen:?GLuint,
+ (<< <<C:?GLint>> || C <- First>>)/binary,0:(((FirstLen) rem 2)*32),CountLen:?GLuint,
+ (<< <<C:?GLsizei>> || C <- Count>>)/binary,0:(((1+CountLen) rem 2)*32)>>);
multiDrawArrays(Mode,First,Count) ->
- cast(5395, <<Mode:?GLenum,(length(First)):?GLuint,
- (<< <<C:?GLint>> || C <- First>>)/binary,0:(((length(First)) rem 2)*32),(length(Count)):?GLuint,
- (<< <<C:?GLsizei>> || C <- Count>>)/binary,0:(((1+length(Count)) rem 2)*32)>>).
+ send_bin(First),
+ FirstLen = byte_size(if is_binary(First) -> First; is_tuple(First) -> element(2, First) end) div 4,
+ send_bin(Count),
+ CountLen = byte_size(if is_binary(Count) -> Count; is_tuple(Count) -> element(2, Count) end) div 4,
+ cast(5396, <<Mode:?GLenum,FirstLen:?GLint,CountLen:?GLsizei>>).
%% @doc Specify point parameters
%%
@@ -9671,26 +9688,26 @@ multiDrawArrays(Mode,First,Count) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPointParameter.xml">external</a> documentation.
-spec pointParameterf(Pname, Param) -> 'ok' when Pname :: enum(),Param :: float().
pointParameterf(Pname,Param) ->
- cast(5396, <<Pname:?GLenum,Param:?GLfloat>>).
+ cast(5397, <<Pname:?GLenum,Param:?GLfloat>>).
%% @doc
%% See {@link pointParameterf/2}
-spec pointParameterfv(Pname, Params) -> 'ok' when Pname :: enum(),Params :: tuple().
pointParameterfv(Pname,Params) ->
- cast(5397, <<Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5398, <<Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>).
%% @doc
%% See {@link pointParameterf/2}
-spec pointParameteri(Pname, Param) -> 'ok' when Pname :: enum(),Param :: integer().
pointParameteri(Pname,Param) ->
- cast(5398, <<Pname:?GLenum,Param:?GLint>>).
+ cast(5399, <<Pname:?GLenum,Param:?GLint>>).
%% @doc
%% See {@link pointParameterf/2}
-spec pointParameteriv(Pname, Params) -> 'ok' when Pname :: enum(),Params :: tuple().
pointParameteriv(Pname,Params) ->
- cast(5399, <<Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5400, <<Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>).
%% @doc Set the current fog coordinates
@@ -9702,7 +9719,7 @@ pointParameteriv(Pname,Params) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFogCoord.xml">external</a> documentation.
-spec fogCoordf(Coord) -> 'ok' when Coord :: float().
fogCoordf(Coord) ->
- cast(5400, <<Coord:?GLfloat>>).
+ cast(5401, <<Coord:?GLfloat>>).
%% @equiv fogCoordf(Coord)
-spec fogCoordfv(Coord) -> 'ok' when Coord :: {Coord :: float()}.
@@ -9712,7 +9729,7 @@ fogCoordfv({Coord}) -> fogCoordf(Coord).
%% See {@link fogCoordf/1}
-spec fogCoordd(Coord) -> 'ok' when Coord :: float().
fogCoordd(Coord) ->
- cast(5401, <<Coord:?GLdouble>>).
+ cast(5402, <<Coord:?GLdouble>>).
%% @equiv fogCoordd(Coord)
-spec fogCoorddv(Coord) -> 'ok' when Coord :: {Coord :: float()}.
@@ -9743,10 +9760,10 @@ fogCoorddv({Coord}) -> fogCoordd(Coord).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFogCoordPointer.xml">external</a> documentation.
-spec fogCoordPointer(Type, Stride, Pointer) -> 'ok' when Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
fogCoordPointer(Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5402, <<Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5403, <<Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
fogCoordPointer(Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5403, <<Type:?GLenum,Stride:?GLsizei>>).
+ cast(5404, <<Type:?GLenum,Stride:?GLsizei>>).
%% @doc Set the current secondary color
%%
@@ -9780,7 +9797,7 @@ fogCoordPointer(Type,Stride,Pointer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSecondaryColor.xml">external</a> documentation.
-spec secondaryColor3b(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3b(Red,Green,Blue) ->
- cast(5404, <<Red:?GLbyte,Green:?GLbyte,Blue:?GLbyte>>).
+ cast(5405, <<Red:?GLbyte,Green:?GLbyte,Blue:?GLbyte>>).
%% @equiv secondaryColor3b(Red,Green,Blue)
-spec secondaryColor3bv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9790,7 +9807,7 @@ secondaryColor3bv({Red,Green,Blue}) -> secondaryColor3b(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3d(Red, Green, Blue) -> 'ok' when Red :: float(),Green :: float(),Blue :: float().
secondaryColor3d(Red,Green,Blue) ->
- cast(5405, <<Red:?GLdouble,Green:?GLdouble,Blue:?GLdouble>>).
+ cast(5406, <<Red:?GLdouble,Green:?GLdouble,Blue:?GLdouble>>).
%% @equiv secondaryColor3d(Red,Green,Blue)
-spec secondaryColor3dv(V) -> 'ok' when V :: {Red :: float(),Green :: float(),Blue :: float()}.
@@ -9800,7 +9817,7 @@ secondaryColor3dv({Red,Green,Blue}) -> secondaryColor3d(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3f(Red, Green, Blue) -> 'ok' when Red :: float(),Green :: float(),Blue :: float().
secondaryColor3f(Red,Green,Blue) ->
- cast(5406, <<Red:?GLfloat,Green:?GLfloat,Blue:?GLfloat>>).
+ cast(5407, <<Red:?GLfloat,Green:?GLfloat,Blue:?GLfloat>>).
%% @equiv secondaryColor3f(Red,Green,Blue)
-spec secondaryColor3fv(V) -> 'ok' when V :: {Red :: float(),Green :: float(),Blue :: float()}.
@@ -9810,7 +9827,7 @@ secondaryColor3fv({Red,Green,Blue}) -> secondaryColor3f(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3i(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3i(Red,Green,Blue) ->
- cast(5407, <<Red:?GLint,Green:?GLint,Blue:?GLint>>).
+ cast(5408, <<Red:?GLint,Green:?GLint,Blue:?GLint>>).
%% @equiv secondaryColor3i(Red,Green,Blue)
-spec secondaryColor3iv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9820,7 +9837,7 @@ secondaryColor3iv({Red,Green,Blue}) -> secondaryColor3i(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3s(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3s(Red,Green,Blue) ->
- cast(5408, <<Red:?GLshort,Green:?GLshort,Blue:?GLshort>>).
+ cast(5409, <<Red:?GLshort,Green:?GLshort,Blue:?GLshort>>).
%% @equiv secondaryColor3s(Red,Green,Blue)
-spec secondaryColor3sv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9830,7 +9847,7 @@ secondaryColor3sv({Red,Green,Blue}) -> secondaryColor3s(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3ub(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3ub(Red,Green,Blue) ->
- cast(5409, <<Red:?GLubyte,Green:?GLubyte,Blue:?GLubyte>>).
+ cast(5410, <<Red:?GLubyte,Green:?GLubyte,Blue:?GLubyte>>).
%% @equiv secondaryColor3ub(Red,Green,Blue)
-spec secondaryColor3ubv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9840,7 +9857,7 @@ secondaryColor3ubv({Red,Green,Blue}) -> secondaryColor3ub(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3ui(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3ui(Red,Green,Blue) ->
- cast(5410, <<Red:?GLuint,Green:?GLuint,Blue:?GLuint>>).
+ cast(5411, <<Red:?GLuint,Green:?GLuint,Blue:?GLuint>>).
%% @equiv secondaryColor3ui(Red,Green,Blue)
-spec secondaryColor3uiv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9850,7 +9867,7 @@ secondaryColor3uiv({Red,Green,Blue}) -> secondaryColor3ui(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3us(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3us(Red,Green,Blue) ->
- cast(5411, <<Red:?GLushort,Green:?GLushort,Blue:?GLushort>>).
+ cast(5412, <<Red:?GLushort,Green:?GLushort,Blue:?GLushort>>).
%% @equiv secondaryColor3us(Red,Green,Blue)
-spec secondaryColor3usv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9883,10 +9900,10 @@ secondaryColor3usv({Red,Green,Blue}) -> secondaryColor3us(Red,Green,Blue).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSecondaryColorPointer.xml">external</a> documentation.
-spec secondaryColorPointer(Size, Type, Stride, Pointer) -> 'ok' when Size :: integer(),Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
secondaryColorPointer(Size,Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5412, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5413, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
secondaryColorPointer(Size,Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5413, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
+ cast(5414, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
%% @doc Specify the raster position in window coordinates for pixel operations
%%
@@ -9929,7 +9946,7 @@ secondaryColorPointer(Size,Type,Stride,Pointer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWindowPos.xml">external</a> documentation.
-spec windowPos2d(X, Y) -> 'ok' when X :: float(),Y :: float().
windowPos2d(X,Y) ->
- cast(5414, <<X:?GLdouble,Y:?GLdouble>>).
+ cast(5415, <<X:?GLdouble,Y:?GLdouble>>).
%% @equiv windowPos2d(X,Y)
-spec windowPos2dv(V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -9939,7 +9956,7 @@ windowPos2dv({X,Y}) -> windowPos2d(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos2f(X, Y) -> 'ok' when X :: float(),Y :: float().
windowPos2f(X,Y) ->
- cast(5415, <<X:?GLfloat,Y:?GLfloat>>).
+ cast(5416, <<X:?GLfloat,Y:?GLfloat>>).
%% @equiv windowPos2f(X,Y)
-spec windowPos2fv(V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -9949,7 +9966,7 @@ windowPos2fv({X,Y}) -> windowPos2f(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos2i(X, Y) -> 'ok' when X :: integer(),Y :: integer().
windowPos2i(X,Y) ->
- cast(5416, <<X:?GLint,Y:?GLint>>).
+ cast(5417, <<X:?GLint,Y:?GLint>>).
%% @equiv windowPos2i(X,Y)
-spec windowPos2iv(V) -> 'ok' when V :: {X :: integer(),Y :: integer()}.
@@ -9959,7 +9976,7 @@ windowPos2iv({X,Y}) -> windowPos2i(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos2s(X, Y) -> 'ok' when X :: integer(),Y :: integer().
windowPos2s(X,Y) ->
- cast(5417, <<X:?GLshort,Y:?GLshort>>).
+ cast(5418, <<X:?GLshort,Y:?GLshort>>).
%% @equiv windowPos2s(X,Y)
-spec windowPos2sv(V) -> 'ok' when V :: {X :: integer(),Y :: integer()}.
@@ -9969,7 +9986,7 @@ windowPos2sv({X,Y}) -> windowPos2s(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos3d(X, Y, Z) -> 'ok' when X :: float(),Y :: float(),Z :: float().
windowPos3d(X,Y,Z) ->
- cast(5418, <<X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5419, <<X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @equiv windowPos3d(X,Y,Z)
-spec windowPos3dv(V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -9979,7 +9996,7 @@ windowPos3dv({X,Y,Z}) -> windowPos3d(X,Y,Z).
%% See {@link windowPos2d/2}
-spec windowPos3f(X, Y, Z) -> 'ok' when X :: float(),Y :: float(),Z :: float().
windowPos3f(X,Y,Z) ->
- cast(5419, <<X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
+ cast(5420, <<X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
%% @equiv windowPos3f(X,Y,Z)
-spec windowPos3fv(V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -9989,7 +10006,7 @@ windowPos3fv({X,Y,Z}) -> windowPos3f(X,Y,Z).
%% See {@link windowPos2d/2}
-spec windowPos3i(X, Y, Z) -> 'ok' when X :: integer(),Y :: integer(),Z :: integer().
windowPos3i(X,Y,Z) ->
- cast(5420, <<X:?GLint,Y:?GLint,Z:?GLint>>).
+ cast(5421, <<X:?GLint,Y:?GLint,Z:?GLint>>).
%% @equiv windowPos3i(X,Y,Z)
-spec windowPos3iv(V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer()}.
@@ -9999,7 +10016,7 @@ windowPos3iv({X,Y,Z}) -> windowPos3i(X,Y,Z).
%% See {@link windowPos2d/2}
-spec windowPos3s(X, Y, Z) -> 'ok' when X :: integer(),Y :: integer(),Z :: integer().
windowPos3s(X,Y,Z) ->
- cast(5421, <<X:?GLshort,Y:?GLshort,Z:?GLshort>>).
+ cast(5422, <<X:?GLshort,Y:?GLshort,Z:?GLshort>>).
%% @equiv windowPos3s(X,Y,Z)
-spec windowPos3sv(V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer()}.
@@ -10020,7 +10037,7 @@ windowPos3sv({X,Y,Z}) -> windowPos3s(X,Y,Z).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenQueries.xml">external</a> documentation.
-spec genQueries(N) -> [integer()] when N :: integer().
genQueries(N) ->
- call(5422, <<N:?GLsizei>>).
+ call(5423, <<N:?GLsizei>>).
%% @doc Delete named query objects
%%
@@ -10034,8 +10051,9 @@ genQueries(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteQueries.xml">external</a> documentation.
-spec deleteQueries(Ids) -> 'ok' when Ids :: [integer()].
deleteQueries(Ids) ->
- cast(5423, <<(length(Ids)):?GLuint,
- (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+length(Ids)) rem 2)*32)>>).
+ IdsLen = length(Ids),
+ cast(5424, <<IdsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+IdsLen) rem 2)*32)>>).
%% @doc Determine if a name corresponds to a query object
%%
@@ -10049,7 +10067,7 @@ deleteQueries(Ids) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsQuery.xml">external</a> documentation.
-spec isQuery(Id) -> 0|1 when Id :: integer().
isQuery(Id) ->
- call(5424, <<Id:?GLuint>>).
+ call(5425, <<Id:?GLuint>>).
%% @doc Delimit the boundaries of a query object
%%
@@ -10116,20 +10134,20 @@ isQuery(Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginQuery.xml">external</a> documentation.
-spec beginQuery(Target, Id) -> 'ok' when Target :: enum(),Id :: integer().
beginQuery(Target,Id) ->
- cast(5425, <<Target:?GLenum,Id:?GLuint>>).
+ cast(5426, <<Target:?GLenum,Id:?GLuint>>).
%% @doc
%% See {@link beginQuery/2}
-spec endQuery(Target) -> 'ok' when Target :: enum().
endQuery(Target) ->
- cast(5426, <<Target:?GLenum>>).
+ cast(5427, <<Target:?GLenum>>).
%% @doc glGetQuery
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQuery.xml">external</a> documentation.
-spec getQueryiv(Target, Pname) -> integer() when Target :: enum(),Pname :: enum().
getQueryiv(Target,Pname) ->
- call(5427, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5428, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Return parameters of a query object
%%
@@ -10149,13 +10167,13 @@ getQueryiv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryObject.xml">external</a> documentation.
-spec getQueryObjectiv(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjectiv(Id,Pname) ->
- call(5428, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5429, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getQueryObjectiv/2}
-spec getQueryObjectuiv(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjectuiv(Id,Pname) ->
- call(5429, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5430, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc Bind a named buffer object
%%
@@ -10238,7 +10256,7 @@ getQueryObjectuiv(Id,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindBuffer.xml">external</a> documentation.
-spec bindBuffer(Target, Buffer) -> 'ok' when Target :: enum(),Buffer :: integer().
bindBuffer(Target,Buffer) ->
- cast(5430, <<Target:?GLenum,Buffer:?GLuint>>).
+ cast(5431, <<Target:?GLenum,Buffer:?GLuint>>).
%% @doc Delete named buffer objects
%%
@@ -10253,8 +10271,9 @@ bindBuffer(Target,Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteBuffers.xml">external</a> documentation.
-spec deleteBuffers(Buffers) -> 'ok' when Buffers :: [integer()].
deleteBuffers(Buffers) ->
- cast(5431, <<(length(Buffers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Buffers>>)/binary,0:(((1+length(Buffers)) rem 2)*32)>>).
+ BuffersLen = length(Buffers),
+ cast(5432, <<BuffersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Buffers>>)/binary,0:(((1+BuffersLen) rem 2)*32)>>).
%% @doc Generate buffer object names
%%
@@ -10272,7 +10291,7 @@ deleteBuffers(Buffers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenBuffers.xml">external</a> documentation.
-spec genBuffers(N) -> [integer()] when N :: integer().
genBuffers(N) ->
- call(5432, <<N:?GLsizei>>).
+ call(5433, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a buffer object
%%
@@ -10287,7 +10306,7 @@ genBuffers(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsBuffer.xml">external</a> documentation.
-spec isBuffer(Buffer) -> 0|1 when Buffer :: integer().
isBuffer(Buffer) ->
- call(5433, <<Buffer:?GLuint>>).
+ call(5434, <<Buffer:?GLuint>>).
%% @doc Creates and initializes a buffer object's data store
%%
@@ -10325,10 +10344,10 @@ isBuffer(Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml">external</a> documentation.
-spec bufferData(Target, Size, Data, Usage) -> 'ok' when Target :: enum(),Size :: integer(),Data :: offset()|mem(),Usage :: enum().
bufferData(Target,Size,Data,Usage) when is_integer(Data) ->
- cast(5434, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Data:?GLuint,Usage:?GLenum>>);
+ cast(5435, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Data:?GLuint,Usage:?GLenum>>);
bufferData(Target,Size,Data,Usage) ->
send_bin(Data),
- cast(5435, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Usage:?GLenum>>).
+ cast(5436, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Usage:?GLenum>>).
%% @doc Updates a subset of a buffer object's data store
%%
@@ -10341,10 +10360,10 @@ bufferData(Target,Size,Data,Usage) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBufferSubData.xml">external</a> documentation.
-spec bufferSubData(Target, Offset, Size, Data) -> 'ok' when Target :: enum(),Offset :: integer(),Size :: integer(),Data :: offset()|mem().
bufferSubData(Target,Offset,Size,Data) when is_integer(Data) ->
- cast(5436, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr,Data:?GLuint>>);
+ cast(5437, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr,Data:?GLuint>>);
bufferSubData(Target,Offset,Size,Data) ->
send_bin(Data),
- cast(5437, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
+ cast(5438, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Returns a subset of a buffer object's data store
%%
@@ -10358,7 +10377,7 @@ bufferSubData(Target,Offset,Size,Data) ->
-spec getBufferSubData(Target, Offset, Size, Data) -> 'ok' when Target :: enum(),Offset :: integer(),Size :: integer(),Data :: mem().
getBufferSubData(Target,Offset,Size,Data) ->
send_bin(Data),
- call(5438, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
+ call(5439, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Return parameters of a buffer object
%%
@@ -10382,7 +10401,7 @@ getBufferSubData(Target,Offset,Size,Data) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetBufferParameteriv.xml">external</a> documentation.
-spec getBufferParameteriv(Target, Pname) -> integer() when Target :: enum(),Pname :: enum().
getBufferParameteriv(Target,Pname) ->
- call(5439, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5440, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Set the RGB blend equation and the alpha blend equation separately
%%
@@ -10424,7 +10443,7 @@ getBufferParameteriv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBlendEquationSeparate.xml">external</a> documentation.
-spec blendEquationSeparate(ModeRGB, ModeAlpha) -> 'ok' when ModeRGB :: enum(),ModeAlpha :: enum().
blendEquationSeparate(ModeRGB,ModeAlpha) ->
- cast(5440, <<ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
+ cast(5441, <<ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
%% @doc Specifies a list of color buffers to be drawn into
%%
@@ -10464,8 +10483,9 @@ blendEquationSeparate(ModeRGB,ModeAlpha) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawBuffers.xml">external</a> documentation.
-spec drawBuffers(Bufs) -> 'ok' when Bufs :: [enum()].
drawBuffers(Bufs) ->
- cast(5441, <<(length(Bufs)):?GLuint,
- (<< <<C:?GLenum>> || C <- Bufs>>)/binary,0:(((1+length(Bufs)) rem 2)*32)>>).
+ BufsLen = length(Bufs),
+ cast(5442, <<BufsLen:?GLuint,
+ (<< <<C:?GLenum>> || C <- Bufs>>)/binary,0:(((1+BufsLen) rem 2)*32)>>).
%% @doc Set front and/or back stencil test actions
%%
@@ -10526,7 +10546,7 @@ drawBuffers(Bufs) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilOpSeparate.xml">external</a> documentation.
-spec stencilOpSeparate(Face, Sfail, Dpfail, Dppass) -> 'ok' when Face :: enum(),Sfail :: enum(),Dpfail :: enum(),Dppass :: enum().
stencilOpSeparate(Face,Sfail,Dpfail,Dppass) ->
- cast(5442, <<Face:?GLenum,Sfail:?GLenum,Dpfail:?GLenum,Dppass:?GLenum>>).
+ cast(5443, <<Face:?GLenum,Sfail:?GLenum,Dpfail:?GLenum,Dppass:?GLenum>>).
%% @doc Set front and/or back function and reference value for stencil testing
%%
@@ -10589,7 +10609,7 @@ stencilOpSeparate(Face,Sfail,Dpfail,Dppass) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilFuncSeparate.xml">external</a> documentation.
-spec stencilFuncSeparate(Face, Func, Ref, Mask) -> 'ok' when Face :: enum(),Func :: enum(),Ref :: integer(),Mask :: integer().
stencilFuncSeparate(Face,Func,Ref,Mask) ->
- cast(5443, <<Face:?GLenum,Func:?GLenum,Ref:?GLint,Mask:?GLuint>>).
+ cast(5444, <<Face:?GLenum,Func:?GLenum,Ref:?GLint,Mask:?GLuint>>).
%% @doc Control the front and/or back writing of individual bits in the stencil planes
%%
@@ -10607,7 +10627,7 @@ stencilFuncSeparate(Face,Func,Ref,Mask) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilMaskSeparate.xml">external</a> documentation.
-spec stencilMaskSeparate(Face, Mask) -> 'ok' when Face :: enum(),Mask :: integer().
stencilMaskSeparate(Face,Mask) ->
- cast(5444, <<Face:?GLenum,Mask:?GLuint>>).
+ cast(5445, <<Face:?GLenum,Mask:?GLuint>>).
%% @doc Attaches a shader object to a program object
%%
@@ -10631,7 +10651,7 @@ stencilMaskSeparate(Face,Mask) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glAttachShader.xml">external</a> documentation.
-spec attachShader(Program, Shader) -> 'ok' when Program :: integer(),Shader :: integer().
attachShader(Program,Shader) ->
- cast(5445, <<Program:?GLuint,Shader:?GLuint>>).
+ cast(5446, <<Program:?GLuint,Shader:?GLuint>>).
%% @doc Associates a generic vertex attribute index with a named attribute variable
%%
@@ -10668,7 +10688,8 @@ attachShader(Program,Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindAttribLocation.xml">external</a> documentation.
-spec bindAttribLocation(Program, Index, Name) -> 'ok' when Program :: integer(),Index :: integer(),Name :: string().
bindAttribLocation(Program,Index,Name) ->
- cast(5446, <<Program:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5447, <<Program:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Compiles a shader object
%%
@@ -10688,7 +10709,7 @@ bindAttribLocation(Program,Index,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShader.xml">external</a> documentation.
-spec compileShader(Shader) -> 'ok' when Shader :: integer().
compileShader(Shader) ->
- cast(5447, <<Shader:?GLuint>>).
+ cast(5448, <<Shader:?GLuint>>).
%% @doc Creates a program object
%%
@@ -10711,7 +10732,7 @@ compileShader(Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateProgram.xml">external</a> documentation.
-spec createProgram() -> integer().
createProgram() ->
- call(5448, <<>>).
+ call(5449, <<>>).
%% @doc Creates a shader object
%%
@@ -10734,7 +10755,7 @@ createProgram() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShader.xml">external</a> documentation.
-spec createShader(Type) -> integer() when Type :: enum().
createShader(Type) ->
- call(5449, <<Type:?GLenum>>).
+ call(5450, <<Type:?GLenum>>).
%% @doc Deletes a program object
%%
@@ -10755,7 +10776,7 @@ createShader(Type) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteProgram.xml">external</a> documentation.
-spec deleteProgram(Program) -> 'ok' when Program :: integer().
deleteProgram(Program) ->
- cast(5450, <<Program:?GLuint>>).
+ cast(5451, <<Program:?GLuint>>).
%% @doc Deletes a shader object
%%
@@ -10774,7 +10795,7 @@ deleteProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteShader.xml">external</a> documentation.
-spec deleteShader(Shader) -> 'ok' when Shader :: integer().
deleteShader(Shader) ->
- cast(5451, <<Shader:?GLuint>>).
+ cast(5452, <<Shader:?GLuint>>).
%% @doc Detaches a shader object from a program object to which it is attached
%%
@@ -10789,7 +10810,7 @@ deleteShader(Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDetachShader.xml">external</a> documentation.
-spec detachShader(Program, Shader) -> 'ok' when Program :: integer(),Shader :: integer().
detachShader(Program,Shader) ->
- cast(5452, <<Program:?GLuint,Shader:?GLuint>>).
+ cast(5453, <<Program:?GLuint,Shader:?GLuint>>).
%% @doc Enable or disable a generic vertex attribute array
%%
@@ -10804,13 +10825,13 @@ detachShader(Program,Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEnableVertexAttribArray.xml">external</a> documentation.
-spec disableVertexAttribArray(Index) -> 'ok' when Index :: integer().
disableVertexAttribArray(Index) ->
- cast(5453, <<Index:?GLuint>>).
+ cast(5454, <<Index:?GLuint>>).
%% @doc
%% See {@link disableVertexAttribArray/1}
-spec enableVertexAttribArray(Index) -> 'ok' when Index :: integer().
enableVertexAttribArray(Index) ->
- cast(5454, <<Index:?GLuint>>).
+ cast(5455, <<Index:?GLuint>>).
%% @doc Returns information about an active attribute variable for the specified program object
%%
@@ -10868,7 +10889,7 @@ enableVertexAttribArray(Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveAttrib.xml">external</a> documentation.
-spec getActiveAttrib(Program, Index, BufSize) -> {Size :: integer(),Type :: enum(),Name :: string()} when Program :: integer(),Index :: integer(),BufSize :: integer().
getActiveAttrib(Program,Index,BufSize) ->
- call(5455, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
+ call(5456, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns information about an active uniform variable for the specified program object
%%
@@ -11015,7 +11036,7 @@ getActiveAttrib(Program,Index,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml">external</a> documentation.
-spec getActiveUniform(Program, Index, BufSize) -> {Size :: integer(),Type :: enum(),Name :: string()} when Program :: integer(),Index :: integer(),BufSize :: integer().
getActiveUniform(Program,Index,BufSize) ->
- call(5456, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
+ call(5457, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns the handles of the shader objects attached to a program object
%%
@@ -11035,7 +11056,7 @@ getActiveUniform(Program,Index,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttachedShaders.xml">external</a> documentation.
-spec getAttachedShaders(Program, MaxCount) -> [integer()] when Program :: integer(),MaxCount :: integer().
getAttachedShaders(Program,MaxCount) ->
- call(5457, <<Program:?GLuint,MaxCount:?GLsizei>>).
+ call(5458, <<Program:?GLuint,MaxCount:?GLsizei>>).
%% @doc Returns the location of an attribute variable
%%
@@ -11059,7 +11080,8 @@ getAttachedShaders(Program,MaxCount) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttribLocation.xml">external</a> documentation.
-spec getAttribLocation(Program, Name) -> integer() when Program :: integer(),Name :: string().
getAttribLocation(Program,Name) ->
- call(5458, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5459, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Returns a parameter from a program object
%%
@@ -11130,7 +11152,7 @@ getAttribLocation(Program,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgram.xml">external</a> documentation.
-spec getProgramiv(Program, Pname) -> integer() when Program :: integer(),Pname :: enum().
getProgramiv(Program,Pname) ->
- call(5459, <<Program:?GLuint,Pname:?GLenum>>).
+ call(5460, <<Program:?GLuint,Pname:?GLenum>>).
%% @doc Returns the information log for a program object
%%
@@ -11155,7 +11177,7 @@ getProgramiv(Program,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramInfoLog.xml">external</a> documentation.
-spec getProgramInfoLog(Program, BufSize) -> string() when Program :: integer(),BufSize :: integer().
getProgramInfoLog(Program,BufSize) ->
- call(5460, <<Program:?GLuint,BufSize:?GLsizei>>).
+ call(5461, <<Program:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns a parameter from a shader object
%%
@@ -11186,7 +11208,7 @@ getProgramInfoLog(Program,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShader.xml">external</a> documentation.
-spec getShaderiv(Shader, Pname) -> integer() when Shader :: integer(),Pname :: enum().
getShaderiv(Shader,Pname) ->
- call(5461, <<Shader:?GLuint,Pname:?GLenum>>).
+ call(5462, <<Shader:?GLuint,Pname:?GLenum>>).
%% @doc Returns the information log for a shader object
%%
@@ -11209,7 +11231,7 @@ getShaderiv(Shader,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderInfoLog.xml">external</a> documentation.
-spec getShaderInfoLog(Shader, BufSize) -> string() when Shader :: integer(),BufSize :: integer().
getShaderInfoLog(Shader,BufSize) ->
- call(5462, <<Shader:?GLuint,BufSize:?GLsizei>>).
+ call(5463, <<Shader:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns the source code string from a shader object
%%
@@ -11229,7 +11251,7 @@ getShaderInfoLog(Shader,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderSource.xml">external</a> documentation.
-spec getShaderSource(Shader, BufSize) -> string() when Shader :: integer(),BufSize :: integer().
getShaderSource(Shader,BufSize) ->
- call(5463, <<Shader:?GLuint,BufSize:?GLsizei>>).
+ call(5464, <<Shader:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns the location of a uniform variable
%%
@@ -11262,7 +11284,8 @@ getShaderSource(Shader,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocation.xml">external</a> documentation.
-spec getUniformLocation(Program, Name) -> integer() when Program :: integer(),Name :: string().
getUniformLocation(Program,Name) ->
- call(5464, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5465, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Returns the value of a uniform variable
%%
@@ -11288,13 +11311,13 @@ getUniformLocation(Program,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniform.xml">external</a> documentation.
-spec getUniformfv(Program, Location) -> matrix() when Program :: integer(),Location :: integer().
getUniformfv(Program,Location) ->
- call(5465, <<Program:?GLuint,Location:?GLint>>).
+ call(5466, <<Program:?GLuint,Location:?GLint>>).
%% @doc
%% See {@link getUniformfv/2}
-spec getUniformiv(Program, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when Program :: integer(),Location :: integer().
getUniformiv(Program,Location) ->
- call(5466, <<Program:?GLuint,Location:?GLint>>).
+ call(5467, <<Program:?GLuint,Location:?GLint>>).
%% @doc Return a generic vertex attribute parameter
%%
@@ -11361,19 +11384,19 @@ getUniformiv(Program,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetVertexAttrib.xml">external</a> documentation.
-spec getVertexAttribdv(Index, Pname) -> {float(),float(),float(),float()} when Index :: integer(),Pname :: enum().
getVertexAttribdv(Index,Pname) ->
- call(5467, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5468, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getVertexAttribdv/2}
-spec getVertexAttribfv(Index, Pname) -> {float(),float(),float(),float()} when Index :: integer(),Pname :: enum().
getVertexAttribfv(Index,Pname) ->
- call(5468, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5469, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getVertexAttribdv/2}
-spec getVertexAttribiv(Index, Pname) -> {integer(),integer(),integer(),integer()} when Index :: integer(),Pname :: enum().
getVertexAttribiv(Index,Pname) ->
- call(5469, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5470, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc Determines if a name corresponds to a program object
%%
@@ -11385,7 +11408,7 @@ getVertexAttribiv(Index,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsProgram.xml">external</a> documentation.
-spec isProgram(Program) -> 0|1 when Program :: integer().
isProgram(Program) ->
- call(5470, <<Program:?GLuint>>).
+ call(5471, <<Program:?GLuint>>).
%% @doc Determines if a name corresponds to a shader object
%%
@@ -11397,7 +11420,7 @@ isProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsShader.xml">external</a> documentation.
-spec isShader(Shader) -> 0|1 when Shader :: integer().
isShader(Shader) ->
- call(5471, <<Shader:?GLuint>>).
+ call(5472, <<Shader:?GLuint>>).
%% @doc Links a program object
%%
@@ -11517,7 +11540,7 @@ isShader(Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLinkProgram.xml">external</a> documentation.
-spec linkProgram(Program) -> 'ok' when Program :: integer().
linkProgram(Program) ->
- cast(5472, <<Program:?GLuint>>).
+ cast(5473, <<Program:?GLuint>>).
%% @doc Replaces the source code in a shader object
%%
@@ -11535,8 +11558,9 @@ linkProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderSource.xml">external</a> documentation.
-spec shaderSource(Shader, String) -> 'ok' when Shader :: integer(),String :: iolist().
shaderSource(Shader,String) ->
- StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
- cast(5473, <<Shader:?GLuint,(length(String)):?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+0) rem 8)) rem 8)>>).
+ StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
+ StringLen = length(String),
+ cast(5474, <<Shader:?GLuint,StringLen:?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+0) rem 8)) rem 8)>>).
%% @doc Installs a program object as part of current rendering state
%%
@@ -11577,7 +11601,7 @@ shaderSource(Shader,String) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUseProgram.xml">external</a> documentation.
-spec useProgram(Program) -> 'ok' when Program :: integer().
useProgram(Program) ->
- cast(5474, <<Program:?GLuint>>).
+ cast(5475, <<Program:?GLuint>>).
%% @doc Specify the value of a uniform variable for the current program object
%%
@@ -11645,125 +11669,136 @@ useProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml">external</a> documentation.
-spec uniform1f(Location, V0) -> 'ok' when Location :: integer(),V0 :: float().
uniform1f(Location,V0) ->
- cast(5475, <<Location:?GLint,V0:?GLfloat>>).
+ cast(5476, <<Location:?GLint,V0:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2f(Location, V0, V1) -> 'ok' when Location :: integer(),V0 :: float(),V1 :: float().
uniform2f(Location,V0,V1) ->
- cast(5476, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
+ cast(5477, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3f(Location, V0, V1, V2) -> 'ok' when Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float().
uniform3f(Location,V0,V1,V2) ->
- cast(5477, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
+ cast(5478, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4f(Location, V0, V1, V2, V3) -> 'ok' when Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float(),V3 :: float().
uniform4f(Location,V0,V1,V2,V3) ->
- cast(5478, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
+ cast(5479, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1i(Location, V0) -> 'ok' when Location :: integer(),V0 :: integer().
uniform1i(Location,V0) ->
- cast(5479, <<Location:?GLint,V0:?GLint>>).
+ cast(5480, <<Location:?GLint,V0:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2i(Location, V0, V1) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer().
uniform2i(Location,V0,V1) ->
- cast(5480, <<Location:?GLint,V0:?GLint,V1:?GLint>>).
+ cast(5481, <<Location:?GLint,V0:?GLint,V1:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3i(Location, V0, V1, V2) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
uniform3i(Location,V0,V1,V2) ->
- cast(5481, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
+ cast(5482, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4i(Location, V0, V1, V2, V3) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
uniform4i(Location,V0,V1,V2,V3) ->
- cast(5482, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
+ cast(5483, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [float()].
uniform1fv(Location,Value) ->
- cast(5483, <<Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5484, <<Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float()}].
uniform2fv(Location,Value) ->
- cast(5484, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5485, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float()}].
uniform3fv(Location,Value) ->
- cast(5485, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5486, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float(),float()}].
uniform4fv(Location,Value) ->
- cast(5486, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5487, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [integer()].
uniform1iv(Location,Value) ->
- cast(5487, <<Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5488, <<Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer()}].
uniform2iv(Location,Value) ->
- cast(5488, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5489, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer()}].
uniform3iv(Location,Value) ->
- cast(5489, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5490, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
uniform4iv(Location,Value) ->
- cast(5490, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5491, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
uniformMatrix2fv(Location,Transpose,Value) ->
- cast(5491, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5492, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3fv(Location,Transpose,Value) ->
- cast(5492, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5493, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4fv(Location,Transpose,Value) ->
- cast(5493, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5494, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat,V13:?GLfloat,V14:?GLfloat,V15:?GLfloat,V16:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc Validates a program object
@@ -11791,7 +11826,7 @@ uniformMatrix4fv(Location,Transpose,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgram.xml">external</a> documentation.
-spec validateProgram(Program) -> 'ok' when Program :: integer().
validateProgram(Program) ->
- cast(5494, <<Program:?GLuint>>).
+ cast(5495, <<Program:?GLuint>>).
%% @doc Specifies the value of a generic vertex attribute
%%
@@ -11866,7 +11901,7 @@ validateProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttrib.xml">external</a> documentation.
-spec vertexAttrib1d(Index, X) -> 'ok' when Index :: integer(),X :: float().
vertexAttrib1d(Index,X) ->
- cast(5495, <<Index:?GLuint,0:32,X:?GLdouble>>).
+ cast(5496, <<Index:?GLuint,0:32,X:?GLdouble>>).
%% @equiv vertexAttrib1d(Index,X)
-spec vertexAttrib1dv(Index :: integer(),V) -> 'ok' when V :: {X :: float()}.
@@ -11876,7 +11911,7 @@ vertexAttrib1dv(Index,{X}) -> vertexAttrib1d(Index,X).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib1f(Index, X) -> 'ok' when Index :: integer(),X :: float().
vertexAttrib1f(Index,X) ->
- cast(5496, <<Index:?GLuint,X:?GLfloat>>).
+ cast(5497, <<Index:?GLuint,X:?GLfloat>>).
%% @equiv vertexAttrib1f(Index,X)
-spec vertexAttrib1fv(Index :: integer(),V) -> 'ok' when V :: {X :: float()}.
@@ -11886,7 +11921,7 @@ vertexAttrib1fv(Index,{X}) -> vertexAttrib1f(Index,X).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib1s(Index, X) -> 'ok' when Index :: integer(),X :: integer().
vertexAttrib1s(Index,X) ->
- cast(5497, <<Index:?GLuint,X:?GLshort>>).
+ cast(5498, <<Index:?GLuint,X:?GLshort>>).
%% @equiv vertexAttrib1s(Index,X)
-spec vertexAttrib1sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer()}.
@@ -11896,7 +11931,7 @@ vertexAttrib1sv(Index,{X}) -> vertexAttrib1s(Index,X).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib2d(Index, X, Y) -> 'ok' when Index :: integer(),X :: float(),Y :: float().
vertexAttrib2d(Index,X,Y) ->
- cast(5498, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
+ cast(5499, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
%% @equiv vertexAttrib2d(Index,X,Y)
-spec vertexAttrib2dv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -11906,7 +11941,7 @@ vertexAttrib2dv(Index,{X,Y}) -> vertexAttrib2d(Index,X,Y).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib2f(Index, X, Y) -> 'ok' when Index :: integer(),X :: float(),Y :: float().
vertexAttrib2f(Index,X,Y) ->
- cast(5499, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat>>).
+ cast(5500, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat>>).
%% @equiv vertexAttrib2f(Index,X,Y)
-spec vertexAttrib2fv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -11916,7 +11951,7 @@ vertexAttrib2fv(Index,{X,Y}) -> vertexAttrib2f(Index,X,Y).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib2s(Index, X, Y) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer().
vertexAttrib2s(Index,X,Y) ->
- cast(5500, <<Index:?GLuint,X:?GLshort,Y:?GLshort>>).
+ cast(5501, <<Index:?GLuint,X:?GLshort,Y:?GLshort>>).
%% @equiv vertexAttrib2s(Index,X,Y)
-spec vertexAttrib2sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer()}.
@@ -11926,7 +11961,7 @@ vertexAttrib2sv(Index,{X,Y}) -> vertexAttrib2s(Index,X,Y).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib3d(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float().
vertexAttrib3d(Index,X,Y,Z) ->
- cast(5501, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5502, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @equiv vertexAttrib3d(Index,X,Y,Z)
-spec vertexAttrib3dv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -11936,7 +11971,7 @@ vertexAttrib3dv(Index,{X,Y,Z}) -> vertexAttrib3d(Index,X,Y,Z).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib3f(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float().
vertexAttrib3f(Index,X,Y,Z) ->
- cast(5502, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
+ cast(5503, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
%% @equiv vertexAttrib3f(Index,X,Y,Z)
-spec vertexAttrib3fv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -11946,7 +11981,7 @@ vertexAttrib3fv(Index,{X,Y,Z}) -> vertexAttrib3f(Index,X,Y,Z).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib3s(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer().
vertexAttrib3s(Index,X,Y,Z) ->
- cast(5503, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort>>).
+ cast(5504, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort>>).
%% @equiv vertexAttrib3s(Index,X,Y,Z)
-spec vertexAttrib3sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer()}.
@@ -11956,25 +11991,25 @@ vertexAttrib3sv(Index,{X,Y,Z}) -> vertexAttrib3s(Index,X,Y,Z).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nbv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nbv(Index,{V1,V2,V3,V4}) ->
- cast(5504, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
+ cast(5505, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Niv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Niv(Index,{V1,V2,V3,V4}) ->
- cast(5505, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
+ cast(5506, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nsv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nsv(Index,{V1,V2,V3,V4}) ->
- cast(5506, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
+ cast(5507, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nub(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttrib4Nub(Index,X,Y,Z,W) ->
- cast(5507, <<Index:?GLuint,X:?GLubyte,Y:?GLubyte,Z:?GLubyte,W:?GLubyte>>).
+ cast(5508, <<Index:?GLuint,X:?GLubyte,Y:?GLubyte,Z:?GLubyte,W:?GLubyte>>).
%% @equiv vertexAttrib4Nub(Index,X,Y,Z,W)
-spec vertexAttrib4Nubv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer(),W :: integer()}.
@@ -11984,25 +12019,25 @@ vertexAttrib4Nubv(Index,{X,Y,Z,W}) -> vertexAttrib4Nub(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nuiv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nuiv(Index,{V1,V2,V3,V4}) ->
- cast(5508, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
+ cast(5509, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nusv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nusv(Index,{V1,V2,V3,V4}) ->
- cast(5509, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
+ cast(5510, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4bv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4bv(Index,{V1,V2,V3,V4}) ->
- cast(5510, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
+ cast(5511, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4d(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
vertexAttrib4d(Index,X,Y,Z,W) ->
- cast(5511, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5512, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @equiv vertexAttrib4d(Index,X,Y,Z,W)
-spec vertexAttrib4dv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float(),W :: float()}.
@@ -12012,7 +12047,7 @@ vertexAttrib4dv(Index,{X,Y,Z,W}) -> vertexAttrib4d(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4f(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
vertexAttrib4f(Index,X,Y,Z,W) ->
- cast(5512, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
+ cast(5513, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
%% @equiv vertexAttrib4f(Index,X,Y,Z,W)
-spec vertexAttrib4fv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float(),W :: float()}.
@@ -12022,13 +12057,13 @@ vertexAttrib4fv(Index,{X,Y,Z,W}) -> vertexAttrib4f(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4iv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4iv(Index,{V1,V2,V3,V4}) ->
- cast(5513, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
+ cast(5514, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4s(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttrib4s(Index,X,Y,Z,W) ->
- cast(5514, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort,W:?GLshort>>).
+ cast(5515, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort,W:?GLshort>>).
%% @equiv vertexAttrib4s(Index,X,Y,Z,W)
-spec vertexAttrib4sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer(),W :: integer()}.
@@ -12038,19 +12073,19 @@ vertexAttrib4sv(Index,{X,Y,Z,W}) -> vertexAttrib4s(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4ubv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4ubv(Index,{V1,V2,V3,V4}) ->
- cast(5515, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
+ cast(5516, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4uiv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4uiv(Index,{V1,V2,V3,V4}) ->
- cast(5516, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
+ cast(5517, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4usv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4usv(Index,{V1,V2,V3,V4}) ->
- cast(5517, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
+ cast(5518, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
%% @doc Define an array of generic vertex attribute data
%%
@@ -12094,51 +12129,57 @@ vertexAttrib4usv(Index,{V1,V2,V3,V4}) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml">external</a> documentation.
-spec vertexAttribPointer(Index, Size, Type, Normalized, Stride, Pointer) -> 'ok' when Index :: integer(),Size :: integer(),Type :: enum(),Normalized :: 0|1,Stride :: integer(),Pointer :: offset()|mem().
vertexAttribPointer(Index,Size,Type,Normalized,Stride,Pointer) when is_integer(Pointer) ->
- cast(5518, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5519, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei,Pointer:?GLuint>>);
vertexAttribPointer(Index,Size,Type,Normalized,Stride,Pointer) ->
send_bin(Pointer),
- cast(5519, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei>>).
+ cast(5520, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x3fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix2x3fv(Location,Transpose,Value) ->
- cast(5520, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5521, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x2fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix3x2fv(Location,Transpose,Value) ->
- cast(5521, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5522, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x4fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix2x4fv(Location,Transpose,Value) ->
- cast(5522, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5523, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x2fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x2fv(Location,Transpose,Value) ->
- cast(5523, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5524, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x4fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3x4fv(Location,Transpose,Value) ->
- cast(5524, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5525, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x3fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x3fv(Location,Transpose,Value) ->
- cast(5525, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5526, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc glColorMaski
@@ -12146,39 +12187,39 @@ uniformMatrix4x3fv(Location,Transpose,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glColorMaski.xml">external</a> documentation.
-spec colorMaski(Index, R, G, B, A) -> 'ok' when Index :: integer(),R :: 0|1,G :: 0|1,B :: 0|1,A :: 0|1.
colorMaski(Index,R,G,B,A) ->
- cast(5526, <<Index:?GLuint,R:?GLboolean,G:?GLboolean,B:?GLboolean,A:?GLboolean>>).
+ cast(5527, <<Index:?GLuint,R:?GLboolean,G:?GLboolean,B:?GLboolean,A:?GLboolean>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getBooleani_v(Target, Index) -> [0|1] when Target :: enum(),Index :: integer().
getBooleani_v(Target,Index) ->
- call(5527, <<Target:?GLenum,Index:?GLuint>>).
+ call(5528, <<Target:?GLenum,Index:?GLuint>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getIntegeri_v(Target, Index) -> [integer()] when Target :: enum(),Index :: integer().
getIntegeri_v(Target,Index) ->
- call(5528, <<Target:?GLenum,Index:?GLuint>>).
+ call(5529, <<Target:?GLenum,Index:?GLuint>>).
%% @doc
%% See {@link enable/1}
-spec enablei(Target, Index) -> 'ok' when Target :: enum(),Index :: integer().
enablei(Target,Index) ->
- cast(5529, <<Target:?GLenum,Index:?GLuint>>).
+ cast(5530, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glEnablei
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEnablei.xml">external</a> documentation.
-spec disablei(Target, Index) -> 'ok' when Target :: enum(),Index :: integer().
disablei(Target,Index) ->
- cast(5530, <<Target:?GLenum,Index:?GLuint>>).
+ cast(5531, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glIsEnabledi
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsEnabledi.xml">external</a> documentation.
-spec isEnabledi(Target, Index) -> 0|1 when Target :: enum(),Index :: integer().
isEnabledi(Target,Index) ->
- call(5531, <<Target:?GLenum,Index:?GLuint>>).
+ call(5532, <<Target:?GLenum,Index:?GLuint>>).
%% @doc Start transform feedback operation
%%
@@ -12206,13 +12247,13 @@ isEnabledi(Target,Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginTransformFeedback.xml">external</a> documentation.
-spec beginTransformFeedback(PrimitiveMode) -> 'ok' when PrimitiveMode :: enum().
beginTransformFeedback(PrimitiveMode) ->
- cast(5532, <<PrimitiveMode:?GLenum>>).
+ cast(5533, <<PrimitiveMode:?GLenum>>).
%% @doc
%% See {@link beginTransformFeedback/1}
-spec endTransformFeedback() -> 'ok'.
endTransformFeedback() ->
- cast(5533, <<>>).
+ cast(5534, <<>>).
%% @doc Bind a range within a buffer object to an indexed buffer target
%%
@@ -12231,7 +12272,7 @@ endTransformFeedback() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindBufferRange.xml">external</a> documentation.
-spec bindBufferRange(Target, Index, Buffer, Offset, Size) -> 'ok' when Target :: enum(),Index :: integer(),Buffer :: integer(),Offset :: integer(),Size :: integer().
bindBufferRange(Target,Index,Buffer,Offset,Size) ->
- cast(5534, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
+ cast(5535, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Bind a buffer object to an indexed buffer target
%%
@@ -12246,7 +12287,7 @@ bindBufferRange(Target,Index,Buffer,Offset,Size) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindBufferBase.xml">external</a> documentation.
-spec bindBufferBase(Target, Index, Buffer) -> 'ok' when Target :: enum(),Index :: integer(),Buffer :: integer().
bindBufferBase(Target,Index,Buffer) ->
- cast(5535, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint>>).
+ cast(5536, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint>>).
%% @doc Specify values to record in transform feedback buffers
%%
@@ -12284,8 +12325,9 @@ bindBufferBase(Target,Index,Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTransformFeedbackVaryings.xml">external</a> documentation.
-spec transformFeedbackVaryings(Program, Varyings, BufferMode) -> 'ok' when Program :: integer(),Varyings :: iolist(),BufferMode :: enum().
transformFeedbackVaryings(Program,Varyings,BufferMode) ->
- VaryingsTemp = list_to_binary([[Str|[0]] || Str <- Varyings ]),
- cast(5536, <<Program:?GLuint,(length(Varyings)):?GLuint,(size(VaryingsTemp)):?GLuint,(VaryingsTemp)/binary,0:((8-((size(VaryingsTemp)+0) rem 8)) rem 8),BufferMode:?GLenum>>).
+ VaryingsTemp = list_to_binary([[Str|[0]] || Str <- Varyings ]),
+ VaryingsLen = length(Varyings),
+ cast(5537, <<Program:?GLuint,VaryingsLen:?GLuint,(size(VaryingsTemp)):?GLuint,(VaryingsTemp)/binary,0:((8-((size(VaryingsTemp)+0) rem 8)) rem 8),BufferMode:?GLenum>>).
%% @doc Retrieve information about varying variables selected for transform feedback
%%
@@ -12318,7 +12360,7 @@ transformFeedbackVaryings(Program,Varyings,BufferMode) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetTransformFeedbackVarying.xml">external</a> documentation.
-spec getTransformFeedbackVarying(Program, Index, BufSize) -> {Size :: integer(),Type :: enum(),Name :: string()} when Program :: integer(),Index :: integer(),BufSize :: integer().
getTransformFeedbackVarying(Program,Index,BufSize) ->
- call(5537, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
+ call(5538, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
%% @doc specify whether data read via
%%
@@ -12333,7 +12375,7 @@ getTransformFeedbackVarying(Program,Index,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClampColor.xml">external</a> documentation.
-spec clampColor(Target, Clamp) -> 'ok' when Target :: enum(),Clamp :: enum().
clampColor(Target,Clamp) ->
- cast(5538, <<Target:?GLenum,Clamp:?GLenum>>).
+ cast(5539, <<Target:?GLenum,Clamp:?GLenum>>).
%% @doc Start conditional rendering
%%
@@ -12365,84 +12407,84 @@ clampColor(Target,Clamp) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginConditionalRender.xml">external</a> documentation.
-spec beginConditionalRender(Id, Mode) -> 'ok' when Id :: integer(),Mode :: enum().
beginConditionalRender(Id,Mode) ->
- cast(5539, <<Id:?GLuint,Mode:?GLenum>>).
+ cast(5540, <<Id:?GLuint,Mode:?GLenum>>).
%% @doc
%% See {@link beginConditionalRender/2}
-spec endConditionalRender() -> 'ok'.
endConditionalRender() ->
- cast(5540, <<>>).
+ cast(5541, <<>>).
%% @doc glVertexAttribIPointer
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribIPointer.xml">external</a> documentation.
-spec vertexAttribIPointer(Index, Size, Type, Stride, Pointer) -> 'ok' when Index :: integer(),Size :: integer(),Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
vertexAttribIPointer(Index,Size,Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5541, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5542, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
vertexAttribIPointer(Index,Size,Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5542, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
+ cast(5543, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
%% @doc
%% See {@link getVertexAttribdv/2}
-spec getVertexAttribIiv(Index, Pname) -> {integer(),integer(),integer(),integer()} when Index :: integer(),Pname :: enum().
getVertexAttribIiv(Index,Pname) ->
- call(5543, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5544, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc glGetVertexAttribI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetVertexAttribI.xml">external</a> documentation.
-spec getVertexAttribIuiv(Index, Pname) -> {integer(),integer(),integer(),integer()} when Index :: integer(),Pname :: enum().
getVertexAttribIuiv(Index,Pname) ->
- call(5544, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5545, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI1i(Index, X) -> 'ok' when Index :: integer(),X :: integer().
vertexAttribI1i(Index,X) ->
- cast(5545, <<Index:?GLuint,X:?GLint>>).
+ cast(5546, <<Index:?GLuint,X:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI2i(Index, X, Y) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer().
vertexAttribI2i(Index,X,Y) ->
- cast(5546, <<Index:?GLuint,X:?GLint,Y:?GLint>>).
+ cast(5547, <<Index:?GLuint,X:?GLint,Y:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI3i(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer().
vertexAttribI3i(Index,X,Y,Z) ->
- cast(5547, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint>>).
+ cast(5548, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4i(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttribI4i(Index,X,Y,Z,W) ->
- cast(5548, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint,W:?GLint>>).
+ cast(5549, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint,W:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI1ui(Index, X) -> 'ok' when Index :: integer(),X :: integer().
vertexAttribI1ui(Index,X) ->
- cast(5549, <<Index:?GLuint,X:?GLuint>>).
+ cast(5550, <<Index:?GLuint,X:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI2ui(Index, X, Y) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer().
vertexAttribI2ui(Index,X,Y) ->
- cast(5550, <<Index:?GLuint,X:?GLuint,Y:?GLuint>>).
+ cast(5551, <<Index:?GLuint,X:?GLuint,Y:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI3ui(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer().
vertexAttribI3ui(Index,X,Y,Z) ->
- cast(5551, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint>>).
+ cast(5552, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4ui(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttribI4ui(Index,X,Y,Z,W) ->
- cast(5552, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint,W:?GLuint>>).
+ cast(5553, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint,W:?GLuint>>).
%% @equiv vertexAttribI1i(Index,X)
-spec vertexAttribI1iv(Index :: integer(),V) -> 'ok' when V :: {X :: integer()}.
@@ -12480,31 +12522,31 @@ vertexAttribI4uiv(Index,{X,Y,Z,W}) -> vertexAttribI4ui(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4bv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4bv(Index,{V1,V2,V3,V4}) ->
- cast(5553, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
+ cast(5554, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4sv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4sv(Index,{V1,V2,V3,V4}) ->
- cast(5554, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
+ cast(5555, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4ubv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4ubv(Index,{V1,V2,V3,V4}) ->
- cast(5555, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
+ cast(5556, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4usv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4usv(Index,{V1,V2,V3,V4}) ->
- cast(5556, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
+ cast(5557, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
%% @doc
%% See {@link getUniformfv/2}
-spec getUniformuiv(Program, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when Program :: integer(),Location :: integer().
getUniformuiv(Program,Location) ->
- call(5557, <<Program:?GLuint,Location:?GLint>>).
+ call(5558, <<Program:?GLuint,Location:?GLint>>).
%% @doc Bind a user-defined varying out variable to a fragment shader color number
%%
@@ -12531,7 +12573,8 @@ getUniformuiv(Program,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindFragDataLocation.xml">external</a> documentation.
-spec bindFragDataLocation(Program, Color, Name) -> 'ok' when Program :: integer(),Color :: integer(),Name :: string().
bindFragDataLocation(Program,Color,Name) ->
- cast(5558, <<Program:?GLuint,Color:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5559, <<Program:?GLuint,Color:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Query the bindings of color numbers to user-defined varying out variables
%%
@@ -12544,65 +12587,70 @@ bindFragDataLocation(Program,Color,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetFragDataLocation.xml">external</a> documentation.
-spec getFragDataLocation(Program, Name) -> integer() when Program :: integer(),Name :: string().
getFragDataLocation(Program,Name) ->
- call(5559, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5560, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1ui(Location, V0) -> 'ok' when Location :: integer(),V0 :: integer().
uniform1ui(Location,V0) ->
- cast(5560, <<Location:?GLint,V0:?GLuint>>).
+ cast(5561, <<Location:?GLint,V0:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2ui(Location, V0, V1) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer().
uniform2ui(Location,V0,V1) ->
- cast(5561, <<Location:?GLint,V0:?GLuint,V1:?GLuint>>).
+ cast(5562, <<Location:?GLint,V0:?GLuint,V1:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3ui(Location, V0, V1, V2) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
uniform3ui(Location,V0,V1,V2) ->
- cast(5562, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
+ cast(5563, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4ui(Location, V0, V1, V2, V3) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
uniform4ui(Location,V0,V1,V2,V3) ->
- cast(5563, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
+ cast(5564, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [integer()].
uniform1uiv(Location,Value) ->
- cast(5564, <<Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5565, <<Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer()}].
uniform2uiv(Location,Value) ->
- cast(5565, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5566, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer()}].
uniform3uiv(Location,Value) ->
- cast(5566, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5567, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
uniform4uiv(Location,Value) ->
- cast(5567, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5568, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link texParameterf/3}
-spec texParameterIiv(Target, Pname, Params) -> 'ok' when Target :: enum(),Pname :: enum(),Params :: tuple().
texParameterIiv(Target,Pname,Params) ->
- cast(5568, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5569, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>).
%% @doc glTexParameterI
@@ -12610,21 +12658,21 @@ texParameterIiv(Target,Pname,Params) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexParameterI.xml">external</a> documentation.
-spec texParameterIuiv(Target, Pname, Params) -> 'ok' when Target :: enum(),Pname :: enum(),Params :: tuple().
texParameterIuiv(Target,Pname,Params) ->
- cast(5569, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5570, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLuint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>).
%% @doc
%% See {@link getTexParameterfv/2}
-spec getTexParameterIiv(Target, Pname) -> {integer(),integer(),integer(),integer()} when Target :: enum(),Pname :: enum().
getTexParameterIiv(Target,Pname) ->
- call(5570, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5571, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc glGetTexParameterI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetTexParameterI.xml">external</a> documentation.
-spec getTexParameterIuiv(Target, Pname) -> {integer(),integer(),integer(),integer()} when Target :: enum(),Pname :: enum().
getTexParameterIuiv(Target,Pname) ->
- call(5571, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5572, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Clear individual buffers of the currently bound draw framebuffer
%%
@@ -12657,21 +12705,21 @@ getTexParameterIuiv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearBuffer.xml">external</a> documentation.
-spec clearBufferiv(Buffer, Drawbuffer, Value) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple().
clearBufferiv(Buffer,Drawbuffer,Value) ->
- cast(5572, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
+ cast(5573, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
(<< <<C:?GLint>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>).
%% @doc
%% See {@link clearBufferiv/3}
-spec clearBufferuiv(Buffer, Drawbuffer, Value) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple().
clearBufferuiv(Buffer,Drawbuffer,Value) ->
- cast(5573, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
+ cast(5574, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
(<< <<C:?GLuint>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>).
%% @doc
%% See {@link clearBufferiv/3}
-spec clearBufferfv(Buffer, Drawbuffer, Value) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple().
clearBufferfv(Buffer,Drawbuffer,Value) ->
- cast(5574, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
+ cast(5575, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
(<< <<C:?GLfloat>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>).
%% @doc glClearBufferfi
@@ -12679,30 +12727,30 @@ clearBufferfv(Buffer,Drawbuffer,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearBufferfi.xml">external</a> documentation.
-spec clearBufferfi(Buffer, Drawbuffer, Depth, Stencil) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Depth :: float(),Stencil :: integer().
clearBufferfi(Buffer,Drawbuffer,Depth,Stencil) ->
- cast(5575, <<Buffer:?GLenum,Drawbuffer:?GLint,Depth:?GLfloat,Stencil:?GLint>>).
+ cast(5576, <<Buffer:?GLenum,Drawbuffer:?GLint,Depth:?GLfloat,Stencil:?GLint>>).
%% @doc
%% See {@link getString/1}
-spec getStringi(Name, Index) -> string() when Name :: enum(),Index :: integer().
getStringi(Name,Index) ->
- call(5576, <<Name:?GLenum,Index:?GLuint>>).
+ call(5577, <<Name:?GLenum,Index:?GLuint>>).
%% @doc glDrawArraysInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawArraysInstance.xml">external</a> documentation.
-spec drawArraysInstanced(Mode, First, Count, Primcount) -> 'ok' when Mode :: enum(),First :: integer(),Count :: integer(),Primcount :: integer().
drawArraysInstanced(Mode,First,Count,Primcount) ->
- cast(5577, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei>>).
+ cast(5578, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei>>).
%% @doc glDrawElementsInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstance.xml">external</a> documentation.
-spec drawElementsInstanced(Mode, Count, Type, Indices, Primcount) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer().
drawElementsInstanced(Mode,Count,Type,Indices,Primcount) when is_integer(Indices) ->
- cast(5578, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei>>);
+ cast(5579, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei>>);
drawElementsInstanced(Mode,Count,Type,Indices,Primcount) ->
send_bin(Indices),
- cast(5579, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei>>).
+ cast(5580, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei>>).
%% @doc Attach the storage for a buffer object to the active buffer texture
%%
@@ -12770,7 +12818,7 @@ drawElementsInstanced(Mode,Count,Type,Indices,Primcount) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexBuffer.xml">external</a> documentation.
-spec texBuffer(Target, Internalformat, Buffer) -> 'ok' when Target :: enum(),Internalformat :: enum(),Buffer :: integer().
texBuffer(Target,Internalformat,Buffer) ->
- cast(5580, <<Target:?GLenum,Internalformat:?GLenum,Buffer:?GLuint>>).
+ cast(5581, <<Target:?GLenum,Internalformat:?GLenum,Buffer:?GLuint>>).
%% @doc Specify the primitive restart index
%%
@@ -12792,20 +12840,20 @@ texBuffer(Target,Internalformat,Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPrimitiveRestartIndex.xml">external</a> documentation.
-spec primitiveRestartIndex(Index) -> 'ok' when Index :: integer().
primitiveRestartIndex(Index) ->
- cast(5581, <<Index:?GLuint>>).
+ cast(5582, <<Index:?GLuint>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getInteger64i_v(Target, Index) -> [integer()] when Target :: enum(),Index :: integer().
getInteger64i_v(Target,Index) ->
- call(5582, <<Target:?GLenum,Index:?GLuint>>).
+ call(5583, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetBufferParameteri64v
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetBufferParameteri64v.xml">external</a> documentation.
-spec getBufferParameteri64v(Target, Pname) -> [integer()] when Target :: enum(),Pname :: enum().
getBufferParameteri64v(Target,Pname) ->
- call(5583, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5584, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Attach a level of a texture object as a logical buffer to the currently bound framebuffer object
%%
@@ -12862,7 +12910,7 @@ getBufferParameteri64v(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFramebufferTexture.xml">external</a> documentation.
-spec framebufferTexture(Target, Attachment, Texture, Level) -> 'ok' when Target :: enum(),Attachment :: enum(),Texture :: integer(),Level :: integer().
framebufferTexture(Target,Attachment,Texture,Level) ->
- cast(5584, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint>>).
+ cast(5585, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint>>).
%% @doc Modify the rate at which generic vertex attributes advance during instanced rendering
%%
@@ -12878,7 +12926,7 @@ framebufferTexture(Target,Attachment,Texture,Level) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribDivisor.xml">external</a> documentation.
-spec vertexAttribDivisor(Index, Divisor) -> 'ok' when Index :: integer(),Divisor :: integer().
vertexAttribDivisor(Index,Divisor) ->
- cast(5585, <<Index:?GLuint,Divisor:?GLuint>>).
+ cast(5586, <<Index:?GLuint,Divisor:?GLuint>>).
%% @doc Specifies minimum rate at which sample shaing takes place
%%
@@ -12899,107 +12947,112 @@ vertexAttribDivisor(Index,Divisor) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMinSampleShading.xml">external</a> documentation.
-spec minSampleShading(Value) -> 'ok' when Value :: clamp().
minSampleShading(Value) ->
- cast(5586, <<Value:?GLclampf>>).
+ cast(5587, <<Value:?GLclampf>>).
%% @doc
%% See {@link blendEquation/1}
-spec blendEquationi(Buf, Mode) -> 'ok' when Buf :: integer(),Mode :: enum().
blendEquationi(Buf,Mode) ->
- cast(5587, <<Buf:?GLuint,Mode:?GLenum>>).
+ cast(5588, <<Buf:?GLuint,Mode:?GLenum>>).
%% @doc
%% See {@link blendEquationSeparate/2}
-spec blendEquationSeparatei(Buf, ModeRGB, ModeAlpha) -> 'ok' when Buf :: integer(),ModeRGB :: enum(),ModeAlpha :: enum().
blendEquationSeparatei(Buf,ModeRGB,ModeAlpha) ->
- cast(5588, <<Buf:?GLuint,ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
+ cast(5589, <<Buf:?GLuint,ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
%% @doc glBlendFunci
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBlendFunci.xml">external</a> documentation.
-spec blendFunci(Buf, Src, Dst) -> 'ok' when Buf :: integer(),Src :: enum(),Dst :: enum().
blendFunci(Buf,Src,Dst) ->
- cast(5589, <<Buf:?GLuint,Src:?GLenum,Dst:?GLenum>>).
+ cast(5590, <<Buf:?GLuint,Src:?GLenum,Dst:?GLenum>>).
%% @doc
%% See {@link blendFuncSeparate/4}
-spec blendFuncSeparatei(Buf, SrcRGB, DstRGB, SrcAlpha, DstAlpha) -> 'ok' when Buf :: integer(),SrcRGB :: enum(),DstRGB :: enum(),SrcAlpha :: enum(),DstAlpha :: enum().
blendFuncSeparatei(Buf,SrcRGB,DstRGB,SrcAlpha,DstAlpha) ->
- cast(5590, <<Buf:?GLuint,SrcRGB:?GLenum,DstRGB:?GLenum,SrcAlpha:?GLenum,DstAlpha:?GLenum>>).
+ cast(5591, <<Buf:?GLuint,SrcRGB:?GLenum,DstRGB:?GLenum,SrcAlpha:?GLenum,DstAlpha:?GLenum>>).
%% @doc glLoadTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLoadTransposeMatrixARB.xml">external</a> documentation.
-spec loadTransposeMatrixfARB(M) -> 'ok' when M :: matrix().
loadTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5591, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
+ cast(5592, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
loadTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5591, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
+ cast(5592, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
%% @doc glLoadTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLoadTransposeMatrixARB.xml">external</a> documentation.
-spec loadTransposeMatrixdARB(M) -> 'ok' when M :: matrix().
loadTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5592, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
+ cast(5593, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
loadTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5592, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
+ cast(5593, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
%% @doc glMultTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultTransposeMatrixARB.xml">external</a> documentation.
-spec multTransposeMatrixfARB(M) -> 'ok' when M :: matrix().
multTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5593, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
+ cast(5594, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
multTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5593, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
+ cast(5594, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
%% @doc glMultTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultTransposeMatrixARB.xml">external</a> documentation.
-spec multTransposeMatrixdARB(M) -> 'ok' when M :: matrix().
multTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5594, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
+ cast(5595, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
multTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5594, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
+ cast(5595, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightbvARB(Weights) -> 'ok' when Weights :: [integer()].
weightbvARB(Weights) ->
- cast(5595, <<(length(Weights)):?GLuint,
- (<< <<C:?GLbyte>> || C <- Weights>>)/binary,0:((8-((length(Weights)+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5596, <<WeightsLen:?GLuint,
+ (<< <<C:?GLbyte>> || C <- Weights>>)/binary,0:((8-((WeightsLen+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightsvARB(Weights) -> 'ok' when Weights :: [integer()].
weightsvARB(Weights) ->
- cast(5596, <<(length(Weights)):?GLuint,
- (<< <<C:?GLshort>> || C <- Weights>>)/binary,0:((8-((length(Weights)*2+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5597, <<WeightsLen:?GLuint,
+ (<< <<C:?GLshort>> || C <- Weights>>)/binary,0:((8-((WeightsLen*2+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightivARB(Weights) -> 'ok' when Weights :: [integer()].
weightivARB(Weights) ->
- cast(5597, <<(length(Weights)):?GLuint,
- (<< <<C:?GLint>> || C <- Weights>>)/binary,0:(((1+length(Weights)) rem 2)*32)>>).
+ WeightsLen = length(Weights),
+ cast(5598, <<WeightsLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Weights>>)/binary,0:(((1+WeightsLen) rem 2)*32)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightfvARB(Weights) -> 'ok' when Weights :: [float()].
weightfvARB(Weights) ->
- cast(5598, <<(length(Weights)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Weights>>)/binary,0:(((1+length(Weights)) rem 2)*32)>>).
+ WeightsLen = length(Weights),
+ cast(5599, <<WeightsLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Weights>>)/binary,0:(((1+WeightsLen) rem 2)*32)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightdvARB(Weights) -> 'ok' when Weights :: [float()].
weightdvARB(Weights) ->
- cast(5599, <<(length(Weights)):?GLuint,0:32,
+ WeightsLen = length(Weights),
+ cast(5600, <<WeightsLen:?GLuint,0:32,
(<< <<C:?GLdouble>> || C <- Weights>>)/binary>>).
%% @doc glWeightARB
@@ -13007,175 +13060,183 @@ weightdvARB(Weights) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightubvARB(Weights) -> 'ok' when Weights :: [integer()].
weightubvARB(Weights) ->
- cast(5600, <<(length(Weights)):?GLuint,
- (<< <<C:?GLubyte>> || C <- Weights>>)/binary,0:((8-((length(Weights)+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5601, <<WeightsLen:?GLuint,
+ (<< <<C:?GLubyte>> || C <- Weights>>)/binary,0:((8-((WeightsLen+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightusvARB(Weights) -> 'ok' when Weights :: [integer()].
weightusvARB(Weights) ->
- cast(5601, <<(length(Weights)):?GLuint,
- (<< <<C:?GLushort>> || C <- Weights>>)/binary,0:((8-((length(Weights)*2+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5602, <<WeightsLen:?GLuint,
+ (<< <<C:?GLushort>> || C <- Weights>>)/binary,0:((8-((WeightsLen*2+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightuivARB(Weights) -> 'ok' when Weights :: [integer()].
weightuivARB(Weights) ->
- cast(5602, <<(length(Weights)):?GLuint,
- (<< <<C:?GLuint>> || C <- Weights>>)/binary,0:(((1+length(Weights)) rem 2)*32)>>).
+ WeightsLen = length(Weights),
+ cast(5603, <<WeightsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Weights>>)/binary,0:(((1+WeightsLen) rem 2)*32)>>).
%% @doc glVertexBlenARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexBlenARB.xml">external</a> documentation.
-spec vertexBlendARB(Count) -> 'ok' when Count :: integer().
vertexBlendARB(Count) ->
- cast(5603, <<Count:?GLint>>).
+ cast(5604, <<Count:?GLint>>).
%% @doc glCurrentPaletteMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCurrentPaletteMatrixARB.xml">external</a> documentation.
-spec currentPaletteMatrixARB(Index) -> 'ok' when Index :: integer().
currentPaletteMatrixARB(Index) ->
- cast(5604, <<Index:?GLint>>).
+ cast(5605, <<Index:?GLint>>).
%% @doc glMatrixIndexARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMatrixIndexARB.xml">external</a> documentation.
-spec matrixIndexubvARB(Indices) -> 'ok' when Indices :: [integer()].
matrixIndexubvARB(Indices) ->
- cast(5605, <<(length(Indices)):?GLuint,
- (<< <<C:?GLubyte>> || C <- Indices>>)/binary,0:((8-((length(Indices)+ 4) rem 8)) rem 8)>>).
+ IndicesLen = length(Indices),
+ cast(5606, <<IndicesLen:?GLuint,
+ (<< <<C:?GLubyte>> || C <- Indices>>)/binary,0:((8-((IndicesLen+ 4) rem 8)) rem 8)>>).
%% @doc glMatrixIndexARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMatrixIndexARB.xml">external</a> documentation.
-spec matrixIndexusvARB(Indices) -> 'ok' when Indices :: [integer()].
matrixIndexusvARB(Indices) ->
- cast(5606, <<(length(Indices)):?GLuint,
- (<< <<C:?GLushort>> || C <- Indices>>)/binary,0:((8-((length(Indices)*2+ 4) rem 8)) rem 8)>>).
+ IndicesLen = length(Indices),
+ cast(5607, <<IndicesLen:?GLuint,
+ (<< <<C:?GLushort>> || C <- Indices>>)/binary,0:((8-((IndicesLen*2+ 4) rem 8)) rem 8)>>).
%% @doc glMatrixIndexARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMatrixIndexARB.xml">external</a> documentation.
-spec matrixIndexuivARB(Indices) -> 'ok' when Indices :: [integer()].
matrixIndexuivARB(Indices) ->
- cast(5607, <<(length(Indices)):?GLuint,
- (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((1+length(Indices)) rem 2)*32)>>).
+ IndicesLen = length(Indices),
+ cast(5608, <<IndicesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((1+IndicesLen) rem 2)*32)>>).
%% @doc glProgramStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramStringARB.xml">external</a> documentation.
-spec programStringARB(Target, Format, String) -> 'ok' when Target :: enum(),Format :: enum(),String :: string().
programStringARB(Target,Format,String) ->
- cast(5608, <<Target:?GLenum,Format:?GLenum,(list_to_binary([String|[0]]))/binary,0:((8-((length(String)+ 1) rem 8)) rem 8)>>).
+ StringLen = length(String),
+ cast(5609, <<Target:?GLenum,Format:?GLenum,(list_to_binary([String|[0]]))/binary,0:((8-((StringLen+ 1) rem 8)) rem 8)>>).
%% @doc glBindProgramARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindProgramARB.xml">external</a> documentation.
-spec bindProgramARB(Target, Program) -> 'ok' when Target :: enum(),Program :: integer().
bindProgramARB(Target,Program) ->
- cast(5609, <<Target:?GLenum,Program:?GLuint>>).
+ cast(5610, <<Target:?GLenum,Program:?GLuint>>).
%% @doc glDeleteProgramsARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteProgramsARB.xml">external</a> documentation.
-spec deleteProgramsARB(Programs) -> 'ok' when Programs :: [integer()].
deleteProgramsARB(Programs) ->
- cast(5610, <<(length(Programs)):?GLuint,
- (<< <<C:?GLuint>> || C <- Programs>>)/binary,0:(((1+length(Programs)) rem 2)*32)>>).
+ ProgramsLen = length(Programs),
+ cast(5611, <<ProgramsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Programs>>)/binary,0:(((1+ProgramsLen) rem 2)*32)>>).
%% @doc glGenProgramsARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenProgramsARB.xml">external</a> documentation.
-spec genProgramsARB(N) -> [integer()] when N :: integer().
genProgramsARB(N) ->
- call(5611, <<N:?GLsizei>>).
+ call(5612, <<N:?GLsizei>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4dARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programEnvParameter4dARB(Target,Index,X,Y,Z,W) ->
- cast(5612, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5613, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4dvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programEnvParameter4dvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5613, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
+ cast(5614, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4fARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programEnvParameter4fARB(Target,Index,X,Y,Z,W) ->
- cast(5614, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
+ cast(5615, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4fvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programEnvParameter4fvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5615, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
+ cast(5616, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4dARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programLocalParameter4dARB(Target,Index,X,Y,Z,W) ->
- cast(5616, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5617, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4dvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programLocalParameter4dvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5617, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
+ cast(5618, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4fARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programLocalParameter4fARB(Target,Index,X,Y,Z,W) ->
- cast(5618, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
+ cast(5619, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4fvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programLocalParameter4fvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5619, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
+ cast(5620, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
%% @doc glGetProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramEnvParameterARB.xml">external</a> documentation.
-spec getProgramEnvParameterdvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramEnvParameterdvARB(Target,Index) ->
- call(5620, <<Target:?GLenum,Index:?GLuint>>).
+ call(5621, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramEnvParameterARB.xml">external</a> documentation.
-spec getProgramEnvParameterfvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramEnvParameterfvARB(Target,Index) ->
- call(5621, <<Target:?GLenum,Index:?GLuint>>).
+ call(5622, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramLocalParameterARB.xml">external</a> documentation.
-spec getProgramLocalParameterdvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramLocalParameterdvARB(Target,Index) ->
- call(5622, <<Target:?GLenum,Index:?GLuint>>).
+ call(5623, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramLocalParameterARB.xml">external</a> documentation.
-spec getProgramLocalParameterfvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramLocalParameterfvARB(Target,Index) ->
- call(5623, <<Target:?GLenum,Index:?GLuint>>).
+ call(5624, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramStringARB
%%
@@ -13183,176 +13244,180 @@ getProgramLocalParameterfvARB(Target,Index) ->
-spec getProgramStringARB(Target, Pname, String) -> 'ok' when Target :: enum(),Pname :: enum(),String :: mem().
getProgramStringARB(Target,Pname,String) ->
send_bin(String),
- call(5624, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5625, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc glGetBufferParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetBufferParameterARB.xml">external</a> documentation.
-spec getBufferParameterivARB(Target, Pname) -> [integer()] when Target :: enum(),Pname :: enum().
getBufferParameterivARB(Target,Pname) ->
- call(5625, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5626, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc glDeleteObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteObjectARB.xml">external</a> documentation.
-spec deleteObjectARB(Obj) -> 'ok' when Obj :: integer().
deleteObjectARB(Obj) ->
- cast(5626, <<Obj:?GLhandleARB>>).
+ cast(5627, <<Obj:?GLhandleARB>>).
%% @doc glGetHandleARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetHandleARB.xml">external</a> documentation.
-spec getHandleARB(Pname) -> integer() when Pname :: enum().
getHandleARB(Pname) ->
- call(5627, <<Pname:?GLenum>>).
+ call(5628, <<Pname:?GLenum>>).
%% @doc glDetachObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDetachObjectARB.xml">external</a> documentation.
-spec detachObjectARB(ContainerObj, AttachedObj) -> 'ok' when ContainerObj :: integer(),AttachedObj :: integer().
detachObjectARB(ContainerObj,AttachedObj) ->
- cast(5628, <<ContainerObj:?GLhandleARB,AttachedObj:?GLhandleARB>>).
+ cast(5629, <<ContainerObj:?GLhandleARB,AttachedObj:?GLhandleARB>>).
%% @doc glCreateShaderObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShaderObjectARB.xml">external</a> documentation.
-spec createShaderObjectARB(ShaderType) -> integer() when ShaderType :: enum().
createShaderObjectARB(ShaderType) ->
- call(5629, <<ShaderType:?GLenum>>).
+ call(5630, <<ShaderType:?GLenum>>).
%% @doc glShaderSourceARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderSourceARB.xml">external</a> documentation.
-spec shaderSourceARB(ShaderObj, String) -> 'ok' when ShaderObj :: integer(),String :: iolist().
shaderSourceARB(ShaderObj,String) ->
- StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
- cast(5630, <<ShaderObj:?GLhandleARB,(length(String)):?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+4) rem 8)) rem 8)>>).
+ StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
+ StringLen = length(String),
+ cast(5631, <<ShaderObj:?GLhandleARB,StringLen:?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+4) rem 8)) rem 8)>>).
%% @doc glCompileShaderARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShaderARB.xml">external</a> documentation.
-spec compileShaderARB(ShaderObj) -> 'ok' when ShaderObj :: integer().
compileShaderARB(ShaderObj) ->
- cast(5631, <<ShaderObj:?GLhandleARB>>).
+ cast(5632, <<ShaderObj:?GLhandleARB>>).
%% @doc glCreateProgramObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateProgramObjectARB.xml">external</a> documentation.
-spec createProgramObjectARB() -> integer().
createProgramObjectARB() ->
- call(5632, <<>>).
+ call(5633, <<>>).
%% @doc glAttachObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glAttachObjectARB.xml">external</a> documentation.
-spec attachObjectARB(ContainerObj, Obj) -> 'ok' when ContainerObj :: integer(),Obj :: integer().
attachObjectARB(ContainerObj,Obj) ->
- cast(5633, <<ContainerObj:?GLhandleARB,Obj:?GLhandleARB>>).
+ cast(5634, <<ContainerObj:?GLhandleARB,Obj:?GLhandleARB>>).
%% @doc glLinkProgramARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLinkProgramARB.xml">external</a> documentation.
-spec linkProgramARB(ProgramObj) -> 'ok' when ProgramObj :: integer().
linkProgramARB(ProgramObj) ->
- cast(5634, <<ProgramObj:?GLhandleARB>>).
+ cast(5635, <<ProgramObj:?GLhandleARB>>).
%% @doc glUseProgramObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUseProgramObjectARB.xml">external</a> documentation.
-spec useProgramObjectARB(ProgramObj) -> 'ok' when ProgramObj :: integer().
useProgramObjectARB(ProgramObj) ->
- cast(5635, <<ProgramObj:?GLhandleARB>>).
+ cast(5636, <<ProgramObj:?GLhandleARB>>).
%% @doc glValidateProgramARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgramARB.xml">external</a> documentation.
-spec validateProgramARB(ProgramObj) -> 'ok' when ProgramObj :: integer().
validateProgramARB(ProgramObj) ->
- cast(5636, <<ProgramObj:?GLhandleARB>>).
+ cast(5637, <<ProgramObj:?GLhandleARB>>).
%% @doc glGetObjectParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetObjectParameterARB.xml">external</a> documentation.
-spec getObjectParameterfvARB(Obj, Pname) -> float() when Obj :: integer(),Pname :: enum().
getObjectParameterfvARB(Obj,Pname) ->
- call(5637, <<Obj:?GLhandleARB,Pname:?GLenum>>).
+ call(5638, <<Obj:?GLhandleARB,Pname:?GLenum>>).
%% @doc glGetObjectParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetObjectParameterARB.xml">external</a> documentation.
-spec getObjectParameterivARB(Obj, Pname) -> integer() when Obj :: integer(),Pname :: enum().
getObjectParameterivARB(Obj,Pname) ->
- call(5638, <<Obj:?GLhandleARB,Pname:?GLenum>>).
+ call(5639, <<Obj:?GLhandleARB,Pname:?GLenum>>).
%% @doc glGetInfoLogARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetInfoLogARB.xml">external</a> documentation.
-spec getInfoLogARB(Obj, MaxLength) -> string() when Obj :: integer(),MaxLength :: integer().
getInfoLogARB(Obj,MaxLength) ->
- call(5639, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
+ call(5640, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
%% @doc glGetAttachedObjectsARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttachedObjectsARB.xml">external</a> documentation.
-spec getAttachedObjectsARB(ContainerObj, MaxCount) -> [integer()] when ContainerObj :: integer(),MaxCount :: integer().
getAttachedObjectsARB(ContainerObj,MaxCount) ->
- call(5640, <<ContainerObj:?GLhandleARB,MaxCount:?GLsizei>>).
+ call(5641, <<ContainerObj:?GLhandleARB,MaxCount:?GLsizei>>).
%% @doc glGetUniformLocationARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocationARB.xml">external</a> documentation.
-spec getUniformLocationARB(ProgramObj, Name) -> integer() when ProgramObj :: integer(),Name :: string().
getUniformLocationARB(ProgramObj,Name) ->
- call(5641, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5642, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc glGetActiveUniformARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniformARB.xml">external</a> documentation.
-spec getActiveUniformARB(ProgramObj, Index, MaxLength) -> {Size :: integer(),Type :: enum(),Name :: string()} when ProgramObj :: integer(),Index :: integer(),MaxLength :: integer().
getActiveUniformARB(ProgramObj,Index,MaxLength) ->
- call(5642, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
+ call(5643, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
%% @doc glGetUniformARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformARB.xml">external</a> documentation.
-spec getUniformfvARB(ProgramObj, Location) -> matrix() when ProgramObj :: integer(),Location :: integer().
getUniformfvARB(ProgramObj,Location) ->
- call(5643, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
+ call(5644, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
%% @doc glGetUniformARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformARB.xml">external</a> documentation.
-spec getUniformivARB(ProgramObj, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when ProgramObj :: integer(),Location :: integer().
getUniformivARB(ProgramObj,Location) ->
- call(5644, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
+ call(5645, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
%% @doc glGetShaderSourceARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderSourceARB.xml">external</a> documentation.
-spec getShaderSourceARB(Obj, MaxLength) -> string() when Obj :: integer(),MaxLength :: integer().
getShaderSourceARB(Obj,MaxLength) ->
- call(5645, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
+ call(5646, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
%% @doc glBindAttribLocationARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindAttribLocationARB.xml">external</a> documentation.
-spec bindAttribLocationARB(ProgramObj, Index, Name) -> 'ok' when ProgramObj :: integer(),Index :: integer(),Name :: string().
bindAttribLocationARB(ProgramObj,Index,Name) ->
- cast(5646, <<ProgramObj:?GLhandleARB,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5647, <<ProgramObj:?GLhandleARB,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc glGetActiveAttribARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveAttribARB.xml">external</a> documentation.
-spec getActiveAttribARB(ProgramObj, Index, MaxLength) -> {Size :: integer(),Type :: enum(),Name :: string()} when ProgramObj :: integer(),Index :: integer(),MaxLength :: integer().
getActiveAttribARB(ProgramObj,Index,MaxLength) ->
- call(5647, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
+ call(5648, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
%% @doc glGetAttribLocationARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttribLocationARB.xml">external</a> documentation.
-spec getAttribLocationARB(ProgramObj, Name) -> integer() when ProgramObj :: integer(),Name :: string().
getAttribLocationARB(ProgramObj,Name) ->
- call(5648, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5649, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Determine if a name corresponds to a renderbuffer object
%%
@@ -13367,7 +13432,7 @@ getAttribLocationARB(ProgramObj,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsRenderbuffer.xml">external</a> documentation.
-spec isRenderbuffer(Renderbuffer) -> 0|1 when Renderbuffer :: integer().
isRenderbuffer(Renderbuffer) ->
- call(5649, <<Renderbuffer:?GLuint>>).
+ call(5650, <<Renderbuffer:?GLuint>>).
%% @doc Bind a renderbuffer to a renderbuffer target
%%
@@ -13380,7 +13445,7 @@ isRenderbuffer(Renderbuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindRenderbuffer.xml">external</a> documentation.
-spec bindRenderbuffer(Target, Renderbuffer) -> 'ok' when Target :: enum(),Renderbuffer :: integer().
bindRenderbuffer(Target,Renderbuffer) ->
- cast(5650, <<Target:?GLenum,Renderbuffer:?GLuint>>).
+ cast(5651, <<Target:?GLenum,Renderbuffer:?GLuint>>).
%% @doc Delete renderbuffer objects
%%
@@ -13402,8 +13467,9 @@ bindRenderbuffer(Target,Renderbuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteRenderbuffers.xml">external</a> documentation.
-spec deleteRenderbuffers(Renderbuffers) -> 'ok' when Renderbuffers :: [integer()].
deleteRenderbuffers(Renderbuffers) ->
- cast(5651, <<(length(Renderbuffers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Renderbuffers>>)/binary,0:(((1+length(Renderbuffers)) rem 2)*32)>>).
+ RenderbuffersLen = length(Renderbuffers),
+ cast(5652, <<RenderbuffersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Renderbuffers>>)/binary,0:(((1+RenderbuffersLen) rem 2)*32)>>).
%% @doc Generate renderbuffer object names
%%
@@ -13421,7 +13487,7 @@ deleteRenderbuffers(Renderbuffers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenRenderbuffers.xml">external</a> documentation.
-spec genRenderbuffers(N) -> [integer()] when N :: integer().
genRenderbuffers(N) ->
- call(5652, <<N:?GLsizei>>).
+ call(5653, <<N:?GLsizei>>).
%% @doc Establish data storage, format and dimensions of a renderbuffer object's image
%%
@@ -13442,7 +13508,7 @@ genRenderbuffers(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glRenderbufferStorage.xml">external</a> documentation.
-spec renderbufferStorage(Target, Internalformat, Width, Height) -> 'ok' when Target :: enum(),Internalformat :: enum(),Width :: integer(),Height :: integer().
renderbufferStorage(Target,Internalformat,Width,Height) ->
- cast(5653, <<Target:?GLenum,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5654, <<Target:?GLenum,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
%% @doc Retrieve information about a bound renderbuffer object
%%
@@ -13470,7 +13536,7 @@ renderbufferStorage(Target,Internalformat,Width,Height) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetRenderbufferParameter.xml">external</a> documentation.
-spec getRenderbufferParameteriv(Target, Pname) -> integer() when Target :: enum(),Pname :: enum().
getRenderbufferParameteriv(Target,Pname) ->
- call(5654, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5655, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Determine if a name corresponds to a framebuffer object
%%
@@ -13484,7 +13550,7 @@ getRenderbufferParameteriv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsFramebuffer.xml">external</a> documentation.
-spec isFramebuffer(Framebuffer) -> 0|1 when Framebuffer :: integer().
isFramebuffer(Framebuffer) ->
- call(5655, <<Framebuffer:?GLuint>>).
+ call(5656, <<Framebuffer:?GLuint>>).
%% @doc Bind a framebuffer to a framebuffer target
%%
@@ -13502,7 +13568,7 @@ isFramebuffer(Framebuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindFramebuffer.xml">external</a> documentation.
-spec bindFramebuffer(Target, Framebuffer) -> 'ok' when Target :: enum(),Framebuffer :: integer().
bindFramebuffer(Target,Framebuffer) ->
- cast(5656, <<Target:?GLenum,Framebuffer:?GLuint>>).
+ cast(5657, <<Target:?GLenum,Framebuffer:?GLuint>>).
%% @doc Delete framebuffer objects
%%
@@ -13517,8 +13583,9 @@ bindFramebuffer(Target,Framebuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteFramebuffers.xml">external</a> documentation.
-spec deleteFramebuffers(Framebuffers) -> 'ok' when Framebuffers :: [integer()].
deleteFramebuffers(Framebuffers) ->
- cast(5657, <<(length(Framebuffers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Framebuffers>>)/binary,0:(((1+length(Framebuffers)) rem 2)*32)>>).
+ FramebuffersLen = length(Framebuffers),
+ cast(5658, <<FramebuffersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Framebuffers>>)/binary,0:(((1+FramebuffersLen) rem 2)*32)>>).
%% @doc Generate framebuffer object names
%%
@@ -13536,7 +13603,7 @@ deleteFramebuffers(Framebuffers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenFramebuffers.xml">external</a> documentation.
-spec genFramebuffers(N) -> [integer()] when N :: integer().
genFramebuffers(N) ->
- call(5658, <<N:?GLsizei>>).
+ call(5659, <<N:?GLsizei>>).
%% @doc Check the completeness status of a framebuffer
%%
@@ -13587,25 +13654,25 @@ genFramebuffers(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCheckFramebufferStatus.xml">external</a> documentation.
-spec checkFramebufferStatus(Target) -> enum() when Target :: enum().
checkFramebufferStatus(Target) ->
- call(5659, <<Target:?GLenum>>).
+ call(5660, <<Target:?GLenum>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTexture1D(Target, Attachment, Textarget, Texture, Level) -> 'ok' when Target :: enum(),Attachment :: enum(),Textarget :: enum(),Texture :: integer(),Level :: integer().
framebufferTexture1D(Target,Attachment,Textarget,Texture,Level) ->
- cast(5660, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
+ cast(5661, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTexture2D(Target, Attachment, Textarget, Texture, Level) -> 'ok' when Target :: enum(),Attachment :: enum(),Textarget :: enum(),Texture :: integer(),Level :: integer().
framebufferTexture2D(Target,Attachment,Textarget,Texture,Level) ->
- cast(5661, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
+ cast(5662, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTexture3D(Target, Attachment, Textarget, Texture, Level, Zoffset) -> 'ok' when Target :: enum(),Attachment :: enum(),Textarget :: enum(),Texture :: integer(),Level :: integer(),Zoffset :: integer().
framebufferTexture3D(Target,Attachment,Textarget,Texture,Level,Zoffset) ->
- cast(5662, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint,Zoffset:?GLint>>).
+ cast(5663, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint,Zoffset:?GLint>>).
%% @doc Attach a renderbuffer as a logical buffer to the currently bound framebuffer object
%%
@@ -13637,7 +13704,7 @@ framebufferTexture3D(Target,Attachment,Textarget,Texture,Level,Zoffset) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFramebufferRenderbuffer.xml">external</a> documentation.
-spec framebufferRenderbuffer(Target, Attachment, Renderbuffertarget, Renderbuffer) -> 'ok' when Target :: enum(),Attachment :: enum(),Renderbuffertarget :: enum(),Renderbuffer :: integer().
framebufferRenderbuffer(Target,Attachment,Renderbuffertarget,Renderbuffer) ->
- cast(5663, <<Target:?GLenum,Attachment:?GLenum,Renderbuffertarget:?GLenum,Renderbuffer:?GLuint>>).
+ cast(5664, <<Target:?GLenum,Attachment:?GLenum,Renderbuffertarget:?GLenum,Renderbuffer:?GLuint>>).
%% @doc Retrieve information about attachments of a bound framebuffer object
%%
@@ -13733,7 +13800,7 @@ framebufferRenderbuffer(Target,Attachment,Renderbuffertarget,Renderbuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetFramebufferAttachmentParameter.xml">external</a> documentation.
-spec getFramebufferAttachmentParameteriv(Target, Attachment, Pname) -> integer() when Target :: enum(),Attachment :: enum(),Pname :: enum().
getFramebufferAttachmentParameteriv(Target,Attachment,Pname) ->
- call(5664, <<Target:?GLenum,Attachment:?GLenum,Pname:?GLenum>>).
+ call(5665, <<Target:?GLenum,Attachment:?GLenum,Pname:?GLenum>>).
%% @doc Generate mipmaps for a specified texture target
%%
@@ -13753,7 +13820,7 @@ getFramebufferAttachmentParameteriv(Target,Attachment,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenerateMipmap.xml">external</a> documentation.
-spec generateMipmap(Target) -> 'ok' when Target :: enum().
generateMipmap(Target) ->
- cast(5665, <<Target:?GLenum>>).
+ cast(5666, <<Target:?GLenum>>).
%% @doc Copy a block of pixels from the read framebuffer to the draw framebuffer
%%
@@ -13795,7 +13862,7 @@ generateMipmap(Target) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBlitFramebuffer.xml">external</a> documentation.
-spec blitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter) -> 'ok' when SrcX0 :: integer(),SrcY0 :: integer(),SrcX1 :: integer(),SrcY1 :: integer(),DstX0 :: integer(),DstY0 :: integer(),DstX1 :: integer(),DstY1 :: integer(),Mask :: integer(),Filter :: enum().
blitFramebuffer(SrcX0,SrcY0,SrcX1,SrcY1,DstX0,DstY0,DstX1,DstY1,Mask,Filter) ->
- cast(5666, <<SrcX0:?GLint,SrcY0:?GLint,SrcX1:?GLint,SrcY1:?GLint,DstX0:?GLint,DstY0:?GLint,DstX1:?GLint,DstY1:?GLint,Mask:?GLbitfield,Filter:?GLenum>>).
+ cast(5667, <<SrcX0:?GLint,SrcY0:?GLint,SrcX1:?GLint,SrcY1:?GLint,DstX0:?GLint,DstY0:?GLint,DstX1:?GLint,DstY1:?GLint,Mask:?GLbitfield,Filter:?GLenum>>).
%% @doc Establish data storage, format, dimensions and sample count of a renderbuffer object's image
%%
@@ -13819,19 +13886,19 @@ blitFramebuffer(SrcX0,SrcY0,SrcX1,SrcY1,DstX0,DstY0,DstX1,DstY1,Mask,Filter) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glRenderbufferStorageMultisample.xml">external</a> documentation.
-spec renderbufferStorageMultisample(Target, Samples, Internalformat, Width, Height) -> 'ok' when Target :: enum(),Samples :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer().
renderbufferStorageMultisample(Target,Samples,Internalformat,Width,Height) ->
- cast(5667, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5668, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTextureLayer(Target, Attachment, Texture, Level, Layer) -> 'ok' when Target :: enum(),Attachment :: enum(),Texture :: integer(),Level :: integer(),Layer :: integer().
framebufferTextureLayer(Target,Attachment,Texture,Level,Layer) ->
- cast(5668, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Layer:?GLint>>).
+ cast(5669, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Layer:?GLint>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTextureFaceARB(Target, Attachment, Texture, Level, Face) -> 'ok' when Target :: enum(),Attachment :: enum(),Texture :: integer(),Level :: integer(),Face :: enum().
framebufferTextureFaceARB(Target,Attachment,Texture,Level,Face) ->
- cast(5669, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Face:?GLenum>>).
+ cast(5670, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Face:?GLenum>>).
%% @doc Indicate modifications to a range of a mapped buffer
%%
@@ -13845,7 +13912,7 @@ framebufferTextureFaceARB(Target,Attachment,Texture,Level,Face) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFlushMappedBufferRange.xml">external</a> documentation.
-spec flushMappedBufferRange(Target, Offset, Length) -> 'ok' when Target :: enum(),Offset :: integer(),Length :: integer().
flushMappedBufferRange(Target,Offset,Length) ->
- cast(5670, <<Target:?GLenum,0:32,Offset:?GLintptr,Length:?GLsizeiptr>>).
+ cast(5671, <<Target:?GLenum,0:32,Offset:?GLintptr,Length:?GLsizeiptr>>).
%% @doc Bind a vertex array object
%%
@@ -13860,7 +13927,7 @@ flushMappedBufferRange(Target,Offset,Length) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindVertexArray.xml">external</a> documentation.
-spec bindVertexArray(Array) -> 'ok' when Array :: integer().
bindVertexArray(Array) ->
- cast(5671, <<Array:?GLuint>>).
+ cast(5672, <<Array:?GLuint>>).
%% @doc Delete vertex array objects
%%
@@ -13873,8 +13940,9 @@ bindVertexArray(Array) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteVertexArrays.xml">external</a> documentation.
-spec deleteVertexArrays(Arrays) -> 'ok' when Arrays :: [integer()].
deleteVertexArrays(Arrays) ->
- cast(5672, <<(length(Arrays)):?GLuint,
- (<< <<C:?GLuint>> || C <- Arrays>>)/binary,0:(((1+length(Arrays)) rem 2)*32)>>).
+ ArraysLen = length(Arrays),
+ cast(5673, <<ArraysLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Arrays>>)/binary,0:(((1+ArraysLen) rem 2)*32)>>).
%% @doc Generate vertex array object names
%%
@@ -13892,7 +13960,7 @@ deleteVertexArrays(Arrays) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenVertexArrays.xml">external</a> documentation.
-spec genVertexArrays(N) -> [integer()] when N :: integer().
genVertexArrays(N) ->
- call(5673, <<N:?GLsizei>>).
+ call(5674, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a vertex array object
%%
@@ -13906,7 +13974,7 @@ genVertexArrays(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsVertexArray.xml">external</a> documentation.
-spec isVertexArray(Array) -> 0|1 when Array :: integer().
isVertexArray(Array) ->
- call(5674, <<Array:?GLuint>>).
+ call(5675, <<Array:?GLuint>>).
%% @doc Retrieve the index of a named uniform block
%%
@@ -13933,16 +14001,18 @@ isVertexArray(Array) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformIndices.xml">external</a> documentation.
-spec getUniformIndices(Program, UniformNames) -> [integer()] when Program :: integer(),UniformNames :: iolist().
getUniformIndices(Program,UniformNames) ->
- UniformNamesTemp = list_to_binary([[Str|[0]] || Str <- UniformNames ]),
- call(5675, <<Program:?GLuint,(length(UniformNames)):?GLuint,(size(UniformNamesTemp)):?GLuint,(UniformNamesTemp)/binary,0:((8-((size(UniformNamesTemp)+0) rem 8)) rem 8)>>).
+ UniformNamesTemp = list_to_binary([[Str|[0]] || Str <- UniformNames ]),
+ UniformNamesLen = length(UniformNames),
+ call(5676, <<Program:?GLuint,UniformNamesLen:?GLuint,(size(UniformNamesTemp)):?GLuint,(UniformNamesTemp)/binary,0:((8-((size(UniformNamesTemp)+0) rem 8)) rem 8)>>).
%% @doc glGetActiveUniforms
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniforms.xml">external</a> documentation.
-spec getActiveUniformsiv(Program, UniformIndices, Pname) -> [integer()] when Program :: integer(),UniformIndices :: [integer()],Pname :: enum().
getActiveUniformsiv(Program,UniformIndices,Pname) ->
- call(5676, <<Program:?GLuint,(length(UniformIndices)):?GLuint,
- (<< <<C:?GLuint>> || C <- UniformIndices>>)/binary,0:(((length(UniformIndices)) rem 2)*32),Pname:?GLenum>>).
+ UniformIndicesLen = length(UniformIndices),
+ call(5677, <<Program:?GLuint,UniformIndicesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- UniformIndices>>)/binary,0:(((UniformIndicesLen) rem 2)*32),Pname:?GLenum>>).
%% @doc Query the name of an active uniform
%%
@@ -13971,7 +14041,7 @@ getActiveUniformsiv(Program,UniformIndices,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniformName.xml">external</a> documentation.
-spec getActiveUniformName(Program, UniformIndex, BufSize) -> string() when Program :: integer(),UniformIndex :: integer(),BufSize :: integer().
getActiveUniformName(Program,UniformIndex,BufSize) ->
- call(5677, <<Program:?GLuint,UniformIndex:?GLuint,BufSize:?GLsizei>>).
+ call(5678, <<Program:?GLuint,UniformIndex:?GLuint,BufSize:?GLsizei>>).
%% @doc Retrieve the index of a named uniform block
%%
@@ -13995,7 +14065,8 @@ getActiveUniformName(Program,UniformIndex,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformBlockIndex.xml">external</a> documentation.
-spec getUniformBlockIndex(Program, UniformBlockName) -> integer() when Program :: integer(),UniformBlockName :: string().
getUniformBlockIndex(Program,UniformBlockName) ->
- call(5678, <<Program:?GLuint,(list_to_binary([UniformBlockName|[0]]))/binary,0:((8-((length(UniformBlockName)+ 5) rem 8)) rem 8)>>).
+ UniformBlockNameLen = length(UniformBlockName),
+ call(5679, <<Program:?GLuint,(list_to_binary([UniformBlockName|[0]]))/binary,0:((8-((UniformBlockNameLen+ 5) rem 8)) rem 8)>>).
%% @doc Query information about an active uniform block
%%
@@ -14048,7 +14119,7 @@ getUniformBlockIndex(Program,UniformBlockName) ->
-spec getActiveUniformBlockiv(Program, UniformBlockIndex, Pname, Params) -> 'ok' when Program :: integer(),UniformBlockIndex :: integer(),Pname :: enum(),Params :: mem().
getActiveUniformBlockiv(Program,UniformBlockIndex,Pname,Params) ->
send_bin(Params),
- call(5679, <<Program:?GLuint,UniformBlockIndex:?GLuint,Pname:?GLenum>>).
+ call(5680, <<Program:?GLuint,UniformBlockIndex:?GLuint,Pname:?GLenum>>).
%% @doc Retrieve the name of an active uniform block
%%
@@ -14077,7 +14148,7 @@ getActiveUniformBlockiv(Program,UniformBlockIndex,Pname,Params) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniformBlockName.xml">external</a> documentation.
-spec getActiveUniformBlockName(Program, UniformBlockIndex, BufSize) -> string() when Program :: integer(),UniformBlockIndex :: integer(),BufSize :: integer().
getActiveUniformBlockName(Program,UniformBlockIndex,BufSize) ->
- call(5680, <<Program:?GLuint,UniformBlockIndex:?GLuint,BufSize:?GLsizei>>).
+ call(5681, <<Program:?GLuint,UniformBlockIndex:?GLuint,BufSize:?GLsizei>>).
%% @doc Assign a binding point to an active uniform block
%%
@@ -14097,7 +14168,7 @@ getActiveUniformBlockName(Program,UniformBlockIndex,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUniformBlockBinding.xml">external</a> documentation.
-spec uniformBlockBinding(Program, UniformBlockIndex, UniformBlockBinding) -> 'ok' when Program :: integer(),UniformBlockIndex :: integer(),UniformBlockBinding :: integer().
uniformBlockBinding(Program,UniformBlockIndex,UniformBlockBinding) ->
- cast(5681, <<Program:?GLuint,UniformBlockIndex:?GLuint,UniformBlockBinding:?GLuint>>).
+ cast(5682, <<Program:?GLuint,UniformBlockIndex:?GLuint,UniformBlockBinding:?GLuint>>).
%% @doc Copy part of the data store of a buffer object to the data store of another buffer object
%%
@@ -14123,7 +14194,7 @@ uniformBlockBinding(Program,UniformBlockIndex,UniformBlockBinding) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCopyBufferSubData.xml">external</a> documentation.
-spec copyBufferSubData(ReadTarget, WriteTarget, ReadOffset, WriteOffset, Size) -> 'ok' when ReadTarget :: enum(),WriteTarget :: enum(),ReadOffset :: integer(),WriteOffset :: integer(),Size :: integer().
copyBufferSubData(ReadTarget,WriteTarget,ReadOffset,WriteOffset,Size) ->
- cast(5682, <<ReadTarget:?GLenum,WriteTarget:?GLenum,ReadOffset:?GLintptr,WriteOffset:?GLintptr,Size:?GLsizeiptr>>).
+ cast(5683, <<ReadTarget:?GLenum,WriteTarget:?GLenum,ReadOffset:?GLintptr,WriteOffset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Render primitives from array data with a per-element offset
%%
@@ -14137,10 +14208,10 @@ copyBufferSubData(ReadTarget,WriteTarget,ReadOffset,WriteOffset,Size) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsBaseVertex.xml">external</a> documentation.
-spec drawElementsBaseVertex(Mode, Count, Type, Indices, Basevertex) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Basevertex :: integer().
drawElementsBaseVertex(Mode,Count,Type,Indices,Basevertex) when is_integer(Indices) ->
- cast(5683, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
+ cast(5684, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
drawElementsBaseVertex(Mode,Count,Type,Indices,Basevertex) ->
send_bin(Indices),
- cast(5684, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
+ cast(5685, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
%% @doc Render primitives from array data with a per-element offset
%%
@@ -14159,10 +14230,10 @@ drawElementsBaseVertex(Mode,Count,Type,Indices,Basevertex) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawRangeElementsBaseVertex.xml">external</a> documentation.
-spec drawRangeElementsBaseVertex(Mode, Start, End, Count, Type, Indices, Basevertex) -> 'ok' when Mode :: enum(),Start :: integer(),End :: integer(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Basevertex :: integer().
drawRangeElementsBaseVertex(Mode,Start,End,Count,Type,Indices,Basevertex) when is_integer(Indices) ->
- cast(5685, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
+ cast(5686, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
drawRangeElementsBaseVertex(Mode,Start,End,Count,Type,Indices,Basevertex) ->
send_bin(Indices),
- cast(5686, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
+ cast(5687, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
%% @doc Render multiple instances of a set of primitives from array data with a per-element offset
%%
@@ -14176,10 +14247,10 @@ drawRangeElementsBaseVertex(Mode,Start,End,Count,Type,Indices,Basevertex) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstancedBaseVertex.xml">external</a> documentation.
-spec drawElementsInstancedBaseVertex(Mode, Count, Type, Indices, Primcount, Basevertex) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer(),Basevertex :: integer().
drawElementsInstancedBaseVertex(Mode,Count,Type,Indices,Primcount,Basevertex) when is_integer(Indices) ->
- cast(5687, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint>>);
+ cast(5688, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint>>);
drawElementsInstancedBaseVertex(Mode,Count,Type,Indices,Primcount,Basevertex) ->
send_bin(Indices),
- cast(5688, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint>>).
+ cast(5689, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint>>).
%% @doc Specifiy the vertex to be used as the source of data for flat shaded varyings
%%
@@ -14213,7 +14284,7 @@ drawElementsInstancedBaseVertex(Mode,Count,Type,Indices,Primcount,Basevertex) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProvokingVertex.xml">external</a> documentation.
-spec provokingVertex(Mode) -> 'ok' when Mode :: enum().
provokingVertex(Mode) ->
- cast(5689, <<Mode:?GLenum>>).
+ cast(5690, <<Mode:?GLenum>>).
%% @doc Create a new sync object and insert it into the GL command stream
%%
@@ -14237,7 +14308,7 @@ provokingVertex(Mode) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFenceSync.xml">external</a> documentation.
-spec fenceSync(Condition, Flags) -> integer() when Condition :: enum(),Flags :: integer().
fenceSync(Condition,Flags) ->
- call(5690, <<Condition:?GLenum,Flags:?GLbitfield>>).
+ call(5691, <<Condition:?GLenum,Flags:?GLbitfield>>).
%% @doc Determine if a name corresponds to a sync object
%%
@@ -14248,7 +14319,7 @@ fenceSync(Condition,Flags) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsSync.xml">external</a> documentation.
-spec isSync(Sync) -> 0|1 when Sync :: integer().
isSync(Sync) ->
- call(5691, <<Sync:?GLsync>>).
+ call(5692, <<Sync:?GLsync>>).
%% @doc Delete a sync object
%%
@@ -14265,7 +14336,7 @@ isSync(Sync) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteSync.xml">external</a> documentation.
-spec deleteSync(Sync) -> 'ok' when Sync :: integer().
deleteSync(Sync) ->
- cast(5692, <<Sync:?GLsync>>).
+ cast(5693, <<Sync:?GLsync>>).
%% @doc Block and wait for a sync object to become signaled
%%
@@ -14291,7 +14362,7 @@ deleteSync(Sync) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClientWaitSync.xml">external</a> documentation.
-spec clientWaitSync(Sync, Flags, Timeout) -> enum() when Sync :: integer(),Flags :: integer(),Timeout :: integer().
clientWaitSync(Sync,Flags,Timeout) ->
- call(5693, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
+ call(5694, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
%% @doc Instruct the GL server to block until the specified sync object becomes signaled
%%
@@ -14313,13 +14384,13 @@ clientWaitSync(Sync,Flags,Timeout) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWaitSync.xml">external</a> documentation.
-spec waitSync(Sync, Flags, Timeout) -> 'ok' when Sync :: integer(),Flags :: integer(),Timeout :: integer().
waitSync(Sync,Flags,Timeout) ->
- cast(5694, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
+ cast(5695, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getInteger64v(Pname) -> [integer()] when Pname :: enum().
getInteger64v(Pname) ->
- call(5695, <<Pname:?GLenum>>).
+ call(5696, <<Pname:?GLenum>>).
%% @doc Query the properties of a sync object
%%
@@ -14354,7 +14425,7 @@ getInteger64v(Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSync.xml">external</a> documentation.
-spec getSynciv(Sync, Pname, BufSize) -> [integer()] when Sync :: integer(),Pname :: enum(),BufSize :: integer().
getSynciv(Sync,Pname,BufSize) ->
- call(5696, <<Sync:?GLsync,Pname:?GLenum,BufSize:?GLsizei>>).
+ call(5697, <<Sync:?GLsync,Pname:?GLenum,BufSize:?GLsizei>>).
%% @doc Establish the data storage, format, dimensions, and number of samples of a multisample texture's image
%%
@@ -14382,7 +14453,7 @@ getSynciv(Sync,Pname,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2DMultisample.xml">external</a> documentation.
-spec texImage2DMultisample(Target, Samples, Internalformat, Width, Height, Fixedsamplelocations) -> 'ok' when Target :: enum(),Samples :: integer(),Internalformat :: integer(),Width :: integer(),Height :: integer(),Fixedsamplelocations :: 0|1.
texImage2DMultisample(Target,Samples,Internalformat,Width,Height,Fixedsamplelocations) ->
- cast(5697, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Fixedsamplelocations:?GLboolean>>).
+ cast(5698, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Fixedsamplelocations:?GLboolean>>).
%% @doc Establish the data storage, format, dimensions, and number of samples of a multisample texture's image
%%
@@ -14410,7 +14481,7 @@ texImage2DMultisample(Target,Samples,Internalformat,Width,Height,Fixedsampleloca
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexImage3DMultisample.xml">external</a> documentation.
-spec texImage3DMultisample(Target, Samples, Internalformat, Width, Height, Depth, Fixedsamplelocations) -> 'ok' when Target :: enum(),Samples :: integer(),Internalformat :: integer(),Width :: integer(),Height :: integer(),Depth :: integer(),Fixedsamplelocations :: 0|1.
texImage3DMultisample(Target,Samples,Internalformat,Width,Height,Depth,Fixedsamplelocations) ->
- cast(5698, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei,Fixedsamplelocations:?GLboolean>>).
+ cast(5699, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei,Fixedsamplelocations:?GLboolean>>).
%% @doc Retrieve the location of a sample
%%
@@ -14428,7 +14499,7 @@ texImage3DMultisample(Target,Samples,Internalformat,Width,Height,Depth,Fixedsamp
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetMultisample.xml">external</a> documentation.
-spec getMultisamplefv(Pname, Index) -> {float(),float()} when Pname :: enum(),Index :: integer().
getMultisamplefv(Pname,Index) ->
- call(5699, <<Pname:?GLenum,Index:?GLuint>>).
+ call(5700, <<Pname:?GLenum,Index:?GLuint>>).
%% @doc Set the value of a sub-word of the sample mask
%%
@@ -14443,57 +14514,65 @@ getMultisamplefv(Pname,Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSampleMaski.xml">external</a> documentation.
-spec sampleMaski(Index, Mask) -> 'ok' when Index :: integer(),Mask :: integer().
sampleMaski(Index,Mask) ->
- cast(5700, <<Index:?GLuint,Mask:?GLbitfield>>).
+ cast(5701, <<Index:?GLuint,Mask:?GLbitfield>>).
%% @doc glNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glNamedStringARB.xml">external</a> documentation.
-spec namedStringARB(Type, Name, String) -> 'ok' when Type :: enum(),Name :: string(),String :: string().
namedStringARB(Type,Name,String) ->
- cast(5701, <<Type:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8),(list_to_binary([String|[0]]))/binary,0:((8-((length(String)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ StringLen = length(String),
+ cast(5702, <<Type:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8),(list_to_binary([String|[0]]))/binary,0:((8-((StringLen+ 1) rem 8)) rem 8)>>).
%% @doc glDeleteNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteNamedStringARB.xml">external</a> documentation.
-spec deleteNamedStringARB(Name) -> 'ok' when Name :: string().
deleteNamedStringARB(Name) ->
- cast(5702, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5703, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc glCompileShaderIncludeARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShaderIncludeARB.xml">external</a> documentation.
-spec compileShaderIncludeARB(Shader, Path) -> 'ok' when Shader :: integer(),Path :: iolist().
compileShaderIncludeARB(Shader,Path) ->
- PathTemp = list_to_binary([[Str|[0]] || Str <- Path ]),
- cast(5703, <<Shader:?GLuint,(length(Path)):?GLuint,(size(PathTemp)):?GLuint,(PathTemp)/binary,0:((8-((size(PathTemp)+0) rem 8)) rem 8)>>).
+ PathTemp = list_to_binary([[Str|[0]] || Str <- Path ]),
+ PathLen = length(Path),
+ cast(5704, <<Shader:?GLuint,PathLen:?GLuint,(size(PathTemp)):?GLuint,(PathTemp)/binary,0:((8-((size(PathTemp)+0) rem 8)) rem 8)>>).
%% @doc glIsNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsNamedStringARB.xml">external</a> documentation.
-spec isNamedStringARB(Name) -> 0|1 when Name :: string().
isNamedStringARB(Name) ->
- call(5704, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5705, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc glGetNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetNamedStringARB.xml">external</a> documentation.
-spec getNamedStringARB(Name, BufSize) -> string() when Name :: string(),BufSize :: integer().
getNamedStringARB(Name,BufSize) ->
- call(5705, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8),BufSize:?GLsizei>>).
+ NameLen = length(Name),
+ call(5706, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8),BufSize:?GLsizei>>).
%% @doc glGetNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetNamedStringARB.xml">external</a> documentation.
-spec getNamedStringivARB(Name, Pname) -> integer() when Name :: string(),Pname :: enum().
getNamedStringivARB(Name,Pname) ->
- call(5706, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8),Pname:?GLenum>>).
+ NameLen = length(Name),
+ call(5707, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8),Pname:?GLenum>>).
%% @doc glBindFragDataLocationIndexe
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindFragDataLocationIndexe.xml">external</a> documentation.
-spec bindFragDataLocationIndexed(Program, ColorNumber, Index, Name) -> 'ok' when Program :: integer(),ColorNumber :: integer(),Index :: integer(),Name :: string().
bindFragDataLocationIndexed(Program,ColorNumber,Index,Name) ->
- cast(5707, <<Program:?GLuint,ColorNumber:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5708, <<Program:?GLuint,ColorNumber:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Query the bindings of color indices to user-defined varying out variables
%%
@@ -14504,7 +14583,8 @@ bindFragDataLocationIndexed(Program,ColorNumber,Index,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetFragDataIndex.xml">external</a> documentation.
-spec getFragDataIndex(Program, Name) -> integer() when Program :: integer(),Name :: string().
getFragDataIndex(Program,Name) ->
- call(5708, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5709, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Generate sampler object names
%%
@@ -14522,7 +14602,7 @@ getFragDataIndex(Program,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenSamplers.xml">external</a> documentation.
-spec genSamplers(Count) -> [integer()] when Count :: integer().
genSamplers(Count) ->
- call(5709, <<Count:?GLsizei>>).
+ call(5710, <<Count:?GLsizei>>).
%% @doc Delete named sampler objects
%%
@@ -14535,8 +14615,9 @@ genSamplers(Count) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteSamplers.xml">external</a> documentation.
-spec deleteSamplers(Samplers) -> 'ok' when Samplers :: [integer()].
deleteSamplers(Samplers) ->
- cast(5710, <<(length(Samplers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Samplers>>)/binary,0:(((1+length(Samplers)) rem 2)*32)>>).
+ SamplersLen = length(Samplers),
+ cast(5711, <<SamplersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Samplers>>)/binary,0:(((1+SamplersLen) rem 2)*32)>>).
%% @doc Determine if a name corresponds to a sampler object
%%
@@ -14549,7 +14630,7 @@ deleteSamplers(Samplers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsSampler.xml">external</a> documentation.
-spec isSampler(Sampler) -> 0|1 when Sampler :: integer().
isSampler(Sampler) ->
- call(5711, <<Sampler:?GLuint>>).
+ call(5712, <<Sampler:?GLuint>>).
%% @doc Bind a named sampler to a texturing target
%%
@@ -14566,7 +14647,7 @@ isSampler(Sampler) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindSampler.xml">external</a> documentation.
-spec bindSampler(Unit, Sampler) -> 'ok' when Unit :: integer(),Sampler :: integer().
bindSampler(Unit,Sampler) ->
- cast(5712, <<Unit:?GLuint,Sampler:?GLuint>>).
+ cast(5713, <<Unit:?GLuint,Sampler:?GLuint>>).
%% @doc Set sampler parameters
%%
@@ -14712,42 +14793,46 @@ bindSampler(Unit,Sampler) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSamplerParameter.xml">external</a> documentation.
-spec samplerParameteri(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: integer().
samplerParameteri(Sampler,Pname,Param) ->
- cast(5713, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLint>>).
+ cast(5714, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLint>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameteriv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [integer()].
samplerParameteriv(Sampler,Pname,Param) ->
- cast(5714, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5715, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameterf(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: float().
samplerParameterf(Sampler,Pname,Param) ->
- cast(5715, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLfloat>>).
+ cast(5716, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLfloat>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameterfv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [float()].
samplerParameterfv(Sampler,Pname,Param) ->
- cast(5716, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5717, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameterIiv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [integer()].
samplerParameterIiv(Sampler,Pname,Param) ->
- cast(5717, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5718, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc glSamplerParameterI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSamplerParameterI.xml">external</a> documentation.
-spec samplerParameterIuiv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [integer()].
samplerParameterIuiv(Sampler,Pname,Param) ->
- cast(5718, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLuint>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5719, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc Return sampler parameter values
%%
@@ -14794,26 +14879,26 @@ samplerParameterIuiv(Sampler,Pname,Param) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSamplerParameter.xml">external</a> documentation.
-spec getSamplerParameteriv(Sampler, Pname) -> [integer()] when Sampler :: integer(),Pname :: enum().
getSamplerParameteriv(Sampler,Pname) ->
- call(5719, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5720, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getSamplerParameteriv/2}
-spec getSamplerParameterIiv(Sampler, Pname) -> [integer()] when Sampler :: integer(),Pname :: enum().
getSamplerParameterIiv(Sampler,Pname) ->
- call(5720, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5721, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getSamplerParameteriv/2}
-spec getSamplerParameterfv(Sampler, Pname) -> [float()] when Sampler :: integer(),Pname :: enum().
getSamplerParameterfv(Sampler,Pname) ->
- call(5721, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5722, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc glGetSamplerParameterI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSamplerParameterI.xml">external</a> documentation.
-spec getSamplerParameterIuiv(Sampler, Pname) -> [integer()] when Sampler :: integer(),Pname :: enum().
getSamplerParameterIuiv(Sampler,Pname) ->
- call(5722, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5723, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc Record the GL time into a query object after all previous commands have reached the GL server but have not yet necessarily executed.
%%
@@ -14828,21 +14913,21 @@ getSamplerParameterIuiv(Sampler,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glQueryCounter.xml">external</a> documentation.
-spec queryCounter(Id, Target) -> 'ok' when Id :: integer(),Target :: enum().
queryCounter(Id,Target) ->
- cast(5723, <<Id:?GLuint,Target:?GLenum>>).
+ cast(5724, <<Id:?GLuint,Target:?GLenum>>).
%% @doc glGetQueryObjecti64v
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryObjecti64v.xml">external</a> documentation.
-spec getQueryObjecti64v(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjecti64v(Id,Pname) ->
- call(5724, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5725, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc glGetQueryObjectui64v
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryObjectui64v.xml">external</a> documentation.
-spec getQueryObjectui64v(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjectui64v(Id,Pname) ->
- call(5725, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5726, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc Render primitives from array data, taking parameters from memory
%%
@@ -14872,10 +14957,10 @@ getQueryObjectui64v(Id,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawArraysIndirect.xml">external</a> documentation.
-spec drawArraysIndirect(Mode, Indirect) -> 'ok' when Mode :: enum(),Indirect :: offset()|mem().
drawArraysIndirect(Mode,Indirect) when is_integer(Indirect) ->
- cast(5726, <<Mode:?GLenum,Indirect:?GLuint>>);
+ cast(5727, <<Mode:?GLenum,Indirect:?GLuint>>);
drawArraysIndirect(Mode,Indirect) ->
send_bin(Indirect),
- cast(5727, <<Mode:?GLenum>>).
+ cast(5728, <<Mode:?GLenum>>).
%% @doc Render indexed primitives from array data, taking parameters from memory
%%
@@ -14912,131 +14997,144 @@ drawArraysIndirect(Mode,Indirect) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsIndirect.xml">external</a> documentation.
-spec drawElementsIndirect(Mode, Type, Indirect) -> 'ok' when Mode :: enum(),Type :: enum(),Indirect :: offset()|mem().
drawElementsIndirect(Mode,Type,Indirect) when is_integer(Indirect) ->
- cast(5728, <<Mode:?GLenum,Type:?GLenum,Indirect:?GLuint>>);
+ cast(5729, <<Mode:?GLenum,Type:?GLenum,Indirect:?GLuint>>);
drawElementsIndirect(Mode,Type,Indirect) ->
send_bin(Indirect),
- cast(5729, <<Mode:?GLenum,Type:?GLenum>>).
+ cast(5730, <<Mode:?GLenum,Type:?GLenum>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1d(Location, X) -> 'ok' when Location :: integer(),X :: float().
uniform1d(Location,X) ->
- cast(5730, <<Location:?GLint,0:32,X:?GLdouble>>).
+ cast(5731, <<Location:?GLint,0:32,X:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2d(Location, X, Y) -> 'ok' when Location :: integer(),X :: float(),Y :: float().
uniform2d(Location,X,Y) ->
- cast(5731, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble>>).
+ cast(5732, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3d(Location, X, Y, Z) -> 'ok' when Location :: integer(),X :: float(),Y :: float(),Z :: float().
uniform3d(Location,X,Y,Z) ->
- cast(5732, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5733, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4d(Location, X, Y, Z, W) -> 'ok' when Location :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
uniform4d(Location,X,Y,Z,W) ->
- cast(5733, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5734, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [float()].
uniform1dv(Location,Value) ->
- cast(5734, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5735, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<C:?GLdouble>> || C <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float()}].
uniform2dv(Location,Value) ->
- cast(5735, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5736, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float()}].
uniform3dv(Location,Value) ->
- cast(5736, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5737, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float(),float()}].
uniform4dv(Location,Value) ->
- cast(5737, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5738, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
uniformMatrix2dv(Location,Transpose,Value) ->
- cast(5738, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5739, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3dv(Location,Transpose,Value) ->
- cast(5739, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5740, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4dv(Location,Transpose,Value) ->
- cast(5740, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5741, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble,V13:?GLdouble,V14:?GLdouble,V15:?GLdouble,V16:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x3dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix2x3dv(Location,Transpose,Value) ->
- cast(5741, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5742, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x4dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix2x4dv(Location,Transpose,Value) ->
- cast(5742, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5743, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x2dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix3x2dv(Location,Transpose,Value) ->
- cast(5743, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5744, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x4dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3x4dv(Location,Transpose,Value) ->
- cast(5744, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5745, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x2dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x2dv(Location,Transpose,Value) ->
- cast(5745, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5746, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x3dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x3dv(Location,Transpose,Value) ->
- cast(5746, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5747, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link getUniformfv/2}
-spec getUniformdv(Program, Location) -> matrix() when Program :: integer(),Location :: integer().
getUniformdv(Program,Location) ->
- call(5747, <<Program:?GLuint,Location:?GLint>>).
+ call(5748, <<Program:?GLuint,Location:?GLint>>).
%% @doc Retrieve the location of a subroutine uniform of a given shader stage within a program
%%
@@ -15055,7 +15153,8 @@ getUniformdv(Program,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSubroutineUniformLocation.xml">external</a> documentation.
-spec getSubroutineUniformLocation(Program, Shadertype, Name) -> integer() when Program :: integer(),Shadertype :: enum(),Name :: string().
getSubroutineUniformLocation(Program,Shadertype,Name) ->
- call(5748, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5749, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Retrieve the index of a subroutine uniform of a given shader stage within a program
%%
@@ -15075,7 +15174,8 @@ getSubroutineUniformLocation(Program,Shadertype,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSubroutineIndex.xml">external</a> documentation.
-spec getSubroutineIndex(Program, Shadertype, Name) -> integer() when Program :: integer(),Shadertype :: enum(),Name :: string().
getSubroutineIndex(Program,Shadertype,Name) ->
- call(5749, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5750, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Query the name of an active shader subroutine uniform
%%
@@ -15096,7 +15196,7 @@ getSubroutineIndex(Program,Shadertype,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveSubroutineUniformName.xml">external</a> documentation.
-spec getActiveSubroutineUniformName(Program, Shadertype, Index, Bufsize) -> string() when Program :: integer(),Shadertype :: enum(),Index :: integer(),Bufsize :: integer().
getActiveSubroutineUniformName(Program,Shadertype,Index,Bufsize) ->
- call(5750, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
+ call(5751, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
%% @doc Query the name of an active shader subroutine
%%
@@ -15114,7 +15214,7 @@ getActiveSubroutineUniformName(Program,Shadertype,Index,Bufsize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveSubroutineName.xml">external</a> documentation.
-spec getActiveSubroutineName(Program, Shadertype, Index, Bufsize) -> string() when Program :: integer(),Shadertype :: enum(),Index :: integer(),Bufsize :: integer().
getActiveSubroutineName(Program,Shadertype,Index,Bufsize) ->
- call(5751, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
+ call(5752, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
%% @doc Load active subroutine uniforms
%%
@@ -15128,8 +15228,9 @@ getActiveSubroutineName(Program,Shadertype,Index,Bufsize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUniformSubroutines.xml">external</a> documentation.
-spec uniformSubroutinesuiv(Shadertype, Indices) -> 'ok' when Shadertype :: enum(),Indices :: [integer()].
uniformSubroutinesuiv(Shadertype,Indices) ->
- cast(5752, <<Shadertype:?GLenum,(length(Indices)):?GLuint,
- (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((length(Indices)) rem 2)*32)>>).
+ IndicesLen = length(Indices),
+ cast(5753, <<Shadertype:?GLenum,IndicesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((IndicesLen) rem 2)*32)>>).
%% @doc Retrieve the value of a subroutine uniform of a given shader stage of the current program
%%
@@ -15142,7 +15243,7 @@ uniformSubroutinesuiv(Shadertype,Indices) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformSubroutine.xml">external</a> documentation.
-spec getUniformSubroutineuiv(Shadertype, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when Shadertype :: enum(),Location :: integer().
getUniformSubroutineuiv(Shadertype,Location) ->
- call(5753, <<Shadertype:?GLenum,Location:?GLint>>).
+ call(5754, <<Shadertype:?GLenum,Location:?GLint>>).
%% @doc Retrieve properties of a program object corresponding to a specified shader stage
%%
@@ -15174,7 +15275,7 @@ getUniformSubroutineuiv(Shadertype,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramStage.xml">external</a> documentation.
-spec getProgramStageiv(Program, Shadertype, Pname) -> integer() when Program :: integer(),Shadertype :: enum(),Pname :: enum().
getProgramStageiv(Program,Shadertype,Pname) ->
- call(5754, <<Program:?GLuint,Shadertype:?GLenum,Pname:?GLenum>>).
+ call(5755, <<Program:?GLuint,Shadertype:?GLenum,Pname:?GLenum>>).
%% @doc Specifies the parameters for patch primitives
%%
@@ -15201,14 +15302,15 @@ getProgramStageiv(Program,Shadertype,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPatchParameter.xml">external</a> documentation.
-spec patchParameteri(Pname, Value) -> 'ok' when Pname :: enum(),Value :: integer().
patchParameteri(Pname,Value) ->
- cast(5755, <<Pname:?GLenum,Value:?GLint>>).
+ cast(5756, <<Pname:?GLenum,Value:?GLint>>).
%% @doc
%% See {@link patchParameteri/2}
-spec patchParameterfv(Pname, Values) -> 'ok' when Pname :: enum(),Values :: [float()].
patchParameterfv(Pname,Values) ->
- cast(5756, <<Pname:?GLenum,(length(Values)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Values>>)/binary,0:(((length(Values)) rem 2)*32)>>).
+ ValuesLen = length(Values),
+ cast(5757, <<Pname:?GLenum,ValuesLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Values>>)/binary,0:(((ValuesLen) rem 2)*32)>>).
%% @doc Bind a transform feedback object
%%
@@ -15231,7 +15333,7 @@ patchParameterfv(Pname,Values) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindTransformFeedback.xml">external</a> documentation.
-spec bindTransformFeedback(Target, Id) -> 'ok' when Target :: enum(),Id :: integer().
bindTransformFeedback(Target,Id) ->
- cast(5757, <<Target:?GLenum,Id:?GLuint>>).
+ cast(5758, <<Target:?GLenum,Id:?GLuint>>).
%% @doc Delete transform feedback objects
%%
@@ -15244,8 +15346,9 @@ bindTransformFeedback(Target,Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteTransformFeedbacks.xml">external</a> documentation.
-spec deleteTransformFeedbacks(Ids) -> 'ok' when Ids :: [integer()].
deleteTransformFeedbacks(Ids) ->
- cast(5758, <<(length(Ids)):?GLuint,
- (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+length(Ids)) rem 2)*32)>>).
+ IdsLen = length(Ids),
+ cast(5759, <<IdsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+IdsLen) rem 2)*32)>>).
%% @doc Reserve transform feedback object names
%%
@@ -15256,7 +15359,7 @@ deleteTransformFeedbacks(Ids) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenTransformFeedbacks.xml">external</a> documentation.
-spec genTransformFeedbacks(N) -> [integer()] when N :: integer().
genTransformFeedbacks(N) ->
- call(5759, <<N:?GLsizei>>).
+ call(5760, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a transform feedback object
%%
@@ -15271,7 +15374,7 @@ genTransformFeedbacks(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsTransformFeedback.xml">external</a> documentation.
-spec isTransformFeedback(Id) -> 0|1 when Id :: integer().
isTransformFeedback(Id) ->
- call(5760, <<Id:?GLuint>>).
+ call(5761, <<Id:?GLuint>>).
%% @doc Pause transform feedback operations
%%
@@ -15284,7 +15387,7 @@ isTransformFeedback(Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPauseTransformFeedback.xml">external</a> documentation.
-spec pauseTransformFeedback() -> 'ok'.
pauseTransformFeedback() ->
- cast(5761, <<>>).
+ cast(5762, <<>>).
%% @doc Resume transform feedback operations
%%
@@ -15297,7 +15400,7 @@ pauseTransformFeedback() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glResumeTransformFeedback.xml">external</a> documentation.
-spec resumeTransformFeedback() -> 'ok'.
resumeTransformFeedback() ->
- cast(5762, <<>>).
+ cast(5763, <<>>).
%% @doc Render primitives using a count derived from a transform feedback object
%%
@@ -15311,7 +15414,7 @@ resumeTransformFeedback() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedback.xml">external</a> documentation.
-spec drawTransformFeedback(Mode, Id) -> 'ok' when Mode :: enum(),Id :: integer().
drawTransformFeedback(Mode,Id) ->
- cast(5763, <<Mode:?GLenum,Id:?GLuint>>).
+ cast(5764, <<Mode:?GLenum,Id:?GLuint>>).
%% @doc Render primitives using a count derived from a specifed stream of a transform feedback object
%%
@@ -15329,14 +15432,14 @@ drawTransformFeedback(Mode,Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedbackStream.xml">external</a> documentation.
-spec drawTransformFeedbackStream(Mode, Id, Stream) -> 'ok' when Mode :: enum(),Id :: integer(),Stream :: integer().
drawTransformFeedbackStream(Mode,Id,Stream) ->
- cast(5764, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint>>).
+ cast(5765, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint>>).
%% @doc glBeginQueryIndexe
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginQueryIndexe.xml">external</a> documentation.
-spec beginQueryIndexed(Target, Index, Id) -> 'ok' when Target :: enum(),Index :: integer(),Id :: integer().
beginQueryIndexed(Target,Index,Id) ->
- cast(5765, <<Target:?GLenum,Index:?GLuint,Id:?GLuint>>).
+ cast(5766, <<Target:?GLenum,Index:?GLuint,Id:?GLuint>>).
%% @doc Delimit the boundaries of a query object on an indexed target
%%
@@ -15413,7 +15516,7 @@ beginQueryIndexed(Target,Index,Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginQueryIndexed.xml">external</a> documentation.
-spec endQueryIndexed(Target, Index) -> 'ok' when Target :: enum(),Index :: integer().
endQueryIndexed(Target,Index) ->
- cast(5766, <<Target:?GLenum,Index:?GLuint>>).
+ cast(5767, <<Target:?GLenum,Index:?GLuint>>).
%% @doc Return parameters of an indexed query object target
%%
@@ -15431,7 +15534,7 @@ endQueryIndexed(Target,Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryIndexed.xml">external</a> documentation.
-spec getQueryIndexediv(Target, Index, Pname) -> integer() when Target :: enum(),Index :: integer(),Pname :: enum().
getQueryIndexediv(Target,Index,Pname) ->
- call(5767, <<Target:?GLenum,Index:?GLuint,Pname:?GLenum>>).
+ call(5768, <<Target:?GLenum,Index:?GLuint,Pname:?GLenum>>).
%% @doc Release resources consumed by the implementation's shader compiler
%%
@@ -15443,7 +15546,7 @@ getQueryIndexediv(Target,Index,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glReleaseShaderCompiler.xml">external</a> documentation.
-spec releaseShaderCompiler() -> 'ok'.
releaseShaderCompiler() ->
- cast(5768, <<>>).
+ cast(5769, <<>>).
%% @doc Load pre-compiled shader binaries
%%
@@ -15465,9 +15568,10 @@ releaseShaderCompiler() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderBinary.xml">external</a> documentation.
-spec shaderBinary(Shaders, Binaryformat, Binary) -> 'ok' when Shaders :: [integer()],Binaryformat :: enum(),Binary :: binary().
shaderBinary(Shaders,Binaryformat,Binary) ->
+ ShadersLen = length(Shaders),
send_bin(Binary),
- cast(5769, <<(length(Shaders)):?GLuint,
- (<< <<C:?GLuint>> || C <- Shaders>>)/binary,0:(((1+length(Shaders)) rem 2)*32),Binaryformat:?GLenum>>).
+ cast(5770, <<ShadersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Shaders>>)/binary,0:(((1+ShadersLen) rem 2)*32),Binaryformat:?GLenum>>).
%% @doc Retrieve the range and precision for numeric formats supported by the shader compiler
%%
@@ -15492,20 +15596,20 @@ shaderBinary(Shaders,Binaryformat,Binary) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderPrecisionFormat.xml">external</a> documentation.
-spec getShaderPrecisionFormat(Shadertype, Precisiontype) -> {Range :: {integer(),integer()},Precision :: integer()} when Shadertype :: enum(),Precisiontype :: enum().
getShaderPrecisionFormat(Shadertype,Precisiontype) ->
- call(5770, <<Shadertype:?GLenum,Precisiontype:?GLenum>>).
+ call(5771, <<Shadertype:?GLenum,Precisiontype:?GLenum>>).
%% @doc
%% See {@link depthRange/2}
-spec depthRangef(N, F) -> 'ok' when N :: clamp(),F :: clamp().
depthRangef(N,F) ->
- cast(5771, <<N:?GLclampf,F:?GLclampf>>).
+ cast(5772, <<N:?GLclampf,F:?GLclampf>>).
%% @doc glClearDepthf
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearDepthf.xml">external</a> documentation.
-spec clearDepthf(D) -> 'ok' when D :: clamp().
clearDepthf(D) ->
- cast(5772, <<D:?GLclampf>>).
+ cast(5773, <<D:?GLclampf>>).
%% @doc Return a binary representation of a program object's compiled and linked executable source
%%
@@ -15526,7 +15630,7 @@ clearDepthf(D) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramBinary.xml">external</a> documentation.
-spec getProgramBinary(Program, BufSize) -> {BinaryFormat :: enum(),Binary :: binary()} when Program :: integer(),BufSize :: integer().
getProgramBinary(Program,BufSize) ->
- call(5773, <<Program:?GLuint,BufSize:?GLsizei>>).
+ call(5774, <<Program:?GLuint,BufSize:?GLsizei>>).
%% @doc Load a program object with a program binary
%%
@@ -15554,7 +15658,7 @@ getProgramBinary(Program,BufSize) ->
-spec programBinary(Program, BinaryFormat, Binary) -> 'ok' when Program :: integer(),BinaryFormat :: enum(),Binary :: binary().
programBinary(Program,BinaryFormat,Binary) ->
send_bin(Binary),
- cast(5774, <<Program:?GLuint,BinaryFormat:?GLenum>>).
+ cast(5775, <<Program:?GLuint,BinaryFormat:?GLenum>>).
%% @doc Specify a parameter for a program object
%%
@@ -15579,7 +15683,7 @@ programBinary(Program,BinaryFormat,Binary) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramParameter.xml">external</a> documentation.
-spec programParameteri(Program, Pname, Value) -> 'ok' when Program :: integer(),Pname :: enum(),Value :: integer().
programParameteri(Program,Pname,Value) ->
- cast(5775, <<Program:?GLuint,Pname:?GLenum,Value:?GLint>>).
+ cast(5776, <<Program:?GLuint,Pname:?GLenum,Value:?GLint>>).
%% @doc Bind stages of a program object to a program pipeline
%%
@@ -15604,7 +15708,7 @@ programParameteri(Program,Pname,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUseProgramStages.xml">external</a> documentation.
-spec useProgramStages(Pipeline, Stages, Program) -> 'ok' when Pipeline :: integer(),Stages :: integer(),Program :: integer().
useProgramStages(Pipeline,Stages,Program) ->
- cast(5776, <<Pipeline:?GLuint,Stages:?GLbitfield,Program:?GLuint>>).
+ cast(5777, <<Pipeline:?GLuint,Stages:?GLbitfield,Program:?GLuint>>).
%% @doc Set the active program object for a program pipeline object
%%
@@ -15616,15 +15720,16 @@ useProgramStages(Pipeline,Stages,Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glActiveShaderProgram.xml">external</a> documentation.
-spec activeShaderProgram(Pipeline, Program) -> 'ok' when Pipeline :: integer(),Program :: integer().
activeShaderProgram(Pipeline,Program) ->
- cast(5777, <<Pipeline:?GLuint,Program:?GLuint>>).
+ cast(5778, <<Pipeline:?GLuint,Program:?GLuint>>).
%% @doc glCreateShaderProgramv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShaderProgramv.xml">external</a> documentation.
-spec createShaderProgramv(Type, Strings) -> integer() when Type :: enum(),Strings :: iolist().
createShaderProgramv(Type,Strings) ->
- StringsTemp = list_to_binary([[Str|[0]] || Str <- Strings ]),
- call(5778, <<Type:?GLenum,(length(Strings)):?GLuint,(size(StringsTemp)):?GLuint,(StringsTemp)/binary,0:((8-((size(StringsTemp)+0) rem 8)) rem 8)>>).
+ StringsTemp = list_to_binary([[Str|[0]] || Str <- Strings ]),
+ StringsLen = length(Strings),
+ call(5779, <<Type:?GLenum,StringsLen:?GLuint,(size(StringsTemp)):?GLuint,(StringsTemp)/binary,0:((8-((size(StringsTemp)+0) rem 8)) rem 8)>>).
%% @doc Bind a program pipeline to the current context
%%
@@ -15646,7 +15751,7 @@ createShaderProgramv(Type,Strings) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindProgramPipeline.xml">external</a> documentation.
-spec bindProgramPipeline(Pipeline) -> 'ok' when Pipeline :: integer().
bindProgramPipeline(Pipeline) ->
- cast(5779, <<Pipeline:?GLuint>>).
+ cast(5780, <<Pipeline:?GLuint>>).
%% @doc Delete program pipeline objects
%%
@@ -15660,8 +15765,9 @@ bindProgramPipeline(Pipeline) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteProgramPipelines.xml">external</a> documentation.
-spec deleteProgramPipelines(Pipelines) -> 'ok' when Pipelines :: [integer()].
deleteProgramPipelines(Pipelines) ->
- cast(5780, <<(length(Pipelines)):?GLuint,
- (<< <<C:?GLuint>> || C <- Pipelines>>)/binary,0:(((1+length(Pipelines)) rem 2)*32)>>).
+ PipelinesLen = length(Pipelines),
+ cast(5781, <<PipelinesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Pipelines>>)/binary,0:(((1+PipelinesLen) rem 2)*32)>>).
%% @doc Reserve program pipeline object names
%%
@@ -15672,7 +15778,7 @@ deleteProgramPipelines(Pipelines) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenProgramPipelines.xml">external</a> documentation.
-spec genProgramPipelines(N) -> [integer()] when N :: integer().
genProgramPipelines(N) ->
- call(5781, <<N:?GLsizei>>).
+ call(5782, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a program pipeline object
%%
@@ -15687,7 +15793,7 @@ genProgramPipelines(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsProgramPipeline.xml">external</a> documentation.
-spec isProgramPipeline(Pipeline) -> 0|1 when Pipeline :: integer().
isProgramPipeline(Pipeline) ->
- call(5782, <<Pipeline:?GLuint>>).
+ call(5783, <<Pipeline:?GLuint>>).
%% @doc Retrieve properties of a program pipeline object
%%
@@ -15725,7 +15831,7 @@ isProgramPipeline(Pipeline) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramPipeline.xml">external</a> documentation.
-spec getProgramPipelineiv(Pipeline, Pname) -> integer() when Pipeline :: integer(),Pname :: enum().
getProgramPipelineiv(Pipeline,Pname) ->
- call(5783, <<Pipeline:?GLuint,Pname:?GLenum>>).
+ call(5784, <<Pipeline:?GLuint,Pname:?GLenum>>).
%% @doc Specify the value of a uniform variable for a specified program object
%%
@@ -15792,334 +15898,368 @@ getProgramPipelineiv(Pipeline,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramUniform.xml">external</a> documentation.
-spec programUniform1i(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer().
programUniform1i(Program,Location,V0) ->
- cast(5784, <<Program:?GLuint,Location:?GLint,V0:?GLint>>).
+ cast(5785, <<Program:?GLuint,Location:?GLint,V0:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [integer()].
programUniform1iv(Program,Location,Value) ->
- cast(5785, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((1+length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5786, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((1+ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1f(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float().
programUniform1f(Program,Location,V0) ->
- cast(5786, <<Program:?GLuint,Location:?GLint,V0:?GLfloat>>).
+ cast(5787, <<Program:?GLuint,Location:?GLint,V0:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [float()].
programUniform1fv(Program,Location,Value) ->
- cast(5787, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((1+length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5788, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((1+ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1d(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float().
programUniform1d(Program,Location,V0) ->
- cast(5788, <<Program:?GLuint,Location:?GLint,V0:?GLdouble>>).
+ cast(5789, <<Program:?GLuint,Location:?GLint,V0:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [float()].
programUniform1dv(Program,Location,Value) ->
- cast(5789, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5790, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<C:?GLdouble>> || C <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1ui(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer().
programUniform1ui(Program,Location,V0) ->
- cast(5790, <<Program:?GLuint,Location:?GLint,V0:?GLuint>>).
+ cast(5791, <<Program:?GLuint,Location:?GLint,V0:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [integer()].
programUniform1uiv(Program,Location,Value) ->
- cast(5791, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((1+length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5792, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((1+ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2i(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer().
programUniform2i(Program,Location,V0,V1) ->
- cast(5792, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint>>).
+ cast(5793, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer()}].
programUniform2iv(Program,Location,Value) ->
- cast(5793, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5794, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2f(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float().
programUniform2f(Program,Location,V0,V1) ->
- cast(5794, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
+ cast(5795, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float()}].
programUniform2fv(Program,Location,Value) ->
- cast(5795, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5796, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2d(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float().
programUniform2d(Program,Location,V0,V1) ->
- cast(5796, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble>>).
+ cast(5797, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float()}].
programUniform2dv(Program,Location,Value) ->
- cast(5797, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5798, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2ui(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer().
programUniform2ui(Program,Location,V0,V1) ->
- cast(5798, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint>>).
+ cast(5799, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer()}].
programUniform2uiv(Program,Location,Value) ->
- cast(5799, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5800, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3i(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
programUniform3i(Program,Location,V0,V1,V2) ->
- cast(5800, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
+ cast(5801, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer()}].
programUniform3iv(Program,Location,Value) ->
- cast(5801, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5802, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3f(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float().
programUniform3f(Program,Location,V0,V1,V2) ->
- cast(5802, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
+ cast(5803, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float()}].
programUniform3fv(Program,Location,Value) ->
- cast(5803, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5804, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3d(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float().
programUniform3d(Program,Location,V0,V1,V2) ->
- cast(5804, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble>>).
+ cast(5805, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float()}].
programUniform3dv(Program,Location,Value) ->
- cast(5805, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5806, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3ui(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
programUniform3ui(Program,Location,V0,V1,V2) ->
- cast(5806, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
+ cast(5807, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer()}].
programUniform3uiv(Program,Location,Value) ->
- cast(5807, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5808, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4i(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
programUniform4i(Program,Location,V0,V1,V2,V3) ->
- cast(5808, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
+ cast(5809, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
programUniform4iv(Program,Location,Value) ->
- cast(5809, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5810, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4f(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float(),V3 :: float().
programUniform4f(Program,Location,V0,V1,V2,V3) ->
- cast(5810, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
+ cast(5811, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float(),float()}].
programUniform4fv(Program,Location,Value) ->
- cast(5811, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5812, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4d(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float(),V3 :: float().
programUniform4d(Program,Location,V0,V1,V2,V3) ->
- cast(5812, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>>).
+ cast(5813, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float(),float()}].
programUniform4dv(Program,Location,Value) ->
- cast(5813, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5814, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4ui(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
programUniform4ui(Program,Location,V0,V1,V2,V3) ->
- cast(5814, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
+ cast(5815, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
programUniform4uiv(Program,Location,Value) ->
- cast(5815, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5816, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
programUniformMatrix2fv(Program,Location,Transpose,Value) ->
- cast(5816, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5817, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3fv(Program,Location,Transpose,Value) ->
- cast(5817, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5818, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4fv(Program,Location,Transpose,Value) ->
- cast(5818, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5819, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat,V13:?GLfloat,V14:?GLfloat,V15:?GLfloat,V16:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
programUniformMatrix2dv(Program,Location,Transpose,Value) ->
- cast(5819, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5820, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3dv(Program,Location,Transpose,Value) ->
- cast(5820, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5821, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4dv(Program,Location,Transpose,Value) ->
- cast(5821, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5822, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble,V13:?GLdouble,V14:?GLdouble,V15:?GLdouble,V16:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x3fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x3fv(Program,Location,Transpose,Value) ->
- cast(5822, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5823, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x2fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x2fv(Program,Location,Transpose,Value) ->
- cast(5823, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5824, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x4fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x4fv(Program,Location,Transpose,Value) ->
- cast(5824, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5825, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x2fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x2fv(Program,Location,Transpose,Value) ->
- cast(5825, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5826, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x4fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x4fv(Program,Location,Transpose,Value) ->
- cast(5826, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5827, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x3fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x3fv(Program,Location,Transpose,Value) ->
- cast(5827, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5828, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x3dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x3dv(Program,Location,Transpose,Value) ->
- cast(5828, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5829, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x2dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x2dv(Program,Location,Transpose,Value) ->
- cast(5829, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5830, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x4dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x4dv(Program,Location,Transpose,Value) ->
- cast(5830, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5831, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x2dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x2dv(Program,Location,Transpose,Value) ->
- cast(5831, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5832, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x4dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x4dv(Program,Location,Transpose,Value) ->
- cast(5832, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5833, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x3dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x3dv(Program,Location,Transpose,Value) ->
- cast(5833, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5834, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc Validate a program pipeline object against current GL state
@@ -16140,7 +16280,7 @@ programUniformMatrix4x3dv(Program,Location,Transpose,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgramPipeline.xml">external</a> documentation.
-spec validateProgramPipeline(Pipeline) -> 'ok' when Pipeline :: integer().
validateProgramPipeline(Pipeline) ->
- cast(5834, <<Pipeline:?GLuint>>).
+ cast(5835, <<Pipeline:?GLuint>>).
%% @doc Retrieve the info log string from a program pipeline object
%%
@@ -16157,35 +16297,35 @@ validateProgramPipeline(Pipeline) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramPipelineInfoLog.xml">external</a> documentation.
-spec getProgramPipelineInfoLog(Pipeline, BufSize) -> string() when Pipeline :: integer(),BufSize :: integer().
getProgramPipelineInfoLog(Pipeline,BufSize) ->
- call(5835, <<Pipeline:?GLuint,BufSize:?GLsizei>>).
+ call(5836, <<Pipeline:?GLuint,BufSize:?GLsizei>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL1d(Index, X) -> 'ok' when Index :: integer(),X :: float().
vertexAttribL1d(Index,X) ->
- cast(5836, <<Index:?GLuint,0:32,X:?GLdouble>>).
+ cast(5837, <<Index:?GLuint,0:32,X:?GLdouble>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL2d(Index, X, Y) -> 'ok' when Index :: integer(),X :: float(),Y :: float().
vertexAttribL2d(Index,X,Y) ->
- cast(5837, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
+ cast(5838, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL3d(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float().
vertexAttribL3d(Index,X,Y,Z) ->
- cast(5838, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5839, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL4d(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
vertexAttribL4d(Index,X,Y,Z,W) ->
- cast(5839, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5840, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @equiv vertexAttribL1d(Index,X)
-spec vertexAttribL1dv(Index :: integer(),V) -> 'ok' when V :: {X :: float()}.
@@ -16208,24 +16348,25 @@ vertexAttribL4dv(Index,{X,Y,Z,W}) -> vertexAttribL4d(Index,X,Y,Z,W).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribLPointer.xml">external</a> documentation.
-spec vertexAttribLPointer(Index, Size, Type, Stride, Pointer) -> 'ok' when Index :: integer(),Size :: integer(),Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
vertexAttribLPointer(Index,Size,Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5840, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5841, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
vertexAttribLPointer(Index,Size,Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5841, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
+ cast(5842, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
%% @doc glGetVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetVertexAttribL.xml">external</a> documentation.
-spec getVertexAttribLdv(Index, Pname) -> {float(),float(),float(),float()} when Index :: integer(),Pname :: enum().
getVertexAttribLdv(Index,Pname) ->
- call(5842, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5843, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc glViewportArrayv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glViewportArrayv.xml">external</a> documentation.
-spec viewportArrayv(First, V) -> 'ok' when First :: integer(),V :: [{float(),float(),float(),float()}].
viewportArrayv(First,V) ->
- cast(5843, <<First:?GLuint,(length(V)):?GLuint,
+ VLen = length(V),
+ cast(5844, <<First:?GLuint,VLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- V>>)/binary>>).
%% @doc Set a specified viewport
@@ -16265,20 +16406,21 @@ viewportArrayv(First,V) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glViewportIndexed.xml">external</a> documentation.
-spec viewportIndexedf(Index, X, Y, W, H) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),W :: float(),H :: float().
viewportIndexedf(Index,X,Y,W,H) ->
- cast(5844, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,W:?GLfloat,H:?GLfloat>>).
+ cast(5845, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,W:?GLfloat,H:?GLfloat>>).
%% @doc
%% See {@link viewportIndexedf/5}
-spec viewportIndexedfv(Index, V) -> 'ok' when Index :: integer(),V :: {float(),float(),float(),float()}.
viewportIndexedfv(Index,{V1,V2,V3,V4}) ->
- cast(5845, <<Index:?GLuint,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>>).
+ cast(5846, <<Index:?GLuint,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>>).
%% @doc glScissorArrayv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glScissorArrayv.xml">external</a> documentation.
-spec scissorArrayv(First, V) -> 'ok' when First :: integer(),V :: [{integer(),integer(),integer(),integer()}].
scissorArrayv(First,V) ->
- cast(5846, <<First:?GLuint,(length(V)):?GLuint,
+ VLen = length(V),
+ cast(5847, <<First:?GLuint,VLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>> || {V1,V2,V3,V4} <- V>>)/binary>>).
%% @doc glScissorIndexe
@@ -16286,21 +16428,22 @@ scissorArrayv(First,V) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glScissorIndexe.xml">external</a> documentation.
-spec scissorIndexed(Index, Left, Bottom, Width, Height) -> 'ok' when Index :: integer(),Left :: integer(),Bottom :: integer(),Width :: integer(),Height :: integer().
scissorIndexed(Index,Left,Bottom,Width,Height) ->
- cast(5847, <<Index:?GLuint,Left:?GLint,Bottom:?GLint,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5848, <<Index:?GLuint,Left:?GLint,Bottom:?GLint,Width:?GLsizei,Height:?GLsizei>>).
%% @doc glScissorIndexe
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glScissorIndexe.xml">external</a> documentation.
-spec scissorIndexedv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
scissorIndexedv(Index,{V1,V2,V3,V4}) ->
- cast(5848, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
+ cast(5849, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
%% @doc glDepthRangeArrayv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDepthRangeArrayv.xml">external</a> documentation.
-spec depthRangeArrayv(First, V) -> 'ok' when First :: integer(),V :: [{clamp(),clamp()}].
depthRangeArrayv(First,V) ->
- cast(5849, <<First:?GLuint,0:32,(length(V)):?GLuint,0:32,
+ VLen = length(V),
+ cast(5850, <<First:?GLuint,0:32,VLen:?GLuint,0:32,
(<< <<V1:?GLclampd,V2:?GLclampd>> || {V1,V2} <- V>>)/binary>>).
%% @doc glDepthRangeIndexe
@@ -16308,48 +16451,50 @@ depthRangeArrayv(First,V) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDepthRangeIndexe.xml">external</a> documentation.
-spec depthRangeIndexed(Index, N, F) -> 'ok' when Index :: integer(),N :: clamp(),F :: clamp().
depthRangeIndexed(Index,N,F) ->
- cast(5850, <<Index:?GLuint,0:32,N:?GLclampd,F:?GLclampd>>).
+ cast(5851, <<Index:?GLuint,0:32,N:?GLclampd,F:?GLclampd>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getFloati_v(Target, Index) -> [float()] when Target :: enum(),Index :: integer().
getFloati_v(Target,Index) ->
- call(5851, <<Target:?GLenum,Index:?GLuint>>).
+ call(5852, <<Target:?GLenum,Index:?GLuint>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getDoublei_v(Target, Index) -> [float()] when Target :: enum(),Index :: integer().
getDoublei_v(Target,Index) ->
- call(5852, <<Target:?GLenum,Index:?GLuint>>).
+ call(5853, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glDebugMessageControlARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDebugMessageControlARB.xml">external</a> documentation.
-spec debugMessageControlARB(Source, Type, Severity, Ids, Enabled) -> 'ok' when Source :: enum(),Type :: enum(),Severity :: enum(),Ids :: [integer()],Enabled :: 0|1.
debugMessageControlARB(Source,Type,Severity,Ids,Enabled) ->
- cast(5853, <<Source:?GLenum,Type:?GLenum,Severity:?GLenum,(length(Ids)):?GLuint,
- (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((length(Ids)) rem 2)*32),Enabled:?GLboolean>>).
+ IdsLen = length(Ids),
+ cast(5854, <<Source:?GLenum,Type:?GLenum,Severity:?GLenum,IdsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((IdsLen) rem 2)*32),Enabled:?GLboolean>>).
%% @doc glDebugMessageInsertARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDebugMessageInsertARB.xml">external</a> documentation.
-spec debugMessageInsertARB(Source, Type, Id, Severity, Buf) -> 'ok' when Source :: enum(),Type :: enum(),Id :: integer(),Severity :: enum(),Buf :: string().
debugMessageInsertARB(Source,Type,Id,Severity,Buf) ->
- cast(5854, <<Source:?GLenum,Type:?GLenum,Id:?GLuint,Severity:?GLenum,(list_to_binary([Buf|[0]]))/binary,0:((8-((length(Buf)+ 1) rem 8)) rem 8)>>).
+ BufLen = length(Buf),
+ cast(5855, <<Source:?GLenum,Type:?GLenum,Id:?GLuint,Severity:?GLenum,(list_to_binary([Buf|[0]]))/binary,0:((8-((BufLen+ 1) rem 8)) rem 8)>>).
%% @doc glGetDebugMessageLogARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetDebugMessageLogARB.xml">external</a> documentation.
-spec getDebugMessageLogARB(Count, Bufsize) -> {integer(),Sources :: [enum()],Types :: [enum()],Ids :: [integer()],Severities :: [enum()],MessageLog :: [string()]} when Count :: integer(),Bufsize :: integer().
getDebugMessageLogARB(Count,Bufsize) ->
- call(5855, <<Count:?GLuint,Bufsize:?GLsizei>>).
+ call(5856, <<Count:?GLuint,Bufsize:?GLsizei>>).
%% @doc glGetGraphicsResetStatusARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetGraphicsResetStatusARB.xml">external</a> documentation.
-spec getGraphicsResetStatusARB() -> enum().
getGraphicsResetStatusARB() ->
- call(5856, <<>>).
+ call(5857, <<>>).
%% @doc Draw multiple instances of a range of elements with offset applied to instanced attributes
%%
@@ -16372,7 +16517,7 @@ getGraphicsResetStatusARB() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawArraysInstancedBaseInstance.xml">external</a> documentation.
-spec drawArraysInstancedBaseInstance(Mode, First, Count, Primcount, Baseinstance) -> 'ok' when Mode :: enum(),First :: integer(),Count :: integer(),Primcount :: integer(),Baseinstance :: integer().
drawArraysInstancedBaseInstance(Mode,First,Count,Primcount,Baseinstance) ->
- cast(5857, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei,Baseinstance:?GLuint>>).
+ cast(5858, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei,Baseinstance:?GLuint>>).
%% @doc Draw multiple instances of a set of elements with offset applied to instanced attributes
%%
@@ -16395,10 +16540,10 @@ drawArraysInstancedBaseInstance(Mode,First,Count,Primcount,Baseinstance) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstancedBaseInstance.xml">external</a> documentation.
-spec drawElementsInstancedBaseInstance(Mode, Count, Type, Indices, Primcount, Baseinstance) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer(),Baseinstance :: integer().
drawElementsInstancedBaseInstance(Mode,Count,Type,Indices,Primcount,Baseinstance) when is_integer(Indices) ->
- cast(5858, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Baseinstance:?GLuint>>);
+ cast(5859, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Baseinstance:?GLuint>>);
drawElementsInstancedBaseInstance(Mode,Count,Type,Indices,Primcount,Baseinstance) ->
send_bin(Indices),
- cast(5859, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Baseinstance:?GLuint>>).
+ cast(5860, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Baseinstance:?GLuint>>).
%% @doc Render multiple instances of a set of primitives from array data with a per-element offset
%%
@@ -16419,31 +16564,31 @@ drawElementsInstancedBaseInstance(Mode,Count,Type,Indices,Primcount,Baseinstance
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstancedBaseVertexBaseInstance.xml">external</a> documentation.
-spec drawElementsInstancedBaseVertexBaseInstance(Mode, Count, Type, Indices, Primcount, Basevertex, Baseinstance) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer(),Basevertex :: integer(),Baseinstance :: integer().
drawElementsInstancedBaseVertexBaseInstance(Mode,Count,Type,Indices,Primcount,Basevertex,Baseinstance) when is_integer(Indices) ->
- cast(5860, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>);
+ cast(5861, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>);
drawElementsInstancedBaseVertexBaseInstance(Mode,Count,Type,Indices,Primcount,Basevertex,Baseinstance) ->
send_bin(Indices),
- cast(5861, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>).
+ cast(5862, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>).
%% @doc glDrawTransformFeedbackInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedbackInstance.xml">external</a> documentation.
-spec drawTransformFeedbackInstanced(Mode, Id, Primcount) -> 'ok' when Mode :: enum(),Id :: integer(),Primcount :: integer().
drawTransformFeedbackInstanced(Mode,Id,Primcount) ->
- cast(5862, <<Mode:?GLenum,Id:?GLuint,Primcount:?GLsizei>>).
+ cast(5863, <<Mode:?GLenum,Id:?GLuint,Primcount:?GLsizei>>).
%% @doc glDrawTransformFeedbackStreamInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedbackStreamInstance.xml">external</a> documentation.
-spec drawTransformFeedbackStreamInstanced(Mode, Id, Stream, Primcount) -> 'ok' when Mode :: enum(),Id :: integer(),Stream :: integer(),Primcount :: integer().
drawTransformFeedbackStreamInstanced(Mode,Id,Stream,Primcount) ->
- cast(5863, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint,Primcount:?GLsizei>>).
+ cast(5864, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint,Primcount:?GLsizei>>).
%% @doc glGetInternalformat
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetInternalformat.xml">external</a> documentation.
-spec getInternalformativ(Target, Internalformat, Pname, BufSize) -> [integer()] when Target :: enum(),Internalformat :: enum(),Pname :: enum(),BufSize :: integer().
getInternalformativ(Target,Internalformat,Pname,BufSize) ->
- call(5864, <<Target:?GLenum,Internalformat:?GLenum,Pname:?GLenum,BufSize:?GLsizei>>).
+ call(5865, <<Target:?GLenum,Internalformat:?GLenum,Pname:?GLenum,BufSize:?GLsizei>>).
%% @doc Bind a level of a texture to an image unit
%%
@@ -16505,7 +16650,7 @@ getInternalformativ(Target,Internalformat,Pname,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindImageTexture.xml">external</a> documentation.
-spec bindImageTexture(Unit, Texture, Level, Layered, Layer, Access, Format) -> 'ok' when Unit :: integer(),Texture :: integer(),Level :: integer(),Layered :: 0|1,Layer :: integer(),Access :: enum(),Format :: enum().
bindImageTexture(Unit,Texture,Level,Layered,Layer,Access,Format) ->
- cast(5865, <<Unit:?GLuint,Texture:?GLuint,Level:?GLint,Layered:?GLboolean,0:24,Layer:?GLint,Access:?GLenum,Format:?GLenum>>).
+ cast(5866, <<Unit:?GLuint,Texture:?GLuint,Level:?GLint,Layered:?GLboolean,0:24,Layer:?GLint,Access:?GLenum,Format:?GLenum>>).
%% @doc Defines a barrier ordering memory transactions
%%
@@ -16632,7 +16777,7 @@ bindImageTexture(Unit,Texture,Level,Layered,Layer,Access,Format) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMemoryBarrier.xml">external</a> documentation.
-spec memoryBarrier(Barriers) -> 'ok' when Barriers :: integer().
memoryBarrier(Barriers) ->
- cast(5866, <<Barriers:?GLbitfield>>).
+ cast(5867, <<Barriers:?GLbitfield>>).
%% @doc Simultaneously specify storage for all levels of a one-dimensional texture
%%
@@ -16665,7 +16810,7 @@ memoryBarrier(Barriers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexStorage1D.xml">external</a> documentation.
-spec texStorage1D(Target, Levels, Internalformat, Width) -> 'ok' when Target :: enum(),Levels :: integer(),Internalformat :: enum(),Width :: integer().
texStorage1D(Target,Levels,Internalformat,Width) ->
- cast(5867, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei>>).
+ cast(5868, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei>>).
%% @doc Simultaneously specify storage for all levels of a two-dimensional or one-dimensional array texture
%%
@@ -16710,7 +16855,7 @@ texStorage1D(Target,Levels,Internalformat,Width) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexStorage2D.xml">external</a> documentation.
-spec texStorage2D(Target, Levels, Internalformat, Width, Height) -> 'ok' when Target :: enum(),Levels :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer().
texStorage2D(Target,Levels,Internalformat,Width,Height) ->
- cast(5868, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5869, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
%% @doc Simultaneously specify storage for all levels of a three-dimensional, two-dimensional array or cube-map array texture
%%
@@ -16753,19 +16898,19 @@ texStorage2D(Target,Levels,Internalformat,Width,Height) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexStorage3D.xml">external</a> documentation.
-spec texStorage3D(Target, Levels, Internalformat, Width, Height, Depth) -> 'ok' when Target :: enum(),Levels :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer(),Depth :: integer().
texStorage3D(Target,Levels,Internalformat,Width,Height,Depth) ->
- cast(5869, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei>>).
+ cast(5870, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei>>).
%% @doc glDepthBoundsEXT
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDepthBoundsEXT.xml">external</a> documentation.
-spec depthBoundsEXT(Zmin, Zmax) -> 'ok' when Zmin :: clamp(),Zmax :: clamp().
depthBoundsEXT(Zmin,Zmax) ->
- cast(5870, <<Zmin:?GLclampd,Zmax:?GLclampd>>).
+ cast(5871, <<Zmin:?GLclampd,Zmax:?GLclampd>>).
%% @doc glStencilClearTagEXT
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilClearTagEXT.xml">external</a> documentation.
-spec stencilClearTagEXT(StencilTagBits, StencilClearTag) -> 'ok' when StencilTagBits :: integer(),StencilClearTag :: integer().
stencilClearTagEXT(StencilTagBits,StencilClearTag) ->
- cast(5871, <<StencilTagBits:?GLsizei,StencilClearTag:?GLuint>>).
+ cast(5872, <<StencilTagBits:?GLsizei,StencilClearTag:?GLuint>>).
diff --git a/lib/wx/src/gen/glu.erl b/lib/wx/src/gen/glu.erl
index 47d9a83999..f641f41262 100644
--- a/lib/wx/src/gen/glu.erl
+++ b/lib/wx/src/gen/glu.erl
@@ -334,7 +334,9 @@ build3DMipmaps(Target,InternalFormat,Width,Height,Depth,Format,Type,Data) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/gluCheckExtension.xml">external</a> documentation.
-spec checkExtension(ExtName, ExtString) -> 0|1 when ExtName :: string(),ExtString :: string().
checkExtension(ExtName,ExtString) ->
- call(5016, <<(list_to_binary([ExtName|[0]]))/binary,0:((8-((length(ExtName)+ 1) rem 8)) rem 8),(list_to_binary([ExtString|[0]]))/binary,0:((8-((length(ExtString)+ 1) rem 8)) rem 8)>>).
+ ExtNameLen = length(ExtName),
+ ExtStringLen = length(ExtString),
+ call(5016, <<(list_to_binary([ExtName|[0]]))/binary,0:((8-((ExtNameLen+ 1) rem 8)) rem 8),(list_to_binary([ExtString|[0]]))/binary,0:((8-((ExtStringLen+ 1) rem 8)) rem 8)>>).
%% @doc Draw a cylinder
%%
diff --git a/lib/wx/src/gen/wxArtProvider.erl b/lib/wx/src/gen/wxArtProvider.erl
index da220a90c8..b52c141b1f 100644
--- a/lib/wx/src/gen/wxArtProvider.erl
+++ b/lib/wx/src/gen/wxArtProvider.erl
@@ -40,7 +40,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
Id::unicode:chardata().
getBitmap(Id)
- when is_list(Id) ->
+ when ?is_chardata(Id) ->
getBitmap(Id, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxartprovider.html#wxartprovidergetbitmap">external documentation</a>.
@@ -49,7 +49,7 @@ getBitmap(Id)
Option :: {'client', unicode:chardata()}
| {'size', {W::integer(), H::integer()}}.
getBitmap(Id, Options)
- when is_list(Id),is_list(Options) ->
+ when ?is_chardata(Id),is_list(Options) ->
Id_UC = unicode:characters_to_binary([Id,0]),
MOpts = fun({client, Client}, Acc) -> Client_UC = unicode:characters_to_binary([Client, $_, $C,0]),[<<1:32/?UI,(byte_size(Client_UC)):32/?UI,(Client_UC)/binary, 0:(((8- ((0+byte_size(Client_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
({size, {SizeW,SizeH}}, Acc) -> [<<2:32/?UI,SizeW:32/?UI,SizeH:32/?UI,0:32>>|Acc];
@@ -63,7 +63,7 @@ getBitmap(Id, Options)
Id::unicode:chardata().
getIcon(Id)
- when is_list(Id) ->
+ when ?is_chardata(Id) ->
getIcon(Id, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxartprovider.html#wxartprovidergeticon">external documentation</a>.
@@ -72,7 +72,7 @@ getIcon(Id)
Option :: {'client', unicode:chardata()}
| {'size', {W::integer(), H::integer()}}.
getIcon(Id, Options)
- when is_list(Id),is_list(Options) ->
+ when ?is_chardata(Id),is_list(Options) ->
Id_UC = unicode:characters_to_binary([Id,0]),
MOpts = fun({client, Client}, Acc) -> Client_UC = unicode:characters_to_binary([Client, $_, $C,0]),[<<1:32/?UI,(byte_size(Client_UC)):32/?UI,(Client_UC)/binary, 0:(((8- ((0+byte_size(Client_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
({size, {SizeW,SizeH}}, Acc) -> [<<2:32/?UI,SizeW:32/?UI,SizeH:32/?UI,0:32>>|Acc];
diff --git a/lib/wx/src/gen/wxAuiManager.erl b/lib/wx/src/gen/wxAuiManager.erl
index 37693060e1..a33e5e9a65 100644
--- a/lib/wx/src/gen/wxAuiManager.erl
+++ b/lib/wx/src/gen/wxAuiManager.erl
@@ -177,7 +177,7 @@ getManager(#wx_ref{type=WindowT,ref=WindowRef}) ->
(This, Window) -> wxAuiPaneInfo:wxAuiPaneInfo() when
This::wxAuiManager(), Window::wxWindow:wxWindow().
getPane(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxAuiManager),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxAuiManager_GetPane_1_0,
@@ -223,7 +223,7 @@ insertPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#
-spec loadPaneInfo(This, Pane_part, Pane) -> 'ok' when
This::wxAuiManager(), Pane_part::unicode:chardata(), Pane::wxAuiPaneInfo:wxAuiPaneInfo().
loadPaneInfo(#wx_ref{type=ThisT,ref=ThisRef},Pane_part,#wx_ref{type=PaneT,ref=PaneRef})
- when is_list(Pane_part) ->
+ when ?is_chardata(Pane_part) ->
?CLASS(ThisT,wxAuiManager),
Pane_part_UC = unicode:characters_to_binary([Pane_part,0]),
?CLASS(PaneT,wxAuiPaneInfo),
@@ -235,7 +235,7 @@ loadPaneInfo(#wx_ref{type=ThisT,ref=ThisRef},Pane_part,#wx_ref{type=PaneT,ref=Pa
This::wxAuiManager(), Perspective::unicode:chardata().
loadPerspective(This,Perspective)
- when is_record(This, wx_ref),is_list(Perspective) ->
+ when is_record(This, wx_ref),?is_chardata(Perspective) ->
loadPerspective(This,Perspective, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauimanager.html#wxauimanagerloadperspective">external documentation</a>.
@@ -243,7 +243,7 @@ loadPerspective(This,Perspective)
This::wxAuiManager(), Perspective::unicode:chardata(),
Option :: {'update', boolean()}.
loadPerspective(#wx_ref{type=ThisT,ref=ThisRef},Perspective, Options)
- when is_list(Perspective),is_list(Options) ->
+ when ?is_chardata(Perspective),is_list(Options) ->
?CLASS(ThisT,wxAuiManager),
Perspective_UC = unicode:characters_to_binary([Perspective,0]),
MOpts = fun({update, Update}, Acc) -> [<<1:32/?UI,(wxe_util:from_bool(Update)):32/?UI>>|Acc];
diff --git a/lib/wx/src/gen/wxAuiNotebook.erl b/lib/wx/src/gen/wxAuiNotebook.erl
index 42da35e16a..adb90c224f 100644
--- a/lib/wx/src/gen/wxAuiNotebook.erl
+++ b/lib/wx/src/gen/wxAuiNotebook.erl
@@ -42,38 +42,38 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setForegroundColour/2,
- setHelpText/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,
- setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,setPalette/2,
- setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
- setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
- setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
- transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
- validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
+ show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
+ update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
-export_type([wxAuiNotebook/0]).
%% @hidden
@@ -121,7 +121,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
This::wxAuiNotebook(), Page::wxWindow:wxWindow(), Caption::unicode:chardata().
addPage(This,Page,Caption)
- when is_record(This, wx_ref),is_record(Page, wx_ref),is_list(Caption) ->
+ when is_record(This, wx_ref),is_record(Page, wx_ref),?is_chardata(Caption) ->
addPage(This,Page,Caption, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauinotebook.html#wxauinotebookaddpage">external documentation</a>.
@@ -130,7 +130,7 @@ addPage(This,Page,Caption)
Option :: {'select', boolean()}
| {'bitmap', wxBitmap:wxBitmap()}.
addPage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageT,ref=PageRef},Caption, Options)
- when is_list(Caption),is_list(Options) ->
+ when ?is_chardata(Caption),is_list(Options) ->
?CLASS(ThisT,wxAuiNotebook),
?CLASS(PageT,wxWindow),
Caption_UC = unicode:characters_to_binary([Caption,0]),
@@ -243,7 +243,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxAuiNotebook(), Page_idx::integer(), Page::wxWindow:wxWindow(), Caption::unicode:chardata().
insertPage(This,Page_idx,Page,Caption)
- when is_record(This, wx_ref),is_integer(Page_idx),is_record(Page, wx_ref),is_list(Caption) ->
+ when is_record(This, wx_ref),is_integer(Page_idx),is_record(Page, wx_ref),?is_chardata(Caption) ->
insertPage(This,Page_idx,Page,Caption, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauinotebook.html#wxauinotebookinsertpage">external documentation</a>.
@@ -252,7 +252,7 @@ insertPage(This,Page_idx,Page,Caption)
Option :: {'select', boolean()}
| {'bitmap', wxBitmap:wxBitmap()}.
insertPage(#wx_ref{type=ThisT,ref=ThisRef},Page_idx,#wx_ref{type=PageT,ref=PageRef},Caption, Options)
- when is_integer(Page_idx),is_list(Caption),is_list(Options) ->
+ when is_integer(Page_idx),?is_chardata(Caption),is_list(Options) ->
?CLASS(ThisT,wxAuiNotebook),
?CLASS(PageT,wxWindow),
Caption_UC = unicode:characters_to_binary([Caption,0]),
@@ -304,7 +304,7 @@ setPageBitmap(#wx_ref{type=ThisT,ref=ThisRef},Page,#wx_ref{type=BitmapT,ref=Bitm
-spec setPageText(This, Page, Text) -> boolean() when
This::wxAuiNotebook(), Page::integer(), Text::unicode:chardata().
setPageText(#wx_ref{type=ThisT,ref=ThisRef},Page,Text)
- when is_integer(Page),is_list(Text) ->
+ when is_integer(Page),?is_chardata(Text) ->
?CLASS(ThisT,wxAuiNotebook),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxAuiNotebook_SetPageText,
@@ -350,6 +350,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -664,6 +666,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxAuiPaneInfo.erl b/lib/wx/src/gen/wxAuiPaneInfo.erl
index 858da200be..c8273269ac 100644
--- a/lib/wx/src/gen/wxAuiPaneInfo.erl
+++ b/lib/wx/src/gen/wxAuiPaneInfo.erl
@@ -117,7 +117,7 @@ bottomDockable(#wx_ref{type=ThisT,ref=ThisRef}, Options)
-spec caption(This, C) -> wxAuiPaneInfo() when
This::wxAuiPaneInfo(), C::unicode:chardata().
caption(#wx_ref{type=ThisT,ref=ThisRef},C)
- when is_list(C) ->
+ when ?is_chardata(C) ->
?CLASS(ThisT,wxAuiPaneInfo),
C_UC = unicode:characters_to_binary([C,0]),
wxe_util:call(?wxAuiPaneInfo_Caption,
@@ -689,7 +689,7 @@ movable(#wx_ref{type=ThisT,ref=ThisRef}, Options)
-spec name(This, N) -> wxAuiPaneInfo() when
This::wxAuiPaneInfo(), N::unicode:chardata().
name(#wx_ref{type=ThisT,ref=ThisRef},N)
- when is_list(N) ->
+ when ?is_chardata(N) ->
?CLASS(ThisT,wxAuiPaneInfo),
N_UC = unicode:characters_to_binary([N,0]),
wxe_util:call(?wxAuiPaneInfo_Name,
diff --git a/lib/wx/src/gen/wxBitmap.erl b/lib/wx/src/gen/wxBitmap.erl
index e7830dae9b..4a6e308d8d 100644
--- a/lib/wx/src/gen/wxBitmap.erl
+++ b/lib/wx/src/gen/wxBitmap.erl
@@ -56,7 +56,7 @@ new() ->
Image::wxImage:wxImage().
new(Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
new(Filename, []);
new(Image)
@@ -86,7 +86,7 @@ new(Width,Height)
when is_integer(Width),is_integer(Height) ->
new(Width,Height, []);
new(Filename, Options)
- when is_list(Filename),is_list(Options) ->
+ when ?is_chardata(Filename),is_list(Options) ->
Filename_UC = unicode:characters_to_binary([Filename,0]),
MOpts = fun({type, Type}, Acc) -> [<<1:32/?UI,Type:32/?UI>>|Acc];
(BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
@@ -230,7 +230,7 @@ getSubBitmap(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
This::wxBitmap(), Name::unicode:chardata().
loadFile(This,Name)
- when is_record(This, wx_ref),is_list(Name) ->
+ when is_record(This, wx_ref),?is_chardata(Name) ->
loadFile(This,Name, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxbitmap.html#wxbitmaploadfile">external documentation</a>.
@@ -239,7 +239,7 @@ loadFile(This,Name)
This::wxBitmap(), Name::unicode:chardata(),
Option :: {'type', wx:wx_enum()}.
loadFile(#wx_ref{type=ThisT,ref=ThisRef},Name, Options)
- when is_list(Name),is_list(Options) ->
+ when ?is_chardata(Name),is_list(Options) ->
?CLASS(ThisT,wxBitmap),
Name_UC = unicode:characters_to_binary([Name,0]),
MOpts = fun({type, Type}, Acc) -> [<<1:32/?UI,Type:32/?UI>>|Acc];
@@ -261,7 +261,7 @@ ok(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxBitmap(), Name::unicode:chardata(), Type::wx:wx_enum().
saveFile(This,Name,Type)
- when is_record(This, wx_ref),is_list(Name),is_integer(Type) ->
+ when is_record(This, wx_ref),?is_chardata(Name),is_integer(Type) ->
saveFile(This,Name,Type, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxbitmap.html#wxbitmapsavefile">external documentation</a>.
@@ -270,7 +270,7 @@ saveFile(This,Name,Type)
This::wxBitmap(), Name::unicode:chardata(), Type::wx:wx_enum(),
Option :: {'palette', wxPalette:wxPalette()}.
saveFile(#wx_ref{type=ThisT,ref=ThisRef},Name,Type, Options)
- when is_list(Name),is_integer(Type),is_list(Options) ->
+ when ?is_chardata(Name),is_integer(Type),is_list(Options) ->
?CLASS(ThisT,wxBitmap),
Name_UC = unicode:characters_to_binary([Name,0]),
MOpts = fun({palette, #wx_ref{type=PaletteT,ref=PaletteRef}}, Acc) -> ?CLASS(PaletteT,wxPalette),[<<1:32/?UI,PaletteRef:32/?UI>>|Acc];
diff --git a/lib/wx/src/gen/wxBitmapButton.erl b/lib/wx/src/gen/wxBitmapButton.erl
index d1d2d037e8..d0a810bdb9 100644
--- a/lib/wx/src/gen/wxBitmapButton.erl
+++ b/lib/wx/src/gen/wxBitmapButton.erl
@@ -41,38 +41,39 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDefault/1,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
- setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
- setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
- setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
- setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
- show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
- update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDefault/1,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,
+ setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5,
+ setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2,
+ setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
+ setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
+ transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
+ validate/1,warpPointer/3]).
-export_type([wxBitmapButton/0]).
%% @hidden
@@ -230,6 +231,8 @@ setDefault(This) -> wxButton:setDefault(This).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -546,6 +549,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxButton.erl b/lib/wx/src/gen/wxButton.erl
index 65d45caa13..f8e24beffa 100644
--- a/lib/wx/src/gen/wxButton.erl
+++ b/lib/wx/src/gen/wxButton.erl
@@ -39,30 +39,30 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2,
- setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
@@ -163,7 +163,7 @@ setDefault(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setLabel(This, Label) -> 'ok' when
This::wxButton(), Label::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label)
- when is_list(Label) ->
+ when ?is_chardata(Label) ->
?CLASS(ThisT,wxButton),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxButton_SetLabel,
@@ -180,6 +180,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -496,6 +498,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxCalendarCtrl.erl b/lib/wx/src/gen/wxCalendarCtrl.erl
index 93fcb61464..bf033e9bc0 100644
--- a/lib/wx/src/gen/wxCalendarCtrl.erl
+++ b/lib/wx/src/gen/wxCalendarCtrl.erl
@@ -43,29 +43,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -364,6 +364,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -680,6 +682,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxCheckBox.erl b/lib/wx/src/gen/wxCheckBox.erl
index 3276add802..5ed49d91b6 100644
--- a/lib/wx/src/gen/wxCheckBox.erl
+++ b/lib/wx/src/gen/wxCheckBox.erl
@@ -40,29 +40,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -92,7 +92,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
new(Parent,Id,Label)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
new(Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxcheckbox.html#wxcheckboxwxcheckbox">external documentation</a>.
@@ -103,7 +103,7 @@ new(Parent,Id,Label)
| {'style', integer()}
| {'validator', wx:wx_object()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -120,7 +120,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
This::wxCheckBox(), Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
create(This,Parent,Id,Label)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
create(This,Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxcheckbox.html#wxcheckboxcreate">external documentation</a>.
@@ -131,7 +131,7 @@ create(This,Parent,Id,Label)
| {'style', integer()}
| {'validator', wx:wx_object()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxCheckBox),
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
@@ -217,6 +217,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -533,6 +535,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxCheckListBox.erl b/lib/wx/src/gen/wxCheckListBox.erl
index 888f29518c..ddef6a29e2 100644
--- a/lib/wx/src/gen/wxCheckListBox.erl
+++ b/lib/wx/src/gen/wxCheckListBox.erl
@@ -41,13 +41,14 @@
clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3,
convertDialogToPixels/2,convertPixelsToDialog/2,delete/2,deselect/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1,
- freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
- getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
- getClientData/2,getClientSize/1,getContainingSizer/1,getCount/1,getCursor/1,
- getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ dragAcceptFiles/2,enable/1,enable/2,findString/2,findString/3,findWindow/2,
+ fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
+ getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,
+ getChildren/1,getClientData/2,getClientSize/1,getContainingSizer/1,
+ getContentScaleFactor/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,
+ getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
+ getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
getSelection/1,getSelections/1,getSize/1,getSizer/1,getString/2,getStringSelection/1,
getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
@@ -222,6 +223,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -538,6 +541,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxChoice.erl b/lib/wx/src/gen/wxChoice.erl
index 1a90b275d1..266a257442 100644
--- a/lib/wx/src/gen/wxChoice.erl
+++ b/lib/wx/src/gen/wxChoice.erl
@@ -40,40 +40,41 @@
centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1,
clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3,
convertDialogToPixels/2,convertPixelsToDialog/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- findString/2,findString/3,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientData/2,getClientSize/1,
- getContainingSizer/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,
- getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSelection/1,getSize/1,getSizer/1,getString/2,getStringSelection/1,
- getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
- getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
- hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1,
- insert/3,insert/4,invalidateBestSize/1,isDoubleBuffered/1,isEmpty/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientData/3,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSelection/2,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,
- setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,
- setSizerAndFit/3,setString/3,setStringSelection/2,setThemeEnabled/2,
- setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
- setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
- setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientData/2,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,
+ getFont/1,getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSelection/1,getSize/1,getSizer/1,
+ getString/2,getStringSelection/1,getTextExtent/2,getTextExtent/3,
+ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,inheritAttributes/1,initDialog/1,insert/3,insert/4,invalidateBestSize/1,
+ isDoubleBuffered/1,isEmpty/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,
+ makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,
+ setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
+ setClientData/3,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setId/2,
+ setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSelection/2,setSize/2,
+ setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
+ setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3,
+ setStringSelection/2,setThemeEnabled/2,setToolTip/2,setTransparent/2,
+ setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,
+ setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,
+ shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
validate/1,warpPointer/3]).
@@ -237,6 +238,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -553,6 +556,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxChoicebook.erl b/lib/wx/src/gen/wxChoicebook.erl
index 34b62ff75b..c6e0941978 100644
--- a/lib/wx/src/gen/wxChoicebook.erl
+++ b/lib/wx/src/gen/wxChoicebook.erl
@@ -43,29 +43,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -120,7 +120,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
This::wxChoicebook(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
addPage(This,Page,Text)
- when is_record(This, wx_ref),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_record(Page, wx_ref),?is_chardata(Text) ->
addPage(This,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxchoicebook.html#wxchoicebookaddpage">external documentation</a>.
@@ -129,7 +129,7 @@ addPage(This,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
addPage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxChoicebook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -296,7 +296,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
This::wxChoicebook(), N::integer(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
insertPage(This,N,Page,Text)
- when is_record(This, wx_ref),is_integer(N),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(N),is_record(Page, wx_ref),?is_chardata(Text) ->
insertPage(This,N,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxchoicebook.html#wxchoicebookinsertpage">external documentation</a>.
@@ -305,7 +305,7 @@ insertPage(This,N,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
insertPage(#wx_ref{type=ThisT,ref=ThisRef},N,#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_integer(N),is_list(Text),is_list(Options) ->
+ when is_integer(N),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxChoicebook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -347,7 +347,7 @@ setPageImage(#wx_ref{type=ThisT,ref=ThisRef},N,ImageId)
-spec setPageText(This, N, StrText) -> boolean() when
This::wxChoicebook(), N::integer(), StrText::unicode:chardata().
setPageText(#wx_ref{type=ThisT,ref=ThisRef},N,StrText)
- when is_integer(N),is_list(StrText) ->
+ when is_integer(N),?is_chardata(StrText) ->
?CLASS(ThisT,wxChoicebook),
StrText_UC = unicode:characters_to_binary([StrText,0]),
wxe_util:call(?wxChoicebook_SetPageText,
@@ -384,6 +384,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -700,6 +702,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxColourDialog.erl b/lib/wx/src/gen/wxColourDialog.erl
index 9c97434d9a..936c0e5099 100644
--- a/lib/wx/src/gen/wxColourDialog.erl
+++ b/lib/wx/src/gen/wxColourDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -223,6 +223,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -539,6 +541,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxColourPickerCtrl.erl b/lib/wx/src/gen/wxColourPickerCtrl.erl
index 9c987b4dde..c97b194bc8 100644
--- a/lib/wx/src/gen/wxColourPickerCtrl.erl
+++ b/lib/wx/src/gen/wxColourPickerCtrl.erl
@@ -39,17 +39,18 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getInternalMargin/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPickerCtrlProportion/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getInternalMargin/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPickerCtrlProportion/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextCtrl/1,
+ getTextCtrlProportion/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,
isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,
@@ -168,7 +169,7 @@ getColour(#wx_ref{type=ThisT,ref=ThisRef}) ->
(This, Col) -> 'ok' when
This::wxColourPickerCtrl(), Col::wx:wx_colour().
setColour(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxColourPickerCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxColourPickerCtrl_SetColour_1_0,
@@ -221,6 +222,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -537,6 +540,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxComboBox.erl b/lib/wx/src/gen/wxComboBox.erl
index bbdf768eba..9f8cf77445 100644
--- a/lib/wx/src/gen/wxComboBox.erl
+++ b/lib/wx/src/gen/wxComboBox.erl
@@ -42,42 +42,42 @@
centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1,
clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3,
convertDialogToPixels/2,convertPixelsToDialog/2,delete/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- findString/2,findString/3,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientData/2,getClientSize/1,
- getContainingSizer/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,
- getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSelection/1,getSize/1,getSizer/1,getString/2,getStringSelection/1,
- getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
- getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
- hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1,
- insert/3,insert/4,invalidateBestSize/1,isDoubleBuffered/1,isEmpty/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientData/3,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
- setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
- setString/3,setStringSelection/2,setThemeEnabled/2,setToolTip/2,setTransparent/2,
- setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,
- setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,
- shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
- transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
- validate/1,warpPointer/3]).
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientData/2,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,
+ getFont/1,getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSelection/1,getSize/1,getSizer/1,
+ getString/2,getStringSelection/1,getTextExtent/2,getTextExtent/3,
+ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,inheritAttributes/1,initDialog/1,insert/3,insert/4,invalidateBestSize/1,
+ isDoubleBuffered/1,isEmpty/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,
+ makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,
+ setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
+ setClientData/3,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setId/2,
+ setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5,
+ setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3,setStringSelection/2,
+ setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
+ show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
+ update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
-export_type([wxComboBox/0]).
%% @hidden
@@ -130,7 +130,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::unicode:chardata(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[unicode:chardata()].
create(This,Parent,Id,Value,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
create(This,Parent,Id,Value,Pos,Size,Choices, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxcombobox.html#wxcomboboxcreate">external documentation</a>.
@@ -139,7 +139,7 @@ create(This,Parent,Id,Value,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
Option :: {'style', integer()}
| {'validator', wx:wx_object()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,{PosX,PosY},{SizeW,SizeH},Choices, Options)
- when is_integer(Id),is_list(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) ->
?CLASS(ThisT,wxComboBox),
?CLASS(ParentT,wxWindow),
Value_UC = unicode:characters_to_binary([Value,0]),
@@ -252,7 +252,7 @@ redo(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec replace(This, From, To, Value) -> 'ok' when
This::wxComboBox(), From::integer(), To::integer(), Value::unicode:chardata().
replace(#wx_ref{type=ThisT,ref=ThisRef},From,To,Value)
- when is_integer(From),is_integer(To),is_list(Value) ->
+ when is_integer(From),is_integer(To),?is_chardata(Value) ->
?CLASS(ThisT,wxComboBox),
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:cast(?wxComboBox_Replace,
@@ -306,7 +306,7 @@ setSelection(#wx_ref{type=ThisT,ref=ThisRef},From,To)
-spec setValue(This, Value) -> 'ok' when
This::wxComboBox(), Value::unicode:chardata().
setValue(#wx_ref{type=ThisT,ref=ThisRef},Value)
- when is_list(Value) ->
+ when ?is_chardata(Value) ->
?CLASS(ThisT,wxComboBox),
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:cast(?wxComboBox_SetValue,
@@ -372,6 +372,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -688,6 +690,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxCommandEvent.erl b/lib/wx/src/gen/wxCommandEvent.erl
index 781482aebb..18ccbc65f0 100644
--- a/lib/wx/src/gen/wxCommandEvent.erl
+++ b/lib/wx/src/gen/wxCommandEvent.erl
@@ -114,7 +114,7 @@ setInt(#wx_ref{type=ThisT,ref=ThisRef},I)
-spec setString(This, S) -> 'ok' when
This::wxCommandEvent(), S::unicode:chardata().
setString(#wx_ref{type=ThisT,ref=ThisRef},S)
- when is_list(S) ->
+ when ?is_chardata(S) ->
?CLASS(ThisT,wxCommandEvent),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:cast(?wxCommandEvent_SetString,
diff --git a/lib/wx/src/gen/wxControl.erl b/lib/wx/src/gen/wxControl.erl
index a84f88639b..6be7574d80 100644
--- a/lib/wx/src/gen/wxControl.erl
+++ b/lib/wx/src/gen/wxControl.erl
@@ -37,30 +37,30 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
- getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2,
- setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getMaxSize/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
@@ -89,7 +89,7 @@ getLabel(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setLabel(This, Label) -> 'ok' when
This::wxControl(), Label::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label)
- when is_list(Label) ->
+ when ?is_chardata(Label) ->
?CLASS(ThisT,wxControl),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxControl_SetLabel,
@@ -97,6 +97,8 @@ setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label)
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -413,6 +415,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxControlWithItems.erl b/lib/wx/src/gen/wxControlWithItems.erl
index c4d116d9e7..47ffa7dcba 100644
--- a/lib/wx/src/gen/wxControlWithItems.erl
+++ b/lib/wx/src/gen/wxControlWithItems.erl
@@ -41,29 +41,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -86,7 +86,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-spec append(This, Item) -> integer() when
This::wxControlWithItems(), Item::unicode:chardata().
append(#wx_ref{type=ThisT,ref=ThisRef},Item)
- when is_list(Item) ->
+ when ?is_chardata(Item) ->
?CLASS(ThisT,wxControlWithItems),
Item_UC = unicode:characters_to_binary([Item,0]),
wxe_util:call(?wxControlWithItems_Append_1,
@@ -96,7 +96,7 @@ append(#wx_ref{type=ThisT,ref=ThisRef},Item)
-spec append(This, Item, ClientData) -> integer() when
This::wxControlWithItems(), Item::unicode:chardata(), ClientData::term().
append(#wx_ref{type=ThisT,ref=ThisRef},Item,ClientData)
- when is_list(Item) ->
+ when ?is_chardata(Item) ->
?CLASS(ThisT,wxControlWithItems),
Item_UC = unicode:characters_to_binary([Item,0]),
wxe_util:send_bin(term_to_binary(ClientData)),
@@ -136,7 +136,7 @@ delete(#wx_ref{type=ThisT,ref=ThisRef},N)
This::wxControlWithItems(), S::unicode:chardata().
findString(This,S)
- when is_record(This, wx_ref),is_list(S) ->
+ when is_record(This, wx_ref),?is_chardata(S) ->
findString(This,S, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxcontrolwithitems.html#wxcontrolwithitemsfindstring">external documentation</a>.
@@ -144,7 +144,7 @@ findString(This,S)
This::wxControlWithItems(), S::unicode:chardata(),
Option :: {'bCase', boolean()}.
findString(#wx_ref{type=ThisT,ref=ThisRef},S, Options)
- when is_list(S),is_list(Options) ->
+ when ?is_chardata(S),is_list(Options) ->
?CLASS(ThisT,wxControlWithItems),
S_UC = unicode:characters_to_binary([S,0]),
MOpts = fun({bCase, BCase}, Acc) -> [<<1:32/?UI,(wxe_util:from_bool(BCase)):32/?UI>>|Acc];
@@ -209,7 +209,7 @@ getStringSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec insert(This, Item, Pos) -> integer() when
This::wxControlWithItems(), Item::unicode:chardata(), Pos::integer().
insert(#wx_ref{type=ThisT,ref=ThisRef},Item,Pos)
- when is_list(Item),is_integer(Pos) ->
+ when ?is_chardata(Item),is_integer(Pos) ->
?CLASS(ThisT,wxControlWithItems),
Item_UC = unicode:characters_to_binary([Item,0]),
wxe_util:call(?wxControlWithItems_Insert_2,
@@ -219,7 +219,7 @@ insert(#wx_ref{type=ThisT,ref=ThisRef},Item,Pos)
-spec insert(This, Item, Pos, ClientData) -> integer() when
This::wxControlWithItems(), Item::unicode:chardata(), Pos::integer(), ClientData::term().
insert(#wx_ref{type=ThisT,ref=ThisRef},Item,Pos,ClientData)
- when is_list(Item),is_integer(Pos) ->
+ when ?is_chardata(Item),is_integer(Pos) ->
?CLASS(ThisT,wxControlWithItems),
Item_UC = unicode:characters_to_binary([Item,0]),
wxe_util:send_bin(term_to_binary(ClientData)),
@@ -256,7 +256,7 @@ setSelection(#wx_ref{type=ThisT,ref=ThisRef},N)
-spec setString(This, N, S) -> 'ok' when
This::wxControlWithItems(), N::integer(), S::unicode:chardata().
setString(#wx_ref{type=ThisT,ref=ThisRef},N,S)
- when is_integer(N),is_list(S) ->
+ when is_integer(N),?is_chardata(S) ->
?CLASS(ThisT,wxControlWithItems),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:cast(?wxControlWithItems_SetString,
@@ -266,7 +266,7 @@ setString(#wx_ref{type=ThisT,ref=ThisRef},N,S)
-spec setStringSelection(This, S) -> boolean() when
This::wxControlWithItems(), S::unicode:chardata().
setStringSelection(#wx_ref{type=ThisT,ref=ThisRef},S)
- when is_list(S) ->
+ when ?is_chardata(S) ->
?CLASS(ThisT,wxControlWithItems),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:call(?wxControlWithItems_SetStringSelection,
@@ -279,6 +279,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -595,6 +597,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxDC.erl b/lib/wx/src/gen/wxDC.erl
index ad7a4251ec..16bfcc3463 100644
--- a/lib/wx/src/gen/wxDC.erl
+++ b/lib/wx/src/gen/wxDC.erl
@@ -253,7 +253,7 @@ drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},{PtX,Pt
This::wxDC(), Text::unicode:chardata(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}.
drawLabel(This,Text,Rect={RectX,RectY,RectW,RectH})
- when is_record(This, wx_ref),is_list(Text),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
+ when is_record(This, wx_ref),?is_chardata(Text),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
drawLabel(This,Text,Rect, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdc.html#wxdcdrawlabel">external documentation</a>.
@@ -262,7 +262,7 @@ drawLabel(This,Text,Rect={RectX,RectY,RectW,RectH})
Option :: {'alignment', integer()}
| {'indexAccel', integer()}.
drawLabel(#wx_ref{type=ThisT,ref=ThisRef},Text,{RectX,RectY,RectW,RectH}, Options)
- when is_list(Text),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_list(Options) ->
+ when ?is_chardata(Text),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_list(Options) ->
?CLASS(ThisT,wxDC),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({alignment, Alignment}, Acc) -> [<<1:32/?UI,Alignment:32/?UI>>|Acc];
@@ -363,7 +363,7 @@ drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH})
-spec drawRotatedText(This, Text, Pt, Angle) -> 'ok' when
This::wxDC(), Text::unicode:chardata(), Pt::{X::integer(), Y::integer()}, Angle::number().
drawRotatedText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY},Angle)
- when is_list(Text),is_integer(PtX),is_integer(PtY),is_number(Angle) ->
+ when ?is_chardata(Text),is_integer(PtX),is_integer(PtY),is_number(Angle) ->
?CLASS(ThisT,wxDC),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxDC_DrawRotatedText,
@@ -391,7 +391,7 @@ drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Radius)
-spec drawText(This, Text, Pt) -> 'ok' when
This::wxDC(), Text::unicode:chardata(), Pt::{X::integer(), Y::integer()}.
drawText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY})
- when is_list(Text),is_integer(PtX),is_integer(PtY) ->
+ when ?is_chardata(Text),is_integer(PtX),is_integer(PtY) ->
?CLASS(ThisT,wxDC),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxDC_DrawText,
@@ -521,7 +521,7 @@ getMapMode(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec getMultiLineTextExtent(This, String) -> {W::integer(), H::integer()} when
This::wxDC(), String::unicode:chardata().
getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
- when is_list(String) ->
+ when ?is_chardata(String) ->
?CLASS(ThisT,wxDC),
String_UC = unicode:characters_to_binary([String,0]),
wxe_util:call(?wxDC_GetMultiLineTextExtent_1,
@@ -532,7 +532,7 @@ getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
This::wxDC(), String::unicode:chardata(),
Option :: {'font', wxFont:wxFont()}.
getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
- when is_list(String),is_list(Options) ->
+ when ?is_chardata(String),is_list(Options) ->
?CLASS(ThisT,wxDC),
String_UC = unicode:characters_to_binary([String,0]),
MOpts = fun({font, #wx_ref{type=FontT,ref=FontRef}}, Acc) -> ?CLASS(FontT,wxFont),[<<1:32/?UI,FontRef:32/?UI>>|Acc];
@@ -546,7 +546,7 @@ getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
Result ::{Res ::boolean(), Widths::[integer()]},
This::wxDC(), Text::unicode:chardata().
getPartialTextExtents(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxDC),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxDC_GetPartialTextExtents,
@@ -606,7 +606,7 @@ getTextBackground(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec getTextExtent(This, String) -> {W::integer(), H::integer()} when
This::wxDC(), String::unicode:chardata().
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
- when is_list(String) ->
+ when ?is_chardata(String) ->
?CLASS(ThisT,wxDC),
String_UC = unicode:characters_to_binary([String,0]),
wxe_util:call(?wxDC_GetTextExtent_1,
@@ -618,7 +618,7 @@ getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
This::wxDC(), String::unicode:chardata(),
Option :: {'theFont', wxFont:wxFont()}.
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
- when is_list(String),is_list(Options) ->
+ when ?is_chardata(String),is_list(Options) ->
?CLASS(ThisT,wxDC),
String_UC = unicode:characters_to_binary([String,0]),
MOpts = fun({theFont, #wx_ref{type=TheFontT,ref=TheFontRef}}, Acc) -> ?CLASS(TheFontT,wxFont),[<<1:32/?UI,TheFontRef:32/?UI>>|Acc];
@@ -929,7 +929,7 @@ setUserScale(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
-spec startDoc(This, Message) -> boolean() when
This::wxDC(), Message::unicode:chardata().
startDoc(#wx_ref{type=ThisT,ref=ThisRef},Message)
- when is_list(Message) ->
+ when ?is_chardata(Message) ->
?CLASS(ThisT,wxDC),
Message_UC = unicode:characters_to_binary([Message,0]),
wxe_util:call(?wxDC_StartDoc,
diff --git a/lib/wx/src/gen/wxDatePickerCtrl.erl b/lib/wx/src/gen/wxDatePickerCtrl.erl
index 1b306a498a..743169c58e 100644
--- a/lib/wx/src/gen/wxDatePickerCtrl.erl
+++ b/lib/wx/src/gen/wxDatePickerCtrl.erl
@@ -39,17 +39,18 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getInternalMargin/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPickerCtrlProportion/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getInternalMargin/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPickerCtrlProportion/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextCtrl/1,
+ getTextCtrlProportion/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,
isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,
@@ -197,6 +198,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -513,6 +516,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxDialog.erl b/lib/wx/src/gen/wxDialog.erl
index 9f98644828..72f37df178 100644
--- a/lib/wx/src/gen/wxDialog.erl
+++ b/lib/wx/src/gen/wxDialog.erl
@@ -41,32 +41,32 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,
- getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
- getTextExtent/2,getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,
- getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
- hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
- inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
- isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
- isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
- layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,
- maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1,
- screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
- setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
- setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
- setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
+ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
+ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
+ isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
+ isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
+ isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
+ makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
+ screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
+ scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,
+ setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,
+ setIcons/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
@@ -97,7 +97,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
new(Parent,Id,Title)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
new(Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdialog.html#wxdialogwxdialog">external documentation</a>.
@@ -107,7 +107,7 @@ new(Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -123,7 +123,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
This::wxDialog(), Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
create(This,Parent,Id,Title)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
create(This,Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdialog.html#wxdialogcreate">external documentation</a>.
@@ -133,7 +133,7 @@ create(This,Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ThisT,wxDialog),
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -298,6 +298,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -614,6 +616,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxDirDialog.erl b/lib/wx/src/gen/wxDirDialog.erl
index 1b6b9dba71..5a2df9821a 100644
--- a/lib/wx/src/gen/wxDirDialog.erl
+++ b/lib/wx/src/gen/wxDirDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -137,7 +137,7 @@ getMessage(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setMessage(This, Message) -> 'ok' when
This::wxDirDialog(), Message::unicode:chardata().
setMessage(#wx_ref{type=ThisT,ref=ThisRef},Message)
- when is_list(Message) ->
+ when ?is_chardata(Message) ->
?CLASS(ThisT,wxDirDialog),
Message_UC = unicode:characters_to_binary([Message,0]),
wxe_util:cast(?wxDirDialog_SetMessage,
@@ -147,7 +147,7 @@ setMessage(#wx_ref{type=ThisT,ref=ThisRef},Message)
-spec setPath(This, Path) -> 'ok' when
This::wxDirDialog(), Path::unicode:chardata().
setPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
- when is_list(Path) ->
+ when ?is_chardata(Path) ->
?CLASS(ThisT,wxDirDialog),
Path_UC = unicode:characters_to_binary([Path,0]),
wxe_util:cast(?wxDirDialog_SetPath,
@@ -231,6 +231,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -547,6 +549,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxDirPickerCtrl.erl b/lib/wx/src/gen/wxDirPickerCtrl.erl
index 3bedeb7f54..9bfff7d458 100644
--- a/lib/wx/src/gen/wxDirPickerCtrl.erl
+++ b/lib/wx/src/gen/wxDirPickerCtrl.erl
@@ -39,17 +39,18 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getInternalMargin/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPickerCtrlProportion/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getInternalMargin/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPickerCtrlProportion/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextCtrl/1,
+ getTextCtrlProportion/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,
isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,
@@ -166,7 +167,7 @@ getPath(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setPath(This, Str) -> 'ok' when
This::wxDirPickerCtrl(), Str::unicode:chardata().
setPath(#wx_ref{type=ThisT,ref=ThisRef},Str)
- when is_list(Str) ->
+ when ?is_chardata(Str) ->
?CLASS(ThisT,wxDirPickerCtrl),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxDirPickerCtrl_SetPath,
@@ -214,6 +215,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -530,6 +533,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxDropFilesEvent.erl b/lib/wx/src/gen/wxDropFilesEvent.erl
new file mode 100644
index 0000000000..d28dcd1f7a
--- /dev/null
+++ b/lib/wx/src/gen/wxDropFilesEvent.erl
@@ -0,0 +1,89 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%% This file is generated DO NOT EDIT
+
+%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdropfilesevent.html">wxDropFilesEvent</a>.
+%% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt>
+%% <dd><em>drop_files</em></dd></dl>
+%% See also the message variant {@link wxEvtHandler:wxDropFiles(). #wxDropFiles{}} event record type.
+%%
+%% <p>This class is derived (and can use functions) from:
+%% <br />{@link wxEvent}
+%% </p>
+%% @type wxDropFilesEvent(). 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(wxDropFilesEvent).
+-include("wxe.hrl").
+-export([getFiles/1,getNumberOfFiles/1,getPosition/1]).
+
+%% inherited exports
+-export([getId/1,getSkipped/1,getTimestamp/1,isCommandEvent/1,parent_class/1,
+ resumePropagation/2,shouldPropagate/1,skip/1,skip/2,stopPropagation/1]).
+
+-export_type([wxDropFilesEvent/0]).
+%% @hidden
+parent_class(wxEvent) -> true;
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
+
+-type wxDropFilesEvent() :: wx:wx_object().
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdropfilesevent.html#wxdropfileseventgetposition">external documentation</a>.
+-spec getPosition(This) -> {X::integer(), Y::integer()} when
+ This::wxDropFilesEvent().
+getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDropFilesEvent),
+ wxe_util:call(?wxDropFilesEvent_GetPosition,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdropfilesevent.html#wxdropfileseventgetnumberoffiles">external documentation</a>.
+-spec getNumberOfFiles(This) -> integer() when
+ This::wxDropFilesEvent().
+getNumberOfFiles(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDropFilesEvent),
+ wxe_util:call(?wxDropFilesEvent_GetNumberOfFiles,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdropfilesevent.html#wxdropfileseventgetfiles">external documentation</a>.
+-spec getFiles(This) -> [unicode:charlist()] when
+ This::wxDropFilesEvent().
+getFiles(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDropFilesEvent),
+ wxe_util:call(?wxDropFilesEvent_GetFiles,
+ <<ThisRef:32/?UI>>).
+
+ %% From wxEvent
+%% @hidden
+stopPropagation(This) -> wxEvent:stopPropagation(This).
+%% @hidden
+skip(This, Options) -> wxEvent:skip(This, Options).
+%% @hidden
+skip(This) -> wxEvent:skip(This).
+%% @hidden
+shouldPropagate(This) -> wxEvent:shouldPropagate(This).
+%% @hidden
+resumePropagation(This,PropagationLevel) -> wxEvent:resumePropagation(This,PropagationLevel).
+%% @hidden
+isCommandEvent(This) -> wxEvent:isCommandEvent(This).
+%% @hidden
+getTimestamp(This) -> wxEvent:getTimestamp(This).
+%% @hidden
+getSkipped(This) -> wxEvent:getSkipped(This).
+%% @hidden
+getId(This) -> wxEvent:getId(This).
diff --git a/lib/wx/src/gen/wxFileDataObject.erl b/lib/wx/src/gen/wxFileDataObject.erl
index 06d8ceb9cd..d4e9198225 100644
--- a/lib/wx/src/gen/wxFileDataObject.erl
+++ b/lib/wx/src/gen/wxFileDataObject.erl
@@ -49,7 +49,7 @@ new() ->
-spec addFile(This, Filename) -> 'ok' when
This::wxFileDataObject(), Filename::unicode:chardata().
addFile(#wx_ref{type=ThisT,ref=ThisRef},Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
?CLASS(ThisT,wxFileDataObject),
Filename_UC = unicode:characters_to_binary([Filename,0]),
wxe_util:cast(?wxFileDataObject_AddFile,
diff --git a/lib/wx/src/gen/wxFileDialog.erl b/lib/wx/src/gen/wxFileDialog.erl
index 070fce3a39..6032e38a16 100644
--- a/lib/wx/src/gen/wxFileDialog.erl
+++ b/lib/wx/src/gen/wxFileDialog.erl
@@ -42,40 +42,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -191,7 +191,7 @@ getWildcard(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setDirectory(This, Dir) -> 'ok' when
This::wxFileDialog(), Dir::unicode:chardata().
setDirectory(#wx_ref{type=ThisT,ref=ThisRef},Dir)
- when is_list(Dir) ->
+ when ?is_chardata(Dir) ->
?CLASS(ThisT,wxFileDialog),
Dir_UC = unicode:characters_to_binary([Dir,0]),
wxe_util:cast(?wxFileDialog_SetDirectory,
@@ -201,7 +201,7 @@ setDirectory(#wx_ref{type=ThisT,ref=ThisRef},Dir)
-spec setFilename(This, Name) -> 'ok' when
This::wxFileDialog(), Name::unicode:chardata().
setFilename(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxFileDialog),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:cast(?wxFileDialog_SetFilename,
@@ -220,7 +220,7 @@ setFilterIndex(#wx_ref{type=ThisT,ref=ThisRef},FilterIndex)
-spec setMessage(This, Message) -> 'ok' when
This::wxFileDialog(), Message::unicode:chardata().
setMessage(#wx_ref{type=ThisT,ref=ThisRef},Message)
- when is_list(Message) ->
+ when ?is_chardata(Message) ->
?CLASS(ThisT,wxFileDialog),
Message_UC = unicode:characters_to_binary([Message,0]),
wxe_util:cast(?wxFileDialog_SetMessage,
@@ -230,7 +230,7 @@ setMessage(#wx_ref{type=ThisT,ref=ThisRef},Message)
-spec setPath(This, Path) -> 'ok' when
This::wxFileDialog(), Path::unicode:chardata().
setPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
- when is_list(Path) ->
+ when ?is_chardata(Path) ->
?CLASS(ThisT,wxFileDialog),
Path_UC = unicode:characters_to_binary([Path,0]),
wxe_util:cast(?wxFileDialog_SetPath,
@@ -240,7 +240,7 @@ setPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
-spec setWildcard(This, WildCard) -> 'ok' when
This::wxFileDialog(), WildCard::unicode:chardata().
setWildcard(#wx_ref{type=ThisT,ref=ThisRef},WildCard)
- when is_list(WildCard) ->
+ when ?is_chardata(WildCard) ->
?CLASS(ThisT,wxFileDialog),
WildCard_UC = unicode:characters_to_binary([WildCard,0]),
wxe_util:cast(?wxFileDialog_SetWildcard,
@@ -324,6 +324,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -640,6 +642,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxFilePickerCtrl.erl b/lib/wx/src/gen/wxFilePickerCtrl.erl
index 396403dc22..3b1943cbee 100644
--- a/lib/wx/src/gen/wxFilePickerCtrl.erl
+++ b/lib/wx/src/gen/wxFilePickerCtrl.erl
@@ -39,17 +39,18 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getInternalMargin/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPickerCtrlProportion/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getInternalMargin/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPickerCtrlProportion/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextCtrl/1,
+ getTextCtrlProportion/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,
isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,
@@ -170,7 +171,7 @@ getPath(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setPath(This, Str) -> 'ok' when
This::wxFilePickerCtrl(), Str::unicode:chardata().
setPath(#wx_ref{type=ThisT,ref=ThisRef},Str)
- when is_list(Str) ->
+ when ?is_chardata(Str) ->
?CLASS(ThisT,wxFilePickerCtrl),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxFilePickerCtrl_SetPath,
@@ -218,6 +219,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -534,6 +537,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxFindReplaceData.erl b/lib/wx/src/gen/wxFindReplaceData.erl
index 9b4b910f7e..388bf5f238 100644
--- a/lib/wx/src/gen/wxFindReplaceData.erl
+++ b/lib/wx/src/gen/wxFindReplaceData.erl
@@ -87,7 +87,7 @@ setFlags(#wx_ref{type=ThisT,ref=ThisRef},Flags)
-spec setFindString(This, Str) -> 'ok' when
This::wxFindReplaceData(), Str::unicode:chardata().
setFindString(#wx_ref{type=ThisT,ref=ThisRef},Str)
- when is_list(Str) ->
+ when ?is_chardata(Str) ->
?CLASS(ThisT,wxFindReplaceData),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxFindReplaceData_SetFindString,
@@ -97,7 +97,7 @@ setFindString(#wx_ref{type=ThisT,ref=ThisRef},Str)
-spec setReplaceString(This, Str) -> 'ok' when
This::wxFindReplaceData(), Str::unicode:chardata().
setReplaceString(#wx_ref{type=ThisT,ref=ThisRef},Str)
- when is_list(Str) ->
+ when ?is_chardata(Str) ->
?CLASS(ThisT,wxFindReplaceData),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxFindReplaceData_SetReplaceString,
diff --git a/lib/wx/src/gen/wxFindReplaceDialog.erl b/lib/wx/src/gen/wxFindReplaceDialog.erl
index a34fc329ae..9250c2fa2f 100644
--- a/lib/wx/src/gen/wxFindReplaceDialog.erl
+++ b/lib/wx/src/gen/wxFindReplaceDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -99,7 +99,7 @@ new() ->
Parent::wxWindow:wxWindow(), Data::wxFindReplaceData:wxFindReplaceData(), Title::unicode:chardata().
new(Parent,Data,Title)
- when is_record(Parent, wx_ref),is_record(Data, wx_ref),is_list(Title) ->
+ when is_record(Parent, wx_ref),is_record(Data, wx_ref),?is_chardata(Title) ->
new(Parent,Data,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxfindreplacedialog.html#wxfindreplacedialogwxfindreplacedialog">external documentation</a>.
@@ -107,7 +107,7 @@ new(Parent,Data,Title)
Parent::wxWindow:wxWindow(), Data::wxFindReplaceData:wxFindReplaceData(), Title::unicode:chardata(),
Option :: {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=DataT,ref=DataRef},Title, Options)
- when is_list(Title),is_list(Options) ->
+ when ?is_chardata(Title),is_list(Options) ->
?CLASS(ParentT,wxWindow),
?CLASS(DataT,wxFindReplaceData),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -122,7 +122,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=DataT,ref=DataRef},Title, O
This::wxFindReplaceDialog(), Parent::wxWindow:wxWindow(), Data::wxFindReplaceData:wxFindReplaceData(), Title::unicode:chardata().
create(This,Parent,Data,Title)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_record(Data, wx_ref),is_list(Title) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_record(Data, wx_ref),?is_chardata(Title) ->
create(This,Parent,Data,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxfindreplacedialog.html#wxfindreplacedialogcreate">external documentation</a>.
@@ -130,7 +130,7 @@ create(This,Parent,Data,Title)
This::wxFindReplaceDialog(), Parent::wxWindow:wxWindow(), Data::wxFindReplaceData:wxFindReplaceData(), Title::unicode:chardata(),
Option :: {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=DataT,ref=DataRef},Title, Options)
- when is_list(Title),is_list(Options) ->
+ when ?is_chardata(Title),is_list(Options) ->
?CLASS(ThisT,wxFindReplaceDialog),
?CLASS(ParentT,wxWindow),
?CLASS(DataT,wxFindReplaceData),
@@ -227,6 +227,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -543,6 +545,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxFont.erl b/lib/wx/src/gen/wxFont.erl
index 56e6e96b6d..fb0ba8b505 100644
--- a/lib/wx/src/gen/wxFont.erl
+++ b/lib/wx/src/gen/wxFont.erl
@@ -49,7 +49,7 @@ new() ->
-spec new(Fontname) -> wxFont() when
Fontname::unicode:chardata().
new(Fontname)
- when is_list(Fontname) ->
+ when ?is_chardata(Fontname) ->
Fontname_UC = unicode:characters_to_binary([Fontname,0]),
wxe_util:construct(?wxFont_new_1,
<<(byte_size(Fontname_UC)):32/?UI,(Fontname_UC)/binary, 0:(((8- ((4+byte_size(Fontname_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -183,7 +183,7 @@ setDefaultEncoding(Encoding)
-spec setFaceName(This, FaceName) -> boolean() when
This::wxFont(), FaceName::unicode:chardata().
setFaceName(#wx_ref{type=ThisT,ref=ThisRef},FaceName)
- when is_list(FaceName) ->
+ when ?is_chardata(FaceName) ->
?CLASS(ThisT,wxFont),
FaceName_UC = unicode:characters_to_binary([FaceName,0]),
wxe_util:call(?wxFont_SetFaceName,
diff --git a/lib/wx/src/gen/wxFontDialog.erl b/lib/wx/src/gen/wxFontDialog.erl
index 3e6a913973..26010aa46b 100644
--- a/lib/wx/src/gen/wxFontDialog.erl
+++ b/lib/wx/src/gen/wxFontDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -199,6 +199,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -515,6 +517,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxFontPickerCtrl.erl b/lib/wx/src/gen/wxFontPickerCtrl.erl
index 0356f795eb..d1234c5589 100644
--- a/lib/wx/src/gen/wxFontPickerCtrl.erl
+++ b/lib/wx/src/gen/wxFontPickerCtrl.erl
@@ -40,17 +40,18 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getInternalMargin/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPickerCtrlProportion/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getInternalMargin/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPickerCtrlProportion/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextCtrl/1,
+ getTextCtrlProportion/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1,
hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,
isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,
@@ -227,6 +228,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -543,6 +546,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxFrame.erl b/lib/wx/src/gen/wxFrame.erl
index 93aad5b235..1dc6106bfa 100644
--- a/lib/wx/src/gen/wxFrame.erl
+++ b/lib/wx/src/gen/wxFrame.erl
@@ -43,32 +43,32 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,
- getParent/1,getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,
- getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
- getTextExtent/2,getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,
- getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
- hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
- inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
- isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
- isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
- layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,
- maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1,
- screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
- setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
- setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
- setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
+ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
+ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
+ isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
+ isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
+ isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
+ makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
+ screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
+ scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,
+ setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,
+ setIcons/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
@@ -99,7 +99,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
new(Parent,Id,Title)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
new(Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxframe.html#wxframewxframe">external documentation</a>.
@@ -109,7 +109,7 @@ new(Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -125,7 +125,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
This::wxFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
create(This,Parent,Id,Title)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
create(This,Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxframe.html#wxframecreate">external documentation</a>.
@@ -135,7 +135,7 @@ create(This,Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ThisT,wxFrame),
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -284,7 +284,7 @@ setStatusBarPane(#wx_ref{type=ThisT,ref=ThisRef},N)
This::wxFrame(), Text::unicode:chardata().
setStatusText(This,Text)
- when is_record(This, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),?is_chardata(Text) ->
setStatusText(This,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxframe.html#wxframesetstatustext">external documentation</a>.
@@ -292,7 +292,7 @@ setStatusText(This,Text)
This::wxFrame(), Text::unicode:chardata(),
Option :: {'number', integer()}.
setStatusText(#wx_ref{type=ThisT,ref=ThisRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxFrame),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({number, Number}, Acc) -> [<<1:32/?UI,Number:32/?UI>>|Acc];
@@ -375,6 +375,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -695,6 +697,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxGLCanvas.erl b/lib/wx/src/gen/wxGLCanvas.erl
index 2007047bd3..8a94d1df26 100644
--- a/lib/wx/src/gen/wxGLCanvas.erl
+++ b/lib/wx/src/gen/wxGLCanvas.erl
@@ -37,29 +37,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -194,6 +194,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -514,6 +516,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxGauge.erl b/lib/wx/src/gen/wxGauge.erl
index fa2e7618e8..40f7f120b0 100644
--- a/lib/wx/src/gen/wxGauge.erl
+++ b/lib/wx/src/gen/wxGauge.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -204,6 +204,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -520,6 +522,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxGenericDirCtrl.erl b/lib/wx/src/gen/wxGenericDirCtrl.erl
index 3ea99c682d..383d592269 100644
--- a/lib/wx/src/gen/wxGenericDirCtrl.erl
+++ b/lib/wx/src/gen/wxGenericDirCtrl.erl
@@ -41,29 +41,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -175,7 +175,7 @@ collapseTree(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec expandPath(This, Path) -> boolean() when
This::wxGenericDirCtrl(), Path::unicode:chardata().
expandPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
- when is_list(Path) ->
+ when ?is_chardata(Path) ->
?CLASS(ThisT,wxGenericDirCtrl),
Path_UC = unicode:characters_to_binary([Path,0]),
wxe_util:call(?wxGenericDirCtrl_ExpandPath,
@@ -249,7 +249,7 @@ reCreateTree(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setDefaultPath(This, Path) -> 'ok' when
This::wxGenericDirCtrl(), Path::unicode:chardata().
setDefaultPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
- when is_list(Path) ->
+ when ?is_chardata(Path) ->
?CLASS(ThisT,wxGenericDirCtrl),
Path_UC = unicode:characters_to_binary([Path,0]),
wxe_util:cast(?wxGenericDirCtrl_SetDefaultPath,
@@ -259,7 +259,7 @@ setDefaultPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
-spec setFilter(This, Filter) -> 'ok' when
This::wxGenericDirCtrl(), Filter::unicode:chardata().
setFilter(#wx_ref{type=ThisT,ref=ThisRef},Filter)
- when is_list(Filter) ->
+ when ?is_chardata(Filter) ->
?CLASS(ThisT,wxGenericDirCtrl),
Filter_UC = unicode:characters_to_binary([Filter,0]),
wxe_util:cast(?wxGenericDirCtrl_SetFilter,
@@ -278,7 +278,7 @@ setFilterIndex(#wx_ref{type=ThisT,ref=ThisRef},N)
-spec setPath(This, Path) -> 'ok' when
This::wxGenericDirCtrl(), Path::unicode:chardata().
setPath(#wx_ref{type=ThisT,ref=ThisRef},Path)
- when is_list(Path) ->
+ when ?is_chardata(Path) ->
?CLASS(ThisT,wxGenericDirCtrl),
Path_UC = unicode:characters_to_binary([Path,0]),
wxe_util:cast(?wxGenericDirCtrl_SetPath,
@@ -297,6 +297,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -613,6 +615,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxGraphicsContext.erl b/lib/wx/src/gen/wxGraphicsContext.erl
index 0aa2119210..2d0271ac48 100644
--- a/lib/wx/src/gen/wxGraphicsContext.erl
+++ b/lib/wx/src/gen/wxGraphicsContext.erl
@@ -287,7 +287,7 @@ drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H,Radius)
-spec drawText(This, Str, X, Y) -> 'ok' when
This::wxGraphicsContext(), Str::unicode:chardata(), X::number(), Y::number().
drawText(#wx_ref{type=ThisT,ref=ThisRef},Str,X,Y)
- when is_list(Str),is_number(X),is_number(Y) ->
+ when ?is_chardata(Str),is_number(X),is_number(Y) ->
?CLASS(ThisT,wxGraphicsContext),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxGraphicsContext_DrawText_3,
@@ -303,13 +303,13 @@ drawText(#wx_ref{type=ThisT,ref=ThisRef},Str,X,Y)
(This, Str, X, Y, BackgroundBrush) -> 'ok' when
This::wxGraphicsContext(), Str::unicode:chardata(), X::number(), Y::number(), BackgroundBrush::wxGraphicsBrush:wxGraphicsBrush().
drawText(#wx_ref{type=ThisT,ref=ThisRef},Str,X,Y,Angle)
- when is_list(Str),is_number(X),is_number(Y),is_number(Angle) ->
+ when ?is_chardata(Str),is_number(X),is_number(Y),is_number(Angle) ->
?CLASS(ThisT,wxGraphicsContext),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxGraphicsContext_DrawText_4_0,
<<ThisRef:32/?UI,(byte_size(Str_UC)):32/?UI,(Str_UC)/binary, 0:(((8- ((0+byte_size(Str_UC)) band 16#7)) band 16#7))/unit:8,X:64/?F,Y:64/?F,Angle:64/?F>>);
drawText(#wx_ref{type=ThisT,ref=ThisRef},Str,X,Y,#wx_ref{type=BackgroundBrushT,ref=BackgroundBrushRef})
- when is_list(Str),is_number(X),is_number(Y) ->
+ when ?is_chardata(Str),is_number(X),is_number(Y) ->
?CLASS(ThisT,wxGraphicsContext),
Str_UC = unicode:characters_to_binary([Str,0]),
?CLASS(BackgroundBrushT,wxGraphicsBrush),
@@ -320,7 +320,7 @@ drawText(#wx_ref{type=ThisT,ref=ThisRef},Str,X,Y,#wx_ref{type=BackgroundBrushT,r
-spec drawText(This, Str, X, Y, Angle, BackgroundBrush) -> 'ok' when
This::wxGraphicsContext(), Str::unicode:chardata(), X::number(), Y::number(), Angle::number(), BackgroundBrush::wxGraphicsBrush:wxGraphicsBrush().
drawText(#wx_ref{type=ThisT,ref=ThisRef},Str,X,Y,Angle,#wx_ref{type=BackgroundBrushT,ref=BackgroundBrushRef})
- when is_list(Str),is_number(X),is_number(Y),is_number(Angle) ->
+ when ?is_chardata(Str),is_number(X),is_number(Y),is_number(Angle) ->
?CLASS(ThisT,wxGraphicsContext),
Str_UC = unicode:characters_to_binary([Str,0]),
?CLASS(BackgroundBrushT,wxGraphicsBrush),
@@ -363,7 +363,7 @@ strokePath(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PathT,ref=PathRef}) ->
-spec getPartialTextExtents(This, Text) -> [number()] when
This::wxGraphicsContext(), Text::unicode:chardata().
getPartialTextExtents(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxGraphicsContext),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxGraphicsContext_GetPartialTextExtents,
@@ -374,7 +374,7 @@ getPartialTextExtents(#wx_ref{type=ThisT,ref=ThisRef},Text)
Result ::{Width::number(), Height::number(), Descent::number(), ExternalLeading::number()},
This::wxGraphicsContext(), Text::unicode:chardata().
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxGraphicsContext),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxGraphicsContext_GetTextExtent,
diff --git a/lib/wx/src/gen/wxGrid.erl b/lib/wx/src/gen/wxGrid.erl
index a1533cbd9f..b8c94ab555 100644
--- a/lib/wx/src/gen/wxGrid.erl
+++ b/lib/wx/src/gen/wxGrid.erl
@@ -91,37 +91,37 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- doPrepareDC/2,enable/1,enable/2,enableScrolling/3,findWindow/2,fitInside/1,
- freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
- getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
- getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPixelsPerUnit/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getToolTip/1,getUpdateRegion/1,getViewStart/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scroll/3,
- scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
- setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2,
- setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
- setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
- setScrollPos/4,setScrollRate/3,setScrollbar/5,setScrollbar/6,setScrollbars/5,
- setScrollbars/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,
- setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,
- setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,setToolTip/2,
- setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ doPrepareDC/2,dragAcceptFiles/2,enable/1,enable/2,enableScrolling/3,
+ findWindow/2,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
+ getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,
+ getChildren/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPixelsPerUnit/1,
+ getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
+ getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getViewStart/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,raise/1,refresh/1,refresh/2,
+ refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,
+ screenToClient/1,screenToClient/2,scroll/3,scrollLines/2,scrollPages/2,
+ scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
+ setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
+ setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
+ setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ setPalette/2,setScrollPos/3,setScrollPos/4,setScrollRate/3,setScrollbar/5,
+ setScrollbar/6,setScrollbars/5,setScrollbars/6,setSize/2,setSize/3,
+ setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,
+ setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
@@ -851,7 +851,7 @@ getDefaultEditorForCell(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
-spec getDefaultEditorForType(This, TypeName) -> wxGridCellEditor:wxGridCellEditor() when
This::wxGrid(), TypeName::unicode:chardata().
getDefaultEditorForType(#wx_ref{type=ThisT,ref=ThisRef},TypeName)
- when is_list(TypeName) ->
+ when ?is_chardata(TypeName) ->
?CLASS(ThisT,wxGrid),
TypeName_UC = unicode:characters_to_binary([TypeName,0]),
wxe_util:call(?wxGrid_GetDefaultEditorForType,
@@ -878,7 +878,7 @@ getDefaultRendererForCell(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
-spec getDefaultRendererForType(This, TypeName) -> wxGridCellRenderer:wxGridCellRenderer() when
This::wxGrid(), TypeName::unicode:chardata().
getDefaultRendererForType(#wx_ref{type=ThisT,ref=ThisRef},TypeName)
- when is_list(TypeName) ->
+ when ?is_chardata(TypeName) ->
?CLASS(ThisT,wxGrid),
TypeName_UC = unicode:characters_to_binary([TypeName,0]),
wxe_util:call(?wxGrid_GetDefaultRendererForType,
@@ -1407,7 +1407,7 @@ movePageUp(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec registerDataType(This, TypeName, Renderer, Editor) -> 'ok' when
This::wxGrid(), TypeName::unicode:chardata(), Renderer::wxGridCellRenderer:wxGridCellRenderer(), Editor::wxGridCellEditor:wxGridCellEditor().
registerDataType(#wx_ref{type=ThisT,ref=ThisRef},TypeName,#wx_ref{type=RendererT,ref=RendererRef},#wx_ref{type=EditorT,ref=EditorRef})
- when is_list(TypeName) ->
+ when ?is_chardata(TypeName) ->
?CLASS(ThisT,wxGrid),
TypeName_UC = unicode:characters_to_binary([TypeName,0]),
?CLASS(RendererT,wxGridCellRenderer),
@@ -1634,7 +1634,7 @@ setCellTextColour(#wx_ref{type=ThisT,ref=ThisRef},Val,Row,Col)
-spec setCellValue(This, Coords, S) -> 'ok' when
This::wxGrid(), Coords::{R::integer(), C::integer()}, S::unicode:chardata().
setCellValue(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC},S)
- when is_integer(CoordsR),is_integer(CoordsC),is_list(S) ->
+ when is_integer(CoordsR),is_integer(CoordsC),?is_chardata(S) ->
?CLASS(ThisT,wxGrid),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:cast(?wxGrid_SetCellValue_2,
@@ -1650,13 +1650,13 @@ setCellValue(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC},S)
(This, Val, Row, Col) -> 'ok' when
This::wxGrid(), Val::unicode:chardata(), Row::integer(), Col::integer().
setCellValue(#wx_ref{type=ThisT,ref=ThisRef},Row,Col,S)
- when is_integer(Row),is_integer(Col),is_list(S) ->
+ when is_integer(Row),is_integer(Col),?is_chardata(S) ->
?CLASS(ThisT,wxGrid),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:cast(?wxGrid_SetCellValue_3_0,
<<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI,(byte_size(S_UC)):32/?UI,(S_UC)/binary, 0:(((8- ((0+byte_size(S_UC)) band 16#7)) band 16#7))/unit:8>>);
setCellValue(#wx_ref{type=ThisT,ref=ThisRef},Val,Row,Col)
- when is_list(Val),is_integer(Row),is_integer(Col) ->
+ when ?is_chardata(Val),is_integer(Row),is_integer(Col) ->
?CLASS(ThisT,wxGrid),
Val_UC = unicode:characters_to_binary([Val,0]),
wxe_util:cast(?wxGrid_SetCellValue_3_1,
@@ -1717,7 +1717,7 @@ setColFormatFloat(#wx_ref{type=ThisT,ref=ThisRef},Col, Options)
-spec setColFormatCustom(This, Col, TypeName) -> 'ok' when
This::wxGrid(), Col::integer(), TypeName::unicode:chardata().
setColFormatCustom(#wx_ref{type=ThisT,ref=ThisRef},Col,TypeName)
- when is_integer(Col),is_list(TypeName) ->
+ when is_integer(Col),?is_chardata(TypeName) ->
?CLASS(ThisT,wxGrid),
TypeName_UC = unicode:characters_to_binary([TypeName,0]),
wxe_util:cast(?wxGrid_SetColFormatCustom,
@@ -1745,7 +1745,7 @@ setColLabelSize(#wx_ref{type=ThisT,ref=ThisRef},Height)
-spec setColLabelValue(This, Col, Val) -> 'ok' when
This::wxGrid(), Col::integer(), Val::unicode:chardata().
setColLabelValue(#wx_ref{type=ThisT,ref=ThisRef},Col,Val)
- when is_integer(Col),is_list(Val) ->
+ when is_integer(Col),?is_chardata(Val) ->
?CLASS(ThisT,wxGrid),
Val_UC = unicode:characters_to_binary([Val,0]),
wxe_util:cast(?wxGrid_SetColLabelValue,
@@ -1981,7 +1981,7 @@ setRowLabelSize(#wx_ref{type=ThisT,ref=ThisRef},Width)
-spec setRowLabelValue(This, Row, Val) -> 'ok' when
This::wxGrid(), Row::integer(), Val::unicode:chardata().
setRowLabelValue(#wx_ref{type=ThisT,ref=ThisRef},Row,Val)
- when is_integer(Row),is_list(Val) ->
+ when is_integer(Row),?is_chardata(Val) ->
?CLASS(ThisT,wxGrid),
Val_UC = unicode:characters_to_binary([Val,0]),
wxe_util:cast(?wxGrid_SetRowLabelValue,
@@ -2158,6 +2158,8 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This).
initDialog(This) -> wxPanel:initDialog(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -2474,6 +2476,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxGridCellBoolEditor.erl b/lib/wx/src/gen/wxGridCellBoolEditor.erl
index 1d949d54ff..59348f94f8 100644
--- a/lib/wx/src/gen/wxGridCellBoolEditor.erl
+++ b/lib/wx/src/gen/wxGridCellBoolEditor.erl
@@ -52,7 +52,7 @@ new() ->
-spec isTrueValue(Value) -> boolean() when
Value::unicode:chardata().
isTrueValue(Value)
- when is_list(Value) ->
+ when ?is_chardata(Value) ->
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:call(?wxGridCellBoolEditor_IsTrueValue,
<<(byte_size(Value_UC)):32/?UI,(Value_UC)/binary, 0:(((8- ((4+byte_size(Value_UC)) band 16#7)) band 16#7))/unit:8>>).
diff --git a/lib/wx/src/gen/wxGridCellChoiceEditor.erl b/lib/wx/src/gen/wxGridCellChoiceEditor.erl
index d5487c3618..8f4a07a0bb 100644
--- a/lib/wx/src/gen/wxGridCellChoiceEditor.erl
+++ b/lib/wx/src/gen/wxGridCellChoiceEditor.erl
@@ -68,7 +68,7 @@ new(Choices, Options)
-spec setParameters(This, Params) -> 'ok' when
This::wxGridCellChoiceEditor(), Params::unicode:chardata().
setParameters(#wx_ref{type=ThisT,ref=ThisRef},Params)
- when is_list(Params) ->
+ when ?is_chardata(Params) ->
?CLASS(ThisT,wxGridCellChoiceEditor),
Params_UC = unicode:characters_to_binary([Params,0]),
wxe_util:cast(?wxGridCellChoiceEditor_SetParameters,
diff --git a/lib/wx/src/gen/wxGridCellFloatEditor.erl b/lib/wx/src/gen/wxGridCellFloatEditor.erl
index 6e85469ecf..90b9542afc 100644
--- a/lib/wx/src/gen/wxGridCellFloatEditor.erl
+++ b/lib/wx/src/gen/wxGridCellFloatEditor.erl
@@ -65,7 +65,7 @@ new(Options)
-spec setParameters(This, Params) -> 'ok' when
This::wxGridCellFloatEditor(), Params::unicode:chardata().
setParameters(#wx_ref{type=ThisT,ref=ThisRef},Params)
- when is_list(Params) ->
+ when ?is_chardata(Params) ->
?CLASS(ThisT,wxGridCellFloatEditor),
Params_UC = unicode:characters_to_binary([Params,0]),
wxe_util:cast(?wxGridCellFloatEditor_SetParameters,
diff --git a/lib/wx/src/gen/wxGridCellFloatRenderer.erl b/lib/wx/src/gen/wxGridCellFloatRenderer.erl
index ccb29902b3..72bdc6fc29 100644
--- a/lib/wx/src/gen/wxGridCellFloatRenderer.erl
+++ b/lib/wx/src/gen/wxGridCellFloatRenderer.erl
@@ -81,7 +81,7 @@ getWidth(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setParameters(This, Params) -> 'ok' when
This::wxGridCellFloatRenderer(), Params::unicode:chardata().
setParameters(#wx_ref{type=ThisT,ref=ThisRef},Params)
- when is_list(Params) ->
+ when ?is_chardata(Params) ->
?CLASS(ThisT,wxGridCellFloatRenderer),
Params_UC = unicode:characters_to_binary([Params,0]),
wxe_util:cast(?wxGridCellFloatRenderer_SetParameters,
diff --git a/lib/wx/src/gen/wxGridCellNumberEditor.erl b/lib/wx/src/gen/wxGridCellNumberEditor.erl
index 7a47024b2f..22f9a1839c 100644
--- a/lib/wx/src/gen/wxGridCellNumberEditor.erl
+++ b/lib/wx/src/gen/wxGridCellNumberEditor.erl
@@ -75,7 +75,7 @@ getValue(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setParameters(This, Params) -> 'ok' when
This::wxGridCellNumberEditor(), Params::unicode:chardata().
setParameters(#wx_ref{type=ThisT,ref=ThisRef},Params)
- when is_list(Params) ->
+ when ?is_chardata(Params) ->
?CLASS(ThisT,wxGridCellNumberEditor),
Params_UC = unicode:characters_to_binary([Params,0]),
wxe_util:cast(?wxGridCellNumberEditor_SetParameters,
diff --git a/lib/wx/src/gen/wxGridCellTextEditor.erl b/lib/wx/src/gen/wxGridCellTextEditor.erl
index 4ddb4a7028..39adda5d8b 100644
--- a/lib/wx/src/gen/wxGridCellTextEditor.erl
+++ b/lib/wx/src/gen/wxGridCellTextEditor.erl
@@ -52,7 +52,7 @@ new() ->
-spec setParameters(This, Params) -> 'ok' when
This::wxGridCellTextEditor(), Params::unicode:chardata().
setParameters(#wx_ref{type=ThisT,ref=ThisRef},Params)
- when is_list(Params) ->
+ when ?is_chardata(Params) ->
?CLASS(ThisT,wxGridCellTextEditor),
Params_UC = unicode:characters_to_binary([Params,0]),
wxe_util:cast(?wxGridCellTextEditor_SetParameters,
diff --git a/lib/wx/src/gen/wxHtmlEasyPrinting.erl b/lib/wx/src/gen/wxHtmlEasyPrinting.erl
index a2cf46ed8d..dfb9dcfa1c 100644
--- a/lib/wx/src/gen/wxHtmlEasyPrinting.erl
+++ b/lib/wx/src/gen/wxHtmlEasyPrinting.erl
@@ -77,7 +77,7 @@ getPageSetupData(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec previewFile(This, Htmlfile) -> boolean() when
This::wxHtmlEasyPrinting(), Htmlfile::unicode:chardata().
previewFile(#wx_ref{type=ThisT,ref=ThisRef},Htmlfile)
- when is_list(Htmlfile) ->
+ when ?is_chardata(Htmlfile) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Htmlfile_UC = unicode:characters_to_binary([Htmlfile,0]),
wxe_util:call(?wxHtmlEasyPrinting_PreviewFile,
@@ -88,7 +88,7 @@ previewFile(#wx_ref{type=ThisT,ref=ThisRef},Htmlfile)
This::wxHtmlEasyPrinting(), Htmltext::unicode:chardata().
previewText(This,Htmltext)
- when is_record(This, wx_ref),is_list(Htmltext) ->
+ when is_record(This, wx_ref),?is_chardata(Htmltext) ->
previewText(This,Htmltext, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxhtmleasyprinting.html#wxhtmleasyprintingpreviewtext">external documentation</a>.
@@ -96,7 +96,7 @@ previewText(This,Htmltext)
This::wxHtmlEasyPrinting(), Htmltext::unicode:chardata(),
Option :: {'basepath', unicode:chardata()}.
previewText(#wx_ref{type=ThisT,ref=ThisRef},Htmltext, Options)
- when is_list(Htmltext),is_list(Options) ->
+ when ?is_chardata(Htmltext),is_list(Options) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Htmltext_UC = unicode:characters_to_binary([Htmltext,0]),
MOpts = fun({basepath, Basepath}, Acc) -> Basepath_UC = unicode:characters_to_binary([Basepath,0]),[<<1:32/?UI,(byte_size(Basepath_UC)):32/?UI,(Basepath_UC)/binary, 0:(((8- ((0+byte_size(Basepath_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -109,7 +109,7 @@ previewText(#wx_ref{type=ThisT,ref=ThisRef},Htmltext, Options)
-spec printFile(This, Htmlfile) -> boolean() when
This::wxHtmlEasyPrinting(), Htmlfile::unicode:chardata().
printFile(#wx_ref{type=ThisT,ref=ThisRef},Htmlfile)
- when is_list(Htmlfile) ->
+ when ?is_chardata(Htmlfile) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Htmlfile_UC = unicode:characters_to_binary([Htmlfile,0]),
wxe_util:call(?wxHtmlEasyPrinting_PrintFile,
@@ -120,7 +120,7 @@ printFile(#wx_ref{type=ThisT,ref=ThisRef},Htmlfile)
This::wxHtmlEasyPrinting(), Htmltext::unicode:chardata().
printText(This,Htmltext)
- when is_record(This, wx_ref),is_list(Htmltext) ->
+ when is_record(This, wx_ref),?is_chardata(Htmltext) ->
printText(This,Htmltext, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxhtmleasyprinting.html#wxhtmleasyprintingprinttext">external documentation</a>.
@@ -128,7 +128,7 @@ printText(This,Htmltext)
This::wxHtmlEasyPrinting(), Htmltext::unicode:chardata(),
Option :: {'basepath', unicode:chardata()}.
printText(#wx_ref{type=ThisT,ref=ThisRef},Htmltext, Options)
- when is_list(Htmltext),is_list(Options) ->
+ when ?is_chardata(Htmltext),is_list(Options) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Htmltext_UC = unicode:characters_to_binary([Htmltext,0]),
MOpts = fun({basepath, Basepath}, Acc) -> Basepath_UC = unicode:characters_to_binary([Basepath,0]),[<<1:32/?UI,(byte_size(Basepath_UC)):32/?UI,(Basepath_UC)/binary, 0:(((8- ((0+byte_size(Basepath_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -150,7 +150,7 @@ pageSetup(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxHtmlEasyPrinting(), Normal_face::unicode:chardata(), Fixed_face::unicode:chardata().
setFonts(This,Normal_face,Fixed_face)
- when is_record(This, wx_ref),is_list(Normal_face),is_list(Fixed_face) ->
+ when is_record(This, wx_ref),?is_chardata(Normal_face),?is_chardata(Fixed_face) ->
setFonts(This,Normal_face,Fixed_face, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxhtmleasyprinting.html#wxhtmleasyprintingsetfonts">external documentation</a>.
@@ -158,7 +158,7 @@ setFonts(This,Normal_face,Fixed_face)
This::wxHtmlEasyPrinting(), Normal_face::unicode:chardata(), Fixed_face::unicode:chardata(),
Option :: {'sizes', [integer()]}.
setFonts(#wx_ref{type=ThisT,ref=ThisRef},Normal_face,Fixed_face, Options)
- when is_list(Normal_face),is_list(Fixed_face),is_list(Options) ->
+ when ?is_chardata(Normal_face),?is_chardata(Fixed_face),is_list(Options) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Normal_face_UC = unicode:characters_to_binary([Normal_face,0]),
Fixed_face_UC = unicode:characters_to_binary([Fixed_face,0]),
@@ -174,7 +174,7 @@ setFonts(#wx_ref{type=ThisT,ref=ThisRef},Normal_face,Fixed_face, Options)
This::wxHtmlEasyPrinting(), Header::unicode:chardata().
setHeader(This,Header)
- when is_record(This, wx_ref),is_list(Header) ->
+ when is_record(This, wx_ref),?is_chardata(Header) ->
setHeader(This,Header, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxhtmleasyprinting.html#wxhtmleasyprintingsetheader">external documentation</a>.
@@ -182,7 +182,7 @@ setHeader(This,Header)
This::wxHtmlEasyPrinting(), Header::unicode:chardata(),
Option :: {'pg', integer()}.
setHeader(#wx_ref{type=ThisT,ref=ThisRef},Header, Options)
- when is_list(Header),is_list(Options) ->
+ when ?is_chardata(Header),is_list(Options) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Header_UC = unicode:characters_to_binary([Header,0]),
MOpts = fun({pg, Pg}, Acc) -> [<<1:32/?UI,Pg:32/?UI>>|Acc];
@@ -196,7 +196,7 @@ setHeader(#wx_ref{type=ThisT,ref=ThisRef},Header, Options)
This::wxHtmlEasyPrinting(), Footer::unicode:chardata().
setFooter(This,Footer)
- when is_record(This, wx_ref),is_list(Footer) ->
+ when is_record(This, wx_ref),?is_chardata(Footer) ->
setFooter(This,Footer, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxhtmleasyprinting.html#wxhtmleasyprintingsetfooter">external documentation</a>.
@@ -204,7 +204,7 @@ setFooter(This,Footer)
This::wxHtmlEasyPrinting(), Footer::unicode:chardata(),
Option :: {'pg', integer()}.
setFooter(#wx_ref{type=ThisT,ref=ThisRef},Footer, Options)
- when is_list(Footer),is_list(Options) ->
+ when ?is_chardata(Footer),is_list(Options) ->
?CLASS(ThisT,wxHtmlEasyPrinting),
Footer_UC = unicode:characters_to_binary([Footer,0]),
MOpts = fun({pg, Pg}, Acc) -> [<<1:32/?UI,Pg:32/?UI>>|Acc];
diff --git a/lib/wx/src/gen/wxHtmlWindow.erl b/lib/wx/src/gen/wxHtmlWindow.erl
index f9bb135fcf..7e3906b9a9 100644
--- a/lib/wx/src/gen/wxHtmlWindow.erl
+++ b/lib/wx/src/gen/wxHtmlWindow.erl
@@ -45,37 +45,37 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- doPrepareDC/2,enable/1,enable/2,enableScrolling/3,findWindow/2,fit/1,
- fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
+ doPrepareDC/2,dragAcceptFiles/2,enable/1,enable/2,enableScrolling/3,
+ findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,
- getChildren/1,getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPixelsPerUnit/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getToolTip/1,getUpdateRegion/1,getViewStart/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scroll/3,
- scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
- setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2,
- setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
- setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
- setScrollPos/4,setScrollRate/3,setScrollbar/5,setScrollbar/6,setScrollbars/5,
- setScrollbars/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,
- setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,
- setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,setToolTip/2,
- setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ getChildren/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPixelsPerUnit/1,
+ getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
+ getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getViewStart/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,raise/1,refresh/1,refresh/2,
+ refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,
+ screenToClient/1,screenToClient/2,scroll/3,scrollLines/2,scrollPages/2,
+ scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
+ setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
+ setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
+ setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ setPalette/2,setScrollPos/3,setScrollPos/4,setScrollRate/3,setScrollbar/5,
+ setScrollbar/6,setScrollbars/5,setScrollbars/6,setSize/2,setSize/3,
+ setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,
+ setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
@@ -127,7 +127,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
-spec appendToPage(This, Source) -> boolean() when
This::wxHtmlWindow(), Source::unicode:chardata().
appendToPage(#wx_ref{type=ThisT,ref=ThisRef},Source)
- when is_list(Source) ->
+ when ?is_chardata(Source) ->
?CLASS(ThisT,wxHtmlWindow),
Source_UC = unicode:characters_to_binary([Source,0]),
wxe_util:call(?wxHtmlWindow_AppendToPage,
@@ -209,7 +209,7 @@ historyForward(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec loadFile(This, Filename) -> boolean() when
This::wxHtmlWindow(), Filename::unicode:chardata().
loadFile(#wx_ref{type=ThisT,ref=ThisRef},Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
?CLASS(ThisT,wxHtmlWindow),
Filename_UC = unicode:characters_to_binary([Filename,0]),
wxe_util:call(?wxHtmlWindow_LoadFile,
@@ -219,7 +219,7 @@ loadFile(#wx_ref{type=ThisT,ref=ThisRef},Filename)
-spec loadPage(This, Location) -> boolean() when
This::wxHtmlWindow(), Location::unicode:chardata().
loadPage(#wx_ref{type=ThisT,ref=ThisRef},Location)
- when is_list(Location) ->
+ when ?is_chardata(Location) ->
?CLASS(ThisT,wxHtmlWindow),
Location_UC = unicode:characters_to_binary([Location,0]),
wxe_util:call(?wxHtmlWindow_LoadPage,
@@ -273,7 +273,7 @@ setBorders(#wx_ref{type=ThisT,ref=ThisRef},B)
This::wxHtmlWindow(), Normal_face::unicode:chardata(), Fixed_face::unicode:chardata().
setFonts(This,Normal_face,Fixed_face)
- when is_record(This, wx_ref),is_list(Normal_face),is_list(Fixed_face) ->
+ when is_record(This, wx_ref),?is_chardata(Normal_face),?is_chardata(Fixed_face) ->
setFonts(This,Normal_face,Fixed_face, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxhtmlwindow.html#wxhtmlwindowsetfonts">external documentation</a>.
@@ -281,7 +281,7 @@ setFonts(This,Normal_face,Fixed_face)
This::wxHtmlWindow(), Normal_face::unicode:chardata(), Fixed_face::unicode:chardata(),
Option :: {'sizes', integer()}.
setFonts(#wx_ref{type=ThisT,ref=ThisRef},Normal_face,Fixed_face, Options)
- when is_list(Normal_face),is_list(Fixed_face),is_list(Options) ->
+ when ?is_chardata(Normal_face),?is_chardata(Fixed_face),is_list(Options) ->
?CLASS(ThisT,wxHtmlWindow),
Normal_face_UC = unicode:characters_to_binary([Normal_face,0]),
Fixed_face_UC = unicode:characters_to_binary([Fixed_face,0]),
@@ -295,7 +295,7 @@ setFonts(#wx_ref{type=ThisT,ref=ThisRef},Normal_face,Fixed_face, Options)
-spec setPage(This, Source) -> boolean() when
This::wxHtmlWindow(), Source::unicode:chardata().
setPage(#wx_ref{type=ThisT,ref=ThisRef},Source)
- when is_list(Source) ->
+ when ?is_chardata(Source) ->
?CLASS(ThisT,wxHtmlWindow),
Source_UC = unicode:characters_to_binary([Source,0]),
wxe_util:call(?wxHtmlWindow_SetPage,
@@ -305,7 +305,7 @@ setPage(#wx_ref{type=ThisT,ref=ThisRef},Source)
-spec setRelatedFrame(This, Frame, Format) -> 'ok' when
This::wxHtmlWindow(), Frame::wxFrame:wxFrame(), Format::unicode:chardata().
setRelatedFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FrameT,ref=FrameRef},Format)
- when is_list(Format) ->
+ when ?is_chardata(Format) ->
?CLASS(ThisT,wxHtmlWindow),
?CLASS(FrameT,wxFrame),
Format_UC = unicode:characters_to_binary([Format,0]),
@@ -371,6 +371,8 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This).
initDialog(This) -> wxPanel:initDialog(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -689,6 +691,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxIcon.erl b/lib/wx/src/gen/wxIcon.erl
index c9ec32dffc..9739a403ff 100644
--- a/lib/wx/src/gen/wxIcon.erl
+++ b/lib/wx/src/gen/wxIcon.erl
@@ -60,7 +60,7 @@ new() ->
Loc::wx:wx_object().
new(Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
new(Filename, []);
new(#wx_ref{type=LocT,ref=LocRef}) ->
?CLASS(LocT,wx),
@@ -75,7 +75,7 @@ new(#wx_ref{type=LocT,ref=LocRef}) ->
| {'desiredWidth', integer()}
| {'desiredHeight', integer()}.
new(Filename, Options)
- when is_list(Filename),is_list(Options) ->
+ when ?is_chardata(Filename),is_list(Options) ->
Filename_UC = unicode:characters_to_binary([Filename,0]),
MOpts = fun({type, Type}, Acc) -> [<<1:32/?UI,Type:32/?UI>>|Acc];
({desiredWidth, DesiredWidth}, Acc) -> [<<2:32/?UI,DesiredWidth:32/?UI>>|Acc];
diff --git a/lib/wx/src/gen/wxIconBundle.erl b/lib/wx/src/gen/wxIconBundle.erl
index 47785963e3..aecf382a9f 100644
--- a/lib/wx/src/gen/wxIconBundle.erl
+++ b/lib/wx/src/gen/wxIconBundle.erl
@@ -58,7 +58,7 @@ new(#wx_ref{type=IcT,ref=IcRef}) ->
-spec new(File, Type) -> wxIconBundle() when
File::unicode:chardata(), Type::integer().
new(File,Type)
- when is_list(File),is_integer(Type) ->
+ when ?is_chardata(File),is_integer(Type) ->
File_UC = unicode:characters_to_binary([File,0]),
wxe_util:construct(?wxIconBundle_new_2,
<<(byte_size(File_UC)):32/?UI,(File_UC)/binary, 0:(((8- ((4+byte_size(File_UC)) band 16#7)) band 16#7))/unit:8,Type:32/?UI>>).
@@ -76,7 +76,7 @@ addIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef}) ->
-spec addIcon(This, File, Type) -> 'ok' when
This::wxIconBundle(), File::unicode:chardata(), Type::integer().
addIcon(#wx_ref{type=ThisT,ref=ThisRef},File,Type)
- when is_list(File),is_integer(Type) ->
+ when ?is_chardata(File),is_integer(Type) ->
?CLASS(ThisT,wxIconBundle),
File_UC = unicode:characters_to_binary([File,0]),
wxe_util:cast(?wxIconBundle_AddIcon_2,
diff --git a/lib/wx/src/gen/wxImage.erl b/lib/wx/src/gen/wxImage.erl
index e82f3d609e..f3b3d393d1 100644
--- a/lib/wx/src/gen/wxImage.erl
+++ b/lib/wx/src/gen/wxImage.erl
@@ -64,7 +64,7 @@ new() ->
Name::unicode:chardata().
new(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
new(Name, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wximage.html#wximagewximage">external documentation</a>.
@@ -85,7 +85,7 @@ new(Width,Height)
when is_integer(Width),is_integer(Height) ->
new(Width,Height, []);
new(Name, Options)
- when is_list(Name),is_list(Options) ->
+ when ?is_chardata(Name),is_list(Options) ->
Name_UC = unicode:characters_to_binary([Name,0]),
MOpts = fun({type, Type}, Acc) -> [<<1:32/?UI,Type:32/?UI>>|Acc];
({index, Index}, Acc) -> [<<2:32/?UI,Index:32/?UI>>|Acc];
@@ -123,7 +123,7 @@ new(Width,Height, Options)
wxe_util:construct(?wxImage_new_3_0,
<<Width:32/?UI,Height:32/?UI, BinOpt/binary>>);
new(Name,Mimetype, Options)
- when is_list(Name),is_list(Mimetype),is_list(Options) ->
+ when ?is_chardata(Name),?is_chardata(Mimetype),is_list(Options) ->
Name_UC = unicode:characters_to_binary([Name,0]),
Mimetype_UC = unicode:characters_to_binary([Mimetype,0]),
MOpts = fun({index, Index}, Acc) -> [<<1:32/?UI,Index:32/?UI>>|Acc];
@@ -421,7 +421,7 @@ getGreen(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
Name::unicode:chardata().
getImageCount(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
getImageCount(Name, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wximage.html#wximagegetimagecount">external documentation</a>.
@@ -430,7 +430,7 @@ getImageCount(Name)
Name::unicode:chardata(),
Option :: {'type', wx:wx_enum()}.
getImageCount(Name, Options)
- when is_list(Name),is_list(Options) ->
+ when ?is_chardata(Name),is_list(Options) ->
Name_UC = unicode:characters_to_binary([Name,0]),
MOpts = fun({type, Type}, Acc) -> [<<1:32/?UI,Type:32/?UI>>|Acc];
(BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
@@ -533,7 +533,7 @@ hasMask(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec getOption(This, Name) -> unicode:charlist() when
This::wxImage(), Name::unicode:chardata().
getOption(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxImage_GetOption,
@@ -543,7 +543,7 @@ getOption(#wx_ref{type=ThisT,ref=ThisRef},Name)
-spec getOptionInt(This, Name) -> integer() when
This::wxImage(), Name::unicode:chardata().
getOptionInt(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxImage_GetOptionInt,
@@ -553,7 +553,7 @@ getOptionInt(#wx_ref{type=ThisT,ref=ThisRef},Name)
-spec hasOption(This, Name) -> boolean() when
This::wxImage(), Name::unicode:chardata().
hasOption(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxImage_HasOption,
@@ -599,7 +599,7 @@ isTransparent(#wx_ref{type=ThisT,ref=ThisRef},X,Y, Options)
This::wxImage(), Name::unicode:chardata().
loadFile(This,Name)
- when is_record(This, wx_ref),is_list(Name) ->
+ when is_record(This, wx_ref),?is_chardata(Name) ->
loadFile(This,Name, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wximage.html#wximageloadfile">external documentation</a>.
@@ -608,7 +608,7 @@ loadFile(This,Name)
Option :: {'type', integer()}
| {'index', integer()}.
loadFile(#wx_ref{type=ThisT,ref=ThisRef},Name, Options)
- when is_list(Name),is_list(Options) ->
+ when ?is_chardata(Name),is_list(Options) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
MOpts = fun({type, Type}, Acc) -> [<<1:32/?UI,Type:32/?UI>>|Acc];
@@ -623,7 +623,7 @@ loadFile(#wx_ref{type=ThisT,ref=ThisRef},Name, Options)
This::wxImage(), Name::unicode:chardata(), Mimetype::unicode:chardata(),
Option :: {'index', integer()}.
loadFile(#wx_ref{type=ThisT,ref=ThisRef},Name,Mimetype, Options)
- when is_list(Name),is_list(Mimetype),is_list(Options) ->
+ when ?is_chardata(Name),?is_chardata(Mimetype),is_list(Options) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
Mimetype_UC = unicode:characters_to_binary([Mimetype,0]),
@@ -645,7 +645,7 @@ ok(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec removeHandler(Name) -> boolean() when
Name::unicode:chardata().
removeHandler(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxImage_RemoveHandler,
<<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -784,7 +784,7 @@ rotate90(#wx_ref{type=ThisT,ref=ThisRef}, Options)
-spec saveFile(This, Name) -> boolean() when
This::wxImage(), Name::unicode:chardata().
saveFile(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxImage_SaveFile_1,
@@ -800,13 +800,13 @@ saveFile(#wx_ref{type=ThisT,ref=ThisRef},Name)
(This, Name, Mimetype) -> boolean() when
This::wxImage(), Name::unicode:chardata(), Mimetype::unicode:chardata().
saveFile(#wx_ref{type=ThisT,ref=ThisRef},Name,Type)
- when is_list(Name),is_integer(Type) ->
+ when ?is_chardata(Name),is_integer(Type) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxImage_SaveFile_2_0,
<<ThisRef:32/?UI,(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((0+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,Type:32/?UI>>);
saveFile(#wx_ref{type=ThisT,ref=ThisRef},Name,Mimetype)
- when is_list(Name),is_list(Mimetype) ->
+ when ?is_chardata(Name),?is_chardata(Mimetype) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
Mimetype_UC = unicode:characters_to_binary([Mimetype,0]),
@@ -985,13 +985,13 @@ setMaskFromImage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=MaskT,ref=MaskRef}
(This, Name, Value) -> 'ok' when
This::wxImage(), Name::unicode:chardata(), Value::unicode:chardata().
setOption(#wx_ref{type=ThisT,ref=ThisRef},Name,Value)
- when is_list(Name),is_integer(Value) ->
+ when ?is_chardata(Name),is_integer(Value) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:cast(?wxImage_SetOption_2_0,
<<ThisRef:32/?UI,(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((0+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,Value:32/?UI>>);
setOption(#wx_ref{type=ThisT,ref=ThisRef},Name,Value)
- when is_list(Name),is_list(Value) ->
+ when ?is_chardata(Name),?is_chardata(Value) ->
?CLASS(ThisT,wxImage),
Name_UC = unicode:characters_to_binary([Name,0]),
Value_UC = unicode:characters_to_binary([Value,0]),
diff --git a/lib/wx/src/gen/wxListBox.erl b/lib/wx/src/gen/wxListBox.erl
index 9ab3616e9b..86d8d41f36 100644
--- a/lib/wx/src/gen/wxListBox.erl
+++ b/lib/wx/src/gen/wxListBox.erl
@@ -40,40 +40,41 @@
centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1,
clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3,
convertDialogToPixels/2,convertPixelsToDialog/2,delete/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- findString/2,findString/3,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientData/2,getClientSize/1,
- getContainingSizer/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,
- getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSelection/1,getSize/1,getSizer/1,getString/2,getStringSelection/1,
- getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
- getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
- hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1,
- insert/3,insert/4,invalidateBestSize/1,isDoubleBuffered/1,isEmpty/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientData/3,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSelection/2,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,
- setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,
- setSizerAndFit/3,setString/3,setStringSelection/2,setThemeEnabled/2,
- setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
- setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
- setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientData/2,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,
+ getFont/1,getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSelection/1,getSize/1,getSizer/1,
+ getString/2,getStringSelection/1,getTextExtent/2,getTextExtent/3,
+ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,inheritAttributes/1,initDialog/1,insert/3,insert/4,invalidateBestSize/1,
+ isDoubleBuffered/1,isEmpty/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,
+ makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,
+ setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
+ setClientData/3,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setId/2,
+ setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSelection/2,setSize/2,
+ setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
+ setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3,
+ setStringSelection/2,setThemeEnabled/2,setToolTip/2,setTransparent/2,
+ setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,
+ setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,
+ shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
validate/1,warpPointer/3]).
@@ -220,7 +221,7 @@ setFirstItem(#wx_ref{type=ThisT,ref=ThisRef},N)
wxe_util:cast(?wxListBox_SetFirstItem_1_0,
<<ThisRef:32/?UI,N:32/?UI>>);
setFirstItem(#wx_ref{type=ThisT,ref=ThisRef},S)
- when is_list(S) ->
+ when ?is_chardata(S) ->
?CLASS(ThisT,wxListBox),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:cast(?wxListBox_SetFirstItem_1_1,
@@ -280,6 +281,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -596,6 +599,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxListCtrl.erl b/lib/wx/src/gen/wxListCtrl.erl
index d1a063d900..10dc76f276 100644
--- a/lib/wx/src/gen/wxListCtrl.erl
+++ b/lib/wx/src/gen/wxListCtrl.erl
@@ -52,38 +52,38 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,
- setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
- setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setId/2,
- setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
- setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5,
- setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
- setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2,
- setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
- setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowVariant/2,
- shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
- transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
- validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundStyle/2,setCaret/2,
+ setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ setWindowStyle/2,setWindowVariant/2,shouldInheritColours/1,show/1,
+ show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,
+ updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
-export_type([wxListCtrl/0]).
%% @hidden
@@ -94,31 +94,34 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-type wxListCtrl() :: wx:wx_object().
-%% @spec () -> wxListCtrl()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>.
+-spec new() -> wxListCtrl().
new() ->
wxe_util:construct(?wxListCtrl_new_0, <<>>).
-%% @spec (Parent::wxWindow:wxWindow()) -> wxListCtrl()
-%% @equiv new(Parent, [])
+-spec new(Parent) -> wxListCtrl() when
+ Parent::wxWindow:wxWindow().
new(Parent)
when is_record(Parent, wx_ref) ->
new(Parent, []).
-%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxListCtrl()
-%% Option = {winid, integer()} |
-%% {pos, {X::integer(),Y::integer()}} |
-%% {size, {W::integer(),H::integer()}} |
-%% {style, integer()} |
-%% {validator, wx:wx()} |
-%% {onGetItemText, OnGetItemText} |
-%% {onGetItemAttr, OnGetItemAttr} |
-%% {onGetItemColumnImage, OnGetItemColumnImage}
+%% @doc Creates a listctrl with optional callback functions:
%%
-%% OnGetItemText = (This, Item, Column) -> wxString()
-%% OnGetItemAttr = (This, Item) -> wxListItemAttr()
+%% OnGetItemText = (This, Item, Column) -> unicode:charlist()
+%% OnGetItemAttr = (This, Item) -> wxListItemAttr:wxListItemAttr()
%% OnGetItemColumnImage = (This, Item, Column) -> integer()
-%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>.
+%%
+%% See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>.
+-spec new(Parent, [Option]) -> wxListCtrl() when
+ Parent::wxWindow:wxWindow(),
+ Option::{winid, integer()} |
+ {pos, {X::integer(),Y::integer()}} |
+ {size, {W::integer(),H::integer()}} |
+ {style, integer()} |
+ {validator, wx:wx_object()} |
+ {onGetItemText, function()} |
+ {onGetItemAttr, function()} |
+ {onGetItemColumnImage, function()}.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options)->
@@ -185,26 +188,27 @@ clearAll(#wx_ref{type=ThisT,ref=ThisRef}) ->
<<ThisRef:32/?UI>>).
-%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow()) -> bool()
%% @equiv create(This,Parent, [])
+-spec create(This, Parent) -> wxListCtrl() when
+ This::wxWindow:wxWindow(),
+ Parent::wxWindow:wxWindow().
create(This,Parent)
when is_record(This, wx_ref),is_record(Parent, wx_ref) ->
create(This,Parent, []).
-%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {winid, integer()} |
-%% {pos, {X::integer(),Y::integer()}} |
-%% {size, {W::integer(),H::integer()}} |
-%% {style, integer()} |
-%% {validator, wx:wx()} |
-%% {onGetItemText, OnGetItemText} |
-%% {onGetItemAttr, OnGetItemAttr} |
-%% {onGetItemColumnImage, OnGetItemColumnImage}
-%%
-%% OnGetItemText = (This, Item, Column) -> wxString()
-%% OnGetItemAttr = (This, Item) -> wxListItemAttr()
-%% OnGetItemColumnImage = (This, Item, Column) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlcreate">external documentation</a>.
+-spec create(This, Parent, [Option]) -> wxListCtrl() when
+ This::wxWindow:wxWindow(),
+ Parent::wxWindow:wxWindow(),
+ Option::{winid, integer()} |
+ {pos, {X::integer(),Y::integer()}} |
+ {size, {W::integer(),H::integer()}} |
+ {style, integer()} |
+ {validator, wx:wx_object()} |
+ {onGetItemText, function()} |
+ {onGetItemAttr, function()} |
+ {onGetItemColumnImage, function()}.
+
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
?CLASS(ThisT,wxListCtrl),
@@ -268,7 +272,7 @@ ensureVisible(#wx_ref{type=ThisT,ref=ThisRef},Item)
This::wxListCtrl(), Start::integer(), Str::unicode:chardata().
findItem(This,Start,Str)
- when is_record(This, wx_ref),is_integer(Start),is_list(Str) ->
+ when is_record(This, wx_ref),is_integer(Start),?is_chardata(Str) ->
findItem(This,Start,Str, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlistctrl.html#wxlistctrlfinditem">external documentation</a>.
@@ -282,7 +286,7 @@ findItem(This,Start,Str)
(This, Start, Pt, Direction) -> integer() when
This::wxListCtrl(), Start::integer(), Pt::{X::integer(), Y::integer()}, Direction::integer().
findItem(#wx_ref{type=ThisT,ref=ThisRef},Start,Str, Options)
- when is_integer(Start),is_list(Str),is_list(Options) ->
+ when is_integer(Start),?is_chardata(Str),is_list(Options) ->
?CLASS(ThisT,wxListCtrl),
Str_UC = unicode:characters_to_binary([Str,0]),
MOpts = fun({partial, Partial}, Acc) -> [<<1:32/?UI,(wxe_util:from_bool(Partial)):32/?UI>>|Acc];
@@ -536,7 +540,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY})
This::wxListCtrl(), Col::integer(), Info::wxListItem:wxListItem().
insertColumn(This,Col,Heading)
- when is_record(This, wx_ref),is_integer(Col),is_list(Heading) ->
+ when is_record(This, wx_ref),is_integer(Col),?is_chardata(Heading) ->
insertColumn(This,Col,Heading, []);
insertColumn(#wx_ref{type=ThisT,ref=ThisRef},Col,#wx_ref{type=InfoT,ref=InfoRef})
when is_integer(Col) ->
@@ -551,7 +555,7 @@ insertColumn(#wx_ref{type=ThisT,ref=ThisRef},Col,#wx_ref{type=InfoT,ref=InfoRef}
Option :: {'format', integer()}
| {'width', integer()}.
insertColumn(#wx_ref{type=ThisT,ref=ThisRef},Col,Heading, Options)
- when is_integer(Col),is_list(Heading),is_list(Options) ->
+ when is_integer(Col),?is_chardata(Heading),is_list(Options) ->
?CLASS(ThisT,wxListCtrl),
Heading_UC = unicode:characters_to_binary([Heading,0]),
MOpts = fun({format, Format}, Acc) -> [<<1:32/?UI,Format:32/?UI>>|Acc];
@@ -585,7 +589,7 @@ insertItem(#wx_ref{type=ThisT,ref=ThisRef},Index,ImageIndex)
wxe_util:call(?wxListCtrl_InsertItem_2_0,
<<ThisRef:32/?UI,Index:32/?UI,ImageIndex:32/?UI>>);
insertItem(#wx_ref{type=ThisT,ref=ThisRef},Index,Label)
- when is_integer(Index),is_list(Label) ->
+ when is_integer(Index),?is_chardata(Label) ->
?CLASS(ThisT,wxListCtrl),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:call(?wxListCtrl_InsertItem_2_1,
@@ -595,7 +599,7 @@ insertItem(#wx_ref{type=ThisT,ref=ThisRef},Index,Label)
-spec insertItem(This, Index, Label, ImageIndex) -> integer() when
This::wxListCtrl(), Index::integer(), Label::unicode:chardata(), ImageIndex::integer().
insertItem(#wx_ref{type=ThisT,ref=ThisRef},Index,Label,ImageIndex)
- when is_integer(Index),is_list(Label),is_integer(ImageIndex) ->
+ when is_integer(Index),?is_chardata(Label),is_integer(ImageIndex) ->
?CLASS(ThisT,wxListCtrl),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:call(?wxListCtrl_InsertItem_3,
@@ -680,7 +684,7 @@ setItem(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=InfoT,ref=InfoRef}) ->
This::wxListCtrl(), Index::integer(), Col::integer(), Label::unicode:chardata().
setItem(This,Index,Col,Label)
- when is_record(This, wx_ref),is_integer(Index),is_integer(Col),is_list(Label) ->
+ when is_record(This, wx_ref),is_integer(Index),is_integer(Col),?is_chardata(Label) ->
setItem(This,Index,Col,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlistctrl.html#wxlistctrlsetitem">external documentation</a>.
@@ -688,7 +692,7 @@ setItem(This,Index,Col,Label)
This::wxListCtrl(), Index::integer(), Col::integer(), Label::unicode:chardata(),
Option :: {'imageId', integer()}.
setItem(#wx_ref{type=ThisT,ref=ThisRef},Index,Col,Label, Options)
- when is_integer(Index),is_integer(Col),is_list(Label),is_list(Options) ->
+ when is_integer(Index),is_integer(Col),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxListCtrl),
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({imageId, ImageId}, Acc) -> [<<1:32/?UI,ImageId:32/?UI>>|Acc];
@@ -786,7 +790,7 @@ setItemState(#wx_ref{type=ThisT,ref=ThisRef},Item,State,StateMask)
-spec setItemText(This, Item, Str) -> 'ok' when
This::wxListCtrl(), Item::integer(), Str::unicode:chardata().
setItemText(#wx_ref{type=ThisT,ref=ThisRef},Item,Str)
- when is_integer(Item),is_list(Str) ->
+ when is_integer(Item),?is_chardata(Str) ->
?CLASS(ThisT,wxListCtrl),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxListCtrl_SetItemText,
@@ -871,6 +875,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -1183,6 +1189,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxListItem.erl b/lib/wx/src/gen/wxListItem.erl
index 1530a8c514..56a1719c55 100644
--- a/lib/wx/src/gen/wxListItem.erl
+++ b/lib/wx/src/gen/wxListItem.erl
@@ -236,7 +236,7 @@ setStateMask(#wx_ref{type=ThisT,ref=ThisRef},StateMask)
-spec setText(This, Text) -> 'ok' when
This::wxListItem(), Text::unicode:chardata().
setText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxListItem),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxListItem_SetText,
diff --git a/lib/wx/src/gen/wxListView.erl b/lib/wx/src/gen/wxListView.erl
index 908bf4c1c9..adba629d5a 100644
--- a/lib/wx/src/gen/wxListView.erl
+++ b/lib/wx/src/gen/wxListView.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -169,6 +169,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -485,6 +487,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxListbook.erl b/lib/wx/src/gen/wxListbook.erl
index a7050e1db9..e2ea559587 100644
--- a/lib/wx/src/gen/wxListbook.erl
+++ b/lib/wx/src/gen/wxListbook.erl
@@ -43,29 +43,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -120,7 +120,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
This::wxListbook(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
addPage(This,Page,Text)
- when is_record(This, wx_ref),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_record(Page, wx_ref),?is_chardata(Text) ->
addPage(This,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlistbook.html#wxlistbookaddpage">external documentation</a>.
@@ -129,7 +129,7 @@ addPage(This,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
addPage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxListbook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -296,7 +296,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
This::wxListbook(), N::integer(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
insertPage(This,N,Page,Text)
- when is_record(This, wx_ref),is_integer(N),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(N),is_record(Page, wx_ref),?is_chardata(Text) ->
insertPage(This,N,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlistbook.html#wxlistbookinsertpage">external documentation</a>.
@@ -305,7 +305,7 @@ insertPage(This,N,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
insertPage(#wx_ref{type=ThisT,ref=ThisRef},N,#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_integer(N),is_list(Text),is_list(Options) ->
+ when is_integer(N),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxListbook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -347,7 +347,7 @@ setPageImage(#wx_ref{type=ThisT,ref=ThisRef},N,ImageId)
-spec setPageText(This, N, StrText) -> boolean() when
This::wxListbook(), N::integer(), StrText::unicode:chardata().
setPageText(#wx_ref{type=ThisT,ref=ThisRef},N,StrText)
- when is_integer(N),is_list(StrText) ->
+ when is_integer(N),?is_chardata(StrText) ->
?CLASS(ThisT,wxListbook),
StrText_UC = unicode:characters_to_binary([StrText,0]),
wxe_util:call(?wxListbook_SetPageText,
@@ -384,6 +384,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -700,6 +702,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxLocale.erl b/lib/wx/src/gen/wxLocale.erl
index d473731bf8..1ce7c3e3e8 100644
--- a/lib/wx/src/gen/wxLocale.erl
+++ b/lib/wx/src/gen/wxLocale.erl
@@ -92,7 +92,7 @@ init(#wx_ref{type=ThisT,ref=ThisRef}, Options)
-spec addCatalog(This, SzDomain) -> boolean() when
This::wxLocale(), SzDomain::unicode:chardata().
addCatalog(#wx_ref{type=ThisT,ref=ThisRef},SzDomain)
- when is_list(SzDomain) ->
+ when ?is_chardata(SzDomain) ->
?CLASS(ThisT,wxLocale),
SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),
wxe_util:call(?wxLocale_AddCatalog_1,
@@ -103,7 +103,7 @@ addCatalog(#wx_ref{type=ThisT,ref=ThisRef},SzDomain)
-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) ->
+ when ?is_chardata(SzDomain),is_integer(MsgIdLanguage),?is_chardata(MsgIdCharset) ->
?CLASS(ThisT,wxLocale),
SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),
MsgIdCharset_UC = unicode:characters_to_binary([MsgIdCharset,0]),
@@ -114,7 +114,7 @@ addCatalog(#wx_ref{type=ThisT,ref=ThisRef},SzDomain,MsgIdLanguage,MsgIdCharset)
-spec addCatalogLookupPathPrefix(Prefix) -> 'ok' when
Prefix::unicode:chardata().
addCatalogLookupPathPrefix(Prefix)
- when is_list(Prefix) ->
+ when ?is_chardata(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>>).
@@ -164,7 +164,7 @@ getName(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxLocale(), SzOrigString::unicode:chardata().
getString(This,SzOrigString)
- when is_record(This, wx_ref),is_list(SzOrigString) ->
+ when is_record(This, wx_ref),?is_chardata(SzOrigString) ->
getString(This,SzOrigString, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetstring">external documentation</a>.
@@ -172,7 +172,7 @@ getString(This,SzOrigString)
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) ->
+ when ?is_chardata(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];
@@ -186,7 +186,7 @@ getString(#wx_ref{type=ThisT,ref=ThisRef},SzOrigString, Options)
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) ->
+ when is_record(This, wx_ref),?is_chardata(SzOrigString),?is_chardata(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>.
@@ -194,7 +194,7 @@ getString(This,SzOrigString,SzOrigString2,N)
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) ->
+ when ?is_chardata(SzOrigString),?is_chardata(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]),
@@ -209,7 +209,7 @@ getString(#wx_ref{type=ThisT,ref=ThisRef},SzOrigString,SzOrigString2,N, Options)
This::wxLocale(), SzHeader::unicode:chardata().
getHeaderValue(This,SzHeader)
- when is_record(This, wx_ref),is_list(SzHeader) ->
+ when is_record(This, wx_ref),?is_chardata(SzHeader) ->
getHeaderValue(This,SzHeader, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetheadervalue">external documentation</a>.
@@ -217,7 +217,7 @@ getHeaderValue(This,SzHeader)
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) ->
+ when ?is_chardata(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];
@@ -257,7 +257,7 @@ getSystemLanguage() ->
-spec isLoaded(This, SzDomain) -> boolean() when
This::wxLocale(), SzDomain::unicode:chardata().
isLoaded(#wx_ref{type=ThisT,ref=ThisRef},SzDomain)
- when is_list(SzDomain) ->
+ when ?is_chardata(SzDomain) ->
?CLASS(ThisT,wxLocale),
SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),
wxe_util:call(?wxLocale_IsLoaded,
diff --git a/lib/wx/src/gen/wxMDIChildFrame.erl b/lib/wx/src/gen/wxMDIChildFrame.erl
index b294e4898d..0d388c016a 100644
--- a/lib/wx/src/gen/wxMDIChildFrame.erl
+++ b/lib/wx/src/gen/wxMDIChildFrame.erl
@@ -42,45 +42,45 @@
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientAreaOrigin/1,
- getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
- getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getStatusBar/1,
- getStatusBarPane/1,getTextExtent/2,getTextExtent/3,getTitle/1,getToolBar/1,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
- setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2,
- setStatusBarPane/2,setStatusText/2,setStatusText/3,setStatusWidths/2,
- setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,setTransparent/2,
- setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,
- setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,
- shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3,
- thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
- updateWindowUI/2,validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientAreaOrigin/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getStatusBar/1,getStatusBarPane/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolBar/1,getToolTip/1,getUpdateRegion/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
+ inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
+ isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,raise/1,refresh/1,
+ refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
+ reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,
+ setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,
+ setIcons/2,setId/2,setLabel/2,setMaxSize/2,setMenuBar/2,setMinSize/2,
+ setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
+ setShape/2,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setStatusBar/2,setStatusBarPane/2,setStatusText/2,setStatusText/3,
+ setStatusWidths/2,setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,
+ setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
+ setWindowVariant/2,shouldInheritColours/1,show/1,show/2,showFullScreen/2,
+ showFullScreen/3,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
+ update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
-export_type([wxMDIChildFrame/0]).
%% @hidden
@@ -102,7 +102,7 @@ new() ->
Parent::wxMDIParentFrame:wxMDIParentFrame(), Id::integer(), Title::unicode:chardata().
new(Parent,Id,Title)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
new(Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmdichildframe.html#wxmdichildframewxmdichildframe">external documentation</a>.
@@ -112,7 +112,7 @@ new(Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ParentT,wxMDIParentFrame),
Title_UC = unicode:characters_to_binary([Title,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -136,7 +136,7 @@ activate(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxMDIChildFrame(), Parent::wxMDIParentFrame:wxMDIParentFrame(), Id::integer(), Title::unicode:chardata().
create(This,Parent,Id,Title)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
create(This,Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmdichildframe.html#wxmdichildframecreate">external documentation</a>.
@@ -146,7 +146,7 @@ create(This,Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ThisT,wxMDIChildFrame),
?CLASS(ParentT,wxMDIParentFrame),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -275,6 +275,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -595,6 +597,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxMDIClientWindow.erl b/lib/wx/src/gen/wxMDIClientWindow.erl
index ddc31760f4..4fc080c64d 100644
--- a/lib/wx/src/gen/wxMDIClientWindow.erl
+++ b/lib/wx/src/gen/wxMDIClientWindow.erl
@@ -37,29 +37,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -136,6 +136,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -456,6 +458,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxMDIParentFrame.erl b/lib/wx/src/gen/wxMDIParentFrame.erl
index 63b4ec8e23..59f24a1b40 100644
--- a/lib/wx/src/gen/wxMDIParentFrame.erl
+++ b/lib/wx/src/gen/wxMDIParentFrame.erl
@@ -43,27 +43,28 @@
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientAreaOrigin/1,
- getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
- getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getStatusBar/1,
- getStatusBarPane/1,getTextExtent/2,getTextExtent/3,getTitle/1,getToolBar/1,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,
- releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientAreaOrigin/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getStatusBar/1,getStatusBarPane/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolBar/1,getToolTip/1,getUpdateRegion/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
+ inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
+ isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,
+ maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,
setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
@@ -103,7 +104,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
new(Parent,Id,Title)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
new(Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmdiparentframe.html#wxmdiparentframewxmdiparentframe">external documentation</a>.
@@ -113,7 +114,7 @@ new(Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -161,7 +162,7 @@ cascade(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxMDIParentFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
create(This,Parent,Id,Title)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
create(This,Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmdiparentframe.html#wxmdiparentframecreate">external documentation</a>.
@@ -171,7 +172,7 @@ create(This,Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ThisT,wxMDIParentFrame),
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -313,6 +314,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -633,6 +636,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxMenu.erl b/lib/wx/src/gen/wxMenu.erl
index 317ea38685..26fe23701d 100644
--- a/lib/wx/src/gen/wxMenu.erl
+++ b/lib/wx/src/gen/wxMenu.erl
@@ -69,7 +69,7 @@ new(Options)
Title::unicode:chardata(),
Option :: {'style', integer()}.
new(Title, Options)
- when is_list(Title),is_list(Options) ->
+ when ?is_chardata(Title),is_list(Options) ->
Title_UC = unicode:characters_to_binary([Title,0]),
MOpts = fun({style, Style}, Acc) -> [<<1:32/?UI,Style:32/?UI>>|Acc];
(BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
@@ -91,7 +91,7 @@ append(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) ->
This::wxMenu(), Itemid::integer(), Text::unicode:chardata().
append(This,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text) ->
append(This,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuappend">external documentation</a>.
@@ -110,10 +110,10 @@ append(This,Itemid,Text)
| {'kind', wx:wx_enum()}.
append(This,Itemid,Text,Submenu)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text),is_record(Submenu, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text),is_record(Submenu, wx_ref) ->
append(This,Itemid,Text,Submenu, []);
append(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -135,14 +135,14 @@ append(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(), Submenu::wxMenu(),
Option :: {'help', unicode:chardata()}.
append(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text,Help,IsCheckable)
- when is_integer(Itemid),is_list(Text),is_list(Help),is_boolean(IsCheckable) ->
+ when is_integer(Itemid),?is_chardata(Text),?is_chardata(Help),is_boolean(IsCheckable) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
Help_UC = unicode:characters_to_binary([Help,0]),
wxe_util:cast(?wxMenu_Append_4_0,
<<ThisRef:32/?UI,Itemid:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((4+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((4+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8,(wxe_util:from_bool(IsCheckable)):32/?UI>>);
append(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text,#wx_ref{type=SubmenuT,ref=SubmenuRef}, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
?CLASS(SubmenuT,wxMenu),
@@ -157,7 +157,7 @@ append(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text,#wx_ref{type=SubmenuT,ref=Sub
This::wxMenu(), Itemid::integer(), Text::unicode:chardata().
appendCheckItem(This,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text) ->
appendCheckItem(This,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuappendcheckitem">external documentation</a>.
@@ -165,7 +165,7 @@ appendCheckItem(This,Itemid,Text)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(),
Option :: {'help', unicode:chardata()}.
appendCheckItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -179,7 +179,7 @@ appendCheckItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata().
appendRadioItem(This,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text) ->
appendRadioItem(This,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuappendradioitem">external documentation</a>.
@@ -187,7 +187,7 @@ appendRadioItem(This,Itemid,Text)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(),
Option :: {'help', unicode:chardata()}.
appendRadioItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -285,7 +285,7 @@ findItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid)
wxe_util:call(?wxMenu_FindItem_2,
<<ThisRef:32/?UI,Itemid:32/?UI>>);
findItem(#wx_ref{type=ThisT,ref=ThisRef},Item)
- when is_list(Item) ->
+ when ?is_chardata(Item) ->
?CLASS(ThisT,wxMenu),
Item_UC = unicode:characters_to_binary([Item,0]),
wxe_util:call(?wxMenu_FindItem_1,
@@ -386,7 +386,7 @@ insert(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid, Options)
This::wxMenu(), Pos::integer(), Itemid::integer(), Text::unicode:chardata(), Submenu::wxMenu().
insert(This,Pos,Itemid,Text,Submenu)
- when is_record(This, wx_ref),is_integer(Pos),is_integer(Itemid),is_list(Text),is_record(Submenu, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Pos),is_integer(Itemid),?is_chardata(Text),is_record(Submenu, wx_ref) ->
insert(This,Pos,Itemid,Text,Submenu, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuinsert">external documentation</a>.
@@ -401,14 +401,14 @@ insert(This,Pos,Itemid,Text,Submenu)
This::wxMenu(), Pos::integer(), Itemid::integer(), Text::unicode:chardata(), Submenu::wxMenu(),
Option :: {'help', unicode:chardata()}.
insert(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid,Text,Help,IsCheckable)
- when is_integer(Pos),is_integer(Itemid),is_list(Text),is_list(Help),is_boolean(IsCheckable) ->
+ when is_integer(Pos),is_integer(Itemid),?is_chardata(Text),?is_chardata(Help),is_boolean(IsCheckable) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
Help_UC = unicode:characters_to_binary([Help,0]),
wxe_util:cast(?wxMenu_Insert_5_0,
<<ThisRef:32/?UI,Pos:32/?UI,Itemid:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((4+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8,(wxe_util:from_bool(IsCheckable)):32/?UI>>);
insert(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid,Text,#wx_ref{type=SubmenuT,ref=SubmenuRef}, Options)
- when is_integer(Pos),is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Pos),is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
?CLASS(SubmenuT,wxMenu),
@@ -423,7 +423,7 @@ insert(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid,Text,#wx_ref{type=SubmenuT,ref
This::wxMenu(), Pos::integer(), Itemid::integer(), Text::unicode:chardata().
insertCheckItem(This,Pos,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Pos),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Pos),is_integer(Itemid),?is_chardata(Text) ->
insertCheckItem(This,Pos,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuinsertcheckitem">external documentation</a>.
@@ -431,7 +431,7 @@ insertCheckItem(This,Pos,Itemid,Text)
This::wxMenu(), Pos::integer(), Itemid::integer(), Text::unicode:chardata(),
Option :: {'help', unicode:chardata()}.
insertCheckItem(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid,Text, Options)
- when is_integer(Pos),is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Pos),is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -445,7 +445,7 @@ insertCheckItem(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid,Text, Options)
This::wxMenu(), Pos::integer(), Itemid::integer(), Text::unicode:chardata().
insertRadioItem(This,Pos,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Pos),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Pos),is_integer(Itemid),?is_chardata(Text) ->
insertRadioItem(This,Pos,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuinsertradioitem">external documentation</a>.
@@ -453,7 +453,7 @@ insertRadioItem(This,Pos,Itemid,Text)
This::wxMenu(), Pos::integer(), Itemid::integer(), Text::unicode:chardata(),
Option :: {'help', unicode:chardata()}.
insertRadioItem(#wx_ref{type=ThisT,ref=ThisRef},Pos,Itemid,Text, Options)
- when is_integer(Pos),is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Pos),is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -532,7 +532,7 @@ prepend(#wx_ref{type=ThisT,ref=ThisRef},Itemid, Options)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(), Submenu::wxMenu().
prepend(This,Itemid,Text,Submenu)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text),is_record(Submenu, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text),is_record(Submenu, wx_ref) ->
prepend(This,Itemid,Text,Submenu, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuprepend">external documentation</a>.
@@ -547,14 +547,14 @@ prepend(This,Itemid,Text,Submenu)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(), Submenu::wxMenu(),
Option :: {'help', unicode:chardata()}.
prepend(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text,Help,IsCheckable)
- when is_integer(Itemid),is_list(Text),is_list(Help),is_boolean(IsCheckable) ->
+ when is_integer(Itemid),?is_chardata(Text),?is_chardata(Help),is_boolean(IsCheckable) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
Help_UC = unicode:characters_to_binary([Help,0]),
wxe_util:cast(?wxMenu_Prepend_4_0,
<<ThisRef:32/?UI,Itemid:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((4+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((4+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8,(wxe_util:from_bool(IsCheckable)):32/?UI>>);
prepend(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text,#wx_ref{type=SubmenuT,ref=SubmenuRef}, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
?CLASS(SubmenuT,wxMenu),
@@ -569,7 +569,7 @@ prepend(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text,#wx_ref{type=SubmenuT,ref=Su
This::wxMenu(), Itemid::integer(), Text::unicode:chardata().
prependCheckItem(This,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text) ->
prependCheckItem(This,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuprependcheckitem">external documentation</a>.
@@ -577,7 +577,7 @@ prependCheckItem(This,Itemid,Text)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(),
Option :: {'help', unicode:chardata()}.
prependCheckItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -591,7 +591,7 @@ prependCheckItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata().
prependRadioItem(This,Itemid,Text)
- when is_record(This, wx_ref),is_integer(Itemid),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Itemid),?is_chardata(Text) ->
prependRadioItem(This,Itemid,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmenu.html#wxmenuprependradioitem">external documentation</a>.
@@ -599,7 +599,7 @@ prependRadioItem(This,Itemid,Text)
This::wxMenu(), Itemid::integer(), Text::unicode:chardata(),
Option :: {'help', unicode:chardata()}.
prependRadioItem(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Text, Options)
- when is_integer(Itemid),is_list(Text),is_list(Options) ->
+ when is_integer(Itemid),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxMenu),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({help, Help}, Acc) -> Help_UC = unicode:characters_to_binary([Help,0]),[<<1:32/?UI,(byte_size(Help_UC)):32/?UI,(Help_UC)/binary, 0:(((8- ((0+byte_size(Help_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -640,7 +640,7 @@ remove(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) ->
-spec setHelpString(This, Itemid, HelpString) -> 'ok' when
This::wxMenu(), Itemid::integer(), HelpString::unicode:chardata().
setHelpString(#wx_ref{type=ThisT,ref=ThisRef},Itemid,HelpString)
- when is_integer(Itemid),is_list(HelpString) ->
+ when is_integer(Itemid),?is_chardata(HelpString) ->
?CLASS(ThisT,wxMenu),
HelpString_UC = unicode:characters_to_binary([HelpString,0]),
wxe_util:cast(?wxMenu_SetHelpString,
@@ -650,7 +650,7 @@ setHelpString(#wx_ref{type=ThisT,ref=ThisRef},Itemid,HelpString)
-spec setLabel(This, Itemid, Label) -> 'ok' when
This::wxMenu(), Itemid::integer(), Label::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Label)
- when is_integer(Itemid),is_list(Label) ->
+ when is_integer(Itemid),?is_chardata(Label) ->
?CLASS(ThisT,wxMenu),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxMenu_SetLabel,
@@ -660,7 +660,7 @@ setLabel(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Label)
-spec setTitle(This, Title) -> 'ok' when
This::wxMenu(), Title::unicode:chardata().
setTitle(#wx_ref{type=ThisT,ref=ThisRef},Title)
- when is_list(Title) ->
+ when ?is_chardata(Title) ->
?CLASS(ThisT,wxMenu),
Title_UC = unicode:characters_to_binary([Title,0]),
wxe_util:cast(?wxMenu_SetTitle,
diff --git a/lib/wx/src/gen/wxMenuBar.erl b/lib/wx/src/gen/wxMenuBar.erl
index 05f7a423d5..fa613c9f3b 100644
--- a/lib/wx/src/gen/wxMenuBar.erl
+++ b/lib/wx/src/gen/wxMenuBar.erl
@@ -41,26 +41,27 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
- getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,
- getChildren/1,getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getMaxSize/1,getMinSize/1,
- getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
- getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
- hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
- initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isExposed/2,
- isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1,
- lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,
- moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
- pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
- popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
- refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
- screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
- setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
- setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ dragAcceptFiles/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
+ getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
+ getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
+ getContentScaleFactor/1,getCursor/1,getDropTarget/1,getEventHandler/1,
+ getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
+ getHandle/1,getHelpText/1,getId/1,getMaxSize/1,getMinSize/1,getName/1,
+ getParent/1,getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,
+ getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
+ getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1,
+ invalidateBestSize/1,isDoubleBuffered/1,isExposed/2,isExposed/3,isExposed/5,
+ isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,
+ makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
+ setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
@@ -98,7 +99,7 @@ new(Style)
-spec append(This, Menu, Title) -> boolean() when
This::wxMenuBar(), Menu::wxMenu:wxMenu(), Title::unicode:chardata().
append(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=MenuT,ref=MenuRef},Title)
- when is_list(Title) ->
+ when ?is_chardata(Title) ->
?CLASS(ThisT,wxMenuBar),
?CLASS(MenuT,wxMenu),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -157,7 +158,7 @@ enableTop(#wx_ref{type=ThisT,ref=ThisRef},Pos,Flag)
-spec findMenu(This, Title) -> integer() when
This::wxMenuBar(), Title::unicode:chardata().
findMenu(#wx_ref{type=ThisT,ref=ThisRef},Title)
- when is_list(Title) ->
+ when ?is_chardata(Title) ->
?CLASS(ThisT,wxMenuBar),
Title_UC = unicode:characters_to_binary([Title,0]),
wxe_util:call(?wxMenuBar_FindMenu,
@@ -167,7 +168,7 @@ findMenu(#wx_ref{type=ThisT,ref=ThisRef},Title)
-spec findMenuItem(This, MenuString, ItemString) -> integer() when
This::wxMenuBar(), MenuString::unicode:chardata(), ItemString::unicode:chardata().
findMenuItem(#wx_ref{type=ThisT,ref=ThisRef},MenuString,ItemString)
- when is_list(MenuString),is_list(ItemString) ->
+ when ?is_chardata(MenuString),?is_chardata(ItemString) ->
?CLASS(ThisT,wxMenuBar),
MenuString_UC = unicode:characters_to_binary([MenuString,0]),
ItemString_UC = unicode:characters_to_binary([ItemString,0]),
@@ -239,7 +240,7 @@ getMenuCount(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec insert(This, Pos, Menu, Title) -> boolean() when
This::wxMenuBar(), Pos::integer(), Menu::wxMenu:wxMenu(), Title::unicode:chardata().
insert(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=MenuT,ref=MenuRef},Title)
- when is_integer(Pos),is_list(Title) ->
+ when is_integer(Pos),?is_chardata(Title) ->
?CLASS(ThisT,wxMenuBar),
?CLASS(MenuT,wxMenu),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -285,7 +286,7 @@ remove(#wx_ref{type=ThisT,ref=ThisRef},Pos)
-spec replace(This, Pos, Menu, Title) -> wxMenu:wxMenu() when
This::wxMenuBar(), Pos::integer(), Menu::wxMenu:wxMenu(), Title::unicode:chardata().
replace(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=MenuT,ref=MenuRef},Title)
- when is_integer(Pos),is_list(Title) ->
+ when is_integer(Pos),?is_chardata(Title) ->
?CLASS(ThisT,wxMenuBar),
?CLASS(MenuT,wxMenu),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -296,7 +297,7 @@ replace(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=MenuT,ref=MenuRef},Titl
-spec setHelpString(This, Itemid, HelpString) -> 'ok' when
This::wxMenuBar(), Itemid::integer(), HelpString::unicode:chardata().
setHelpString(#wx_ref{type=ThisT,ref=ThisRef},Itemid,HelpString)
- when is_integer(Itemid),is_list(HelpString) ->
+ when is_integer(Itemid),?is_chardata(HelpString) ->
?CLASS(ThisT,wxMenuBar),
HelpString_UC = unicode:characters_to_binary([HelpString,0]),
wxe_util:cast(?wxMenuBar_SetHelpString,
@@ -306,7 +307,7 @@ setHelpString(#wx_ref{type=ThisT,ref=ThisRef},Itemid,HelpString)
-spec setLabel(This, S) -> 'ok' when
This::wxMenuBar(), S::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},S)
- when is_list(S) ->
+ when ?is_chardata(S) ->
?CLASS(ThisT,wxMenuBar),
S_UC = unicode:characters_to_binary([S,0]),
wxe_util:cast(?wxMenuBar_SetLabel_1,
@@ -316,7 +317,7 @@ setLabel(#wx_ref{type=ThisT,ref=ThisRef},S)
-spec setLabel(This, Itemid, Label) -> 'ok' when
This::wxMenuBar(), Itemid::integer(), Label::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Label)
- when is_integer(Itemid),is_list(Label) ->
+ when is_integer(Itemid),?is_chardata(Label) ->
?CLASS(ThisT,wxMenuBar),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxMenuBar_SetLabel_2,
@@ -326,7 +327,7 @@ setLabel(#wx_ref{type=ThisT,ref=ThisRef},Itemid,Label)
-spec setLabelTop(This, Pos, Label) -> 'ok' when
This::wxMenuBar(), Pos::integer(), Label::unicode:chardata().
setLabelTop(#wx_ref{type=ThisT,ref=ThisRef},Pos,Label)
- when is_integer(Pos),is_list(Label) ->
+ when is_integer(Pos),?is_chardata(Label) ->
?CLASS(ThisT,wxMenuBar),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxMenuBar_SetLabelTop,
@@ -340,6 +341,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -650,6 +653,8 @@ fit(This) -> wxWindow:fit(This).
%% @hidden
findWindow(This,Winid) -> wxWindow:findWindow(This,Winid).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxMenuItem.erl b/lib/wx/src/gen/wxMenuItem.erl
index 324910d15d..2e0a1c756a 100644
--- a/lib/wx/src/gen/wxMenuItem.erl
+++ b/lib/wx/src/gen/wxMenuItem.erl
@@ -153,7 +153,7 @@ getLabel(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec getLabelFromText(Text) -> unicode:charlist() when
Text::unicode:chardata().
getLabelFromText(Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxMenuItem_GetLabelFromText,
<<(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((4+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -235,7 +235,7 @@ setBitmap(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BitmapT,ref=BitmapRef}) -
-spec setHelp(This, Str) -> 'ok' when
This::wxMenuItem(), Str::unicode:chardata().
setHelp(#wx_ref{type=ThisT,ref=ThisRef},Str)
- when is_list(Str) ->
+ when ?is_chardata(Str) ->
?CLASS(ThisT,wxMenuItem),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxMenuItem_SetHelp,
@@ -263,7 +263,7 @@ setSubMenu(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=MenuT,ref=MenuRef}) ->
-spec setText(This, Str) -> 'ok' when
This::wxMenuItem(), Str::unicode:chardata().
setText(#wx_ref{type=ThisT,ref=ThisRef},Str)
- when is_list(Str) ->
+ when ?is_chardata(Str) ->
?CLASS(ThisT,wxMenuItem),
Str_UC = unicode:characters_to_binary([Str,0]),
wxe_util:cast(?wxMenuItem_SetText,
diff --git a/lib/wx/src/gen/wxMessageDialog.erl b/lib/wx/src/gen/wxMessageDialog.erl
index 30e47529cc..a63f66741b 100644
--- a/lib/wx/src/gen/wxMessageDialog.erl
+++ b/lib/wx/src/gen/wxMessageDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -93,7 +93,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
Parent::wxWindow:wxWindow(), Message::unicode:chardata().
new(Parent,Message)
- when is_record(Parent, wx_ref),is_list(Message) ->
+ when is_record(Parent, wx_ref),?is_chardata(Message) ->
new(Parent,Message, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmessagedialog.html#wxmessagedialogwxmessagedialog">external documentation</a>.
@@ -103,7 +103,7 @@ new(Parent,Message)
| {'style', integer()}
| {'pos', {X::integer(), Y::integer()}}.
new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options)
- when is_list(Message),is_list(Options) ->
+ when ?is_chardata(Message),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Message_UC = unicode:characters_to_binary([Message,0]),
MOpts = fun({caption, Caption}, Acc) -> Caption_UC = unicode:characters_to_binary([Caption,0]),[<<1:32/?UI,(byte_size(Caption_UC)):32/?UI,(Caption_UC)/binary, 0:(((8- ((0+byte_size(Caption_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -192,6 +192,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -508,6 +510,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxMiniFrame.erl b/lib/wx/src/gen/wxMiniFrame.erl
index 4ae9764819..37dc2f2e04 100644
--- a/lib/wx/src/gen/wxMiniFrame.erl
+++ b/lib/wx/src/gen/wxMiniFrame.erl
@@ -41,27 +41,28 @@
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientAreaOrigin/1,
- getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
- getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getStatusBar/1,
- getStatusBarPane/1,getTextExtent/2,getTextExtent/3,getTitle/1,getToolBar/1,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,
- releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientAreaOrigin/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getStatusBar/1,getStatusBarPane/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolBar/1,getToolTip/1,getUpdateRegion/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
+ inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
+ isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,
+ maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,
setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
@@ -101,7 +102,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
new(Parent,Id,Title)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
new(Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxminiframe.html#wxminiframewxminiframe">external documentation</a>.
@@ -111,7 +112,7 @@ new(Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -127,7 +128,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
This::wxMiniFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata().
create(This,Parent,Id,Title)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title) ->
create(This,Parent,Id,Title, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxminiframe.html#wxminiframecreate">external documentation</a>.
@@ -137,7 +138,7 @@ create(This,Parent,Id,Title)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
- when is_integer(Id),is_list(Title),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_list(Options) ->
?CLASS(ThisT,wxMiniFrame),
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -241,6 +242,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -561,6 +564,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxMultiChoiceDialog.erl b/lib/wx/src/gen/wxMultiChoiceDialog.erl
index 0436515256..eef15d561e 100644
--- a/lib/wx/src/gen/wxMultiChoiceDialog.erl
+++ b/lib/wx/src/gen/wxMultiChoiceDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -99,7 +99,7 @@ new() ->
Parent::wxWindow:wxWindow(), Message::unicode:chardata(), Caption::unicode:chardata(), Choices::[unicode:chardata()].
new(Parent,Message,Caption,Choices)
- when is_record(Parent, wx_ref),is_list(Message),is_list(Caption),is_list(Choices) ->
+ when is_record(Parent, wx_ref),?is_chardata(Message),?is_chardata(Caption),is_list(Choices) ->
new(Parent,Message,Caption,Choices, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmultichoicedialog.html#wxmultichoicedialogwxmultichoicedialog">external documentation</a>.
@@ -108,7 +108,7 @@ new(Parent,Message,Caption,Choices)
Option :: {'style', integer()}
| {'pos', {X::integer(), Y::integer()}}.
new(#wx_ref{type=ParentT,ref=ParentRef},Message,Caption,Choices, Options)
- when is_list(Message),is_list(Caption),is_list(Choices),is_list(Options) ->
+ when ?is_chardata(Message),?is_chardata(Caption),is_list(Choices),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Message_UC = unicode:characters_to_binary([Message,0]),
Caption_UC = unicode:characters_to_binary([Caption,0]),
@@ -217,6 +217,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -533,6 +535,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxNotebook.erl b/lib/wx/src/gen/wxNotebook.erl
index 24f96ac88c..d7d1b0f87f 100644
--- a/lib/wx/src/gen/wxNotebook.erl
+++ b/lib/wx/src/gen/wxNotebook.erl
@@ -43,29 +43,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -120,7 +120,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Winid, Options)
This::wxNotebook(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
addPage(This,Page,Text)
- when is_record(This, wx_ref),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_record(Page, wx_ref),?is_chardata(Text) ->
addPage(This,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxnotebook.html#wxnotebookaddpage">external documentation</a>.
@@ -129,7 +129,7 @@ addPage(This,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
addPage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxNotebook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -312,7 +312,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
This::wxNotebook(), Position::integer(), Win::wxWindow:wxWindow(), StrText::unicode:chardata().
insertPage(This,Position,Win,StrText)
- when is_record(This, wx_ref),is_integer(Position),is_record(Win, wx_ref),is_list(StrText) ->
+ when is_record(This, wx_ref),is_integer(Position),is_record(Win, wx_ref),?is_chardata(StrText) ->
insertPage(This,Position,Win,StrText, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxnotebook.html#wxnotebookinsertpage">external documentation</a>.
@@ -321,7 +321,7 @@ insertPage(This,Position,Win,StrText)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
insertPage(#wx_ref{type=ThisT,ref=ThisRef},Position,#wx_ref{type=WinT,ref=WinRef},StrText, Options)
- when is_integer(Position),is_list(StrText),is_list(Options) ->
+ when is_integer(Position),?is_chardata(StrText),is_list(Options) ->
?CLASS(ThisT,wxNotebook),
?CLASS(WinT,wxWindow),
StrText_UC = unicode:characters_to_binary([StrText,0]),
@@ -372,7 +372,7 @@ setPageImage(#wx_ref{type=ThisT,ref=ThisRef},NPage,NImage)
-spec setPageText(This, NPage, StrText) -> boolean() when
This::wxNotebook(), NPage::integer(), StrText::unicode:chardata().
setPageText(#wx_ref{type=ThisT,ref=ThisRef},NPage,StrText)
- when is_integer(NPage),is_list(StrText) ->
+ when is_integer(NPage),?is_chardata(StrText) ->
?CLASS(ThisT,wxNotebook),
StrText_UC = unicode:characters_to_binary([StrText,0]),
wxe_util:call(?wxNotebook_SetPageText,
@@ -409,6 +409,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -725,6 +727,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPanel.erl b/lib/wx/src/gen/wxPanel.erl
index 07898cf19e..fc48d569af 100644
--- a/lib/wx/src/gen/wxPanel.erl
+++ b/lib/wx/src/gen/wxPanel.erl
@@ -37,29 +37,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
+ isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,
+ lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
+ popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
+ setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -155,6 +155,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -473,6 +475,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPasswordEntryDialog.erl b/lib/wx/src/gen/wxPasswordEntryDialog.erl
index e8ee8c8f37..4667376783 100644
--- a/lib/wx/src/gen/wxPasswordEntryDialog.erl
+++ b/lib/wx/src/gen/wxPasswordEntryDialog.erl
@@ -41,34 +41,34 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getValue/1,getVirtualSize/1,
- getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
- hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
- initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
- isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
- isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
- lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
- move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
- pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
- popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
- refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
- requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
- scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
- setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
- setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
- setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getValue/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
+ inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
+ isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,
+ isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
+ maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
+ refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
+ reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,
+ setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,
+ setIcons/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -95,7 +95,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
Parent::wxWindow:wxWindow(), Message::unicode:chardata().
new(Parent,Message)
- when is_record(Parent, wx_ref),is_list(Message) ->
+ when is_record(Parent, wx_ref),?is_chardata(Message) ->
new(Parent,Message, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxpasswordentrydialog.html#wxpasswordentrydialogwxpasswordentrydialog">external documentation</a>.
@@ -106,7 +106,7 @@ new(Parent,Message)
| {'style', integer()}
| {'pos', {X::integer(), Y::integer()}}.
new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options)
- when is_list(Message),is_list(Options) ->
+ when ?is_chardata(Message),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Message_UC = unicode:characters_to_binary([Message,0]),
MOpts = fun({caption, Caption}, Acc) -> Caption_UC = unicode:characters_to_binary([Caption,0]),[<<1:32/?UI,(byte_size(Caption_UC)):32/?UI,(Caption_UC)/binary, 0:(((8- ((0+byte_size(Caption_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -201,6 +201,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -517,6 +519,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPickerBase.erl b/lib/wx/src/gen/wxPickerBase.erl
index 33931f9119..0ea3a36d33 100644
--- a/lib/wx/src/gen/wxPickerBase.erl
+++ b/lib/wx/src/gen/wxPickerBase.erl
@@ -41,29 +41,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -214,6 +214,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -530,6 +532,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPopupTransientWindow.erl b/lib/wx/src/gen/wxPopupTransientWindow.erl
index b1feef6dcb..6ec2fcae62 100644
--- a/lib/wx/src/gen/wxPopupTransientWindow.erl
+++ b/lib/wx/src/gen/wxPopupTransientWindow.erl
@@ -38,38 +38,39 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,position/3,raise/1,
- refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
- setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
- setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
- setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
- setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
- show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
- update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,position/3,raise/1,refresh/1,refresh/2,
+ refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,
+ screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
+ scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,
+ setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,
+ setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,
+ setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setId/2,
+ setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5,
+ setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2,
+ setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
+ setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
+ transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
+ validate/1,warpPointer/3]).
-export_type([wxPopupTransientWindow/0]).
%% @hidden
@@ -146,6 +147,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
position(This,PtOrigin,Size) -> wxPopupWindow:position(This,PtOrigin,Size).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -466,6 +469,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPopupWindow.erl b/lib/wx/src/gen/wxPopupWindow.erl
index 962fd9903b..ddf1033841 100644
--- a/lib/wx/src/gen/wxPopupWindow.erl
+++ b/lib/wx/src/gen/wxPopupWindow.erl
@@ -37,29 +37,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -143,6 +143,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -463,6 +465,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPreviewCanvas.erl b/lib/wx/src/gen/wxPreviewCanvas.erl
index 67357dbd65..4e869dd6f2 100644
--- a/lib/wx/src/gen/wxPreviewCanvas.erl
+++ b/lib/wx/src/gen/wxPreviewCanvas.erl
@@ -40,37 +40,37 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- doPrepareDC/2,enable/1,enable/2,enableScrolling/3,findWindow/2,fit/1,
- fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
+ doPrepareDC/2,dragAcceptFiles/2,enable/1,enable/2,enableScrolling/3,
+ findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,
- getChildren/1,getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPixelsPerUnit/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getToolTip/1,getUpdateRegion/1,getViewStart/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scroll/3,
- scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
- setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2,
- setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
- setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
- setScrollPos/4,setScrollRate/3,setScrollbar/5,setScrollbar/6,setScrollbars/5,
- setScrollbars/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,
- setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,
- setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,setToolTip/2,
- setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ getChildren/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPixelsPerUnit/1,
+ getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
+ getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getViewStart/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,raise/1,refresh/1,refresh/2,
+ refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,
+ screenToClient/1,screenToClient/2,scroll/3,scrollLines/2,scrollPages/2,
+ scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
+ setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
+ setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
+ setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ setPalette/2,setScrollPos/3,setScrollPos/4,setScrollRate/3,setScrollbar/5,
+ setScrollbar/6,setScrollbars/5,setScrollbars/6,setSize/2,setSize/3,
+ setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,
+ setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
@@ -121,6 +121,8 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This).
initDialog(This) -> wxPanel:initDialog(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -439,6 +441,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPreviewControlBar.erl b/lib/wx/src/gen/wxPreviewControlBar.erl
index 4dd224b26b..cf17f40527 100644
--- a/lib/wx/src/gen/wxPreviewControlBar.erl
+++ b/lib/wx/src/gen/wxPreviewControlBar.erl
@@ -39,38 +39,39 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
- setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
- setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
- setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
- setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
- show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
- update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5,
+ setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2,
+ setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
+ setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
+ transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
+ validate/1,warpPointer/3]).
-export_type([wxPreviewControlBar/0]).
%% @hidden
@@ -152,6 +153,8 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This).
initDialog(This) -> wxPanel:initDialog(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -470,6 +473,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPreviewFrame.erl b/lib/wx/src/gen/wxPreviewFrame.erl
index 2f530b49ea..022b0cd46e 100644
--- a/lib/wx/src/gen/wxPreviewFrame.erl
+++ b/lib/wx/src/gen/wxPreviewFrame.erl
@@ -42,27 +42,28 @@
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientAreaOrigin/1,
- getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
- getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getStatusBar/1,
- getStatusBarPane/1,getTextExtent/2,getTextExtent/3,getTitle/1,getToolBar/1,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,
- releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientAreaOrigin/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getStatusBar/1,getStatusBarPane/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolBar/1,getToolTip/1,getUpdateRegion/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
+ inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
+ isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,
+ maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,
setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
@@ -244,6 +245,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -564,6 +567,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPrintData.erl b/lib/wx/src/gen/wxPrintData.erl
index 6b6b678adf..b6815da90b 100644
--- a/lib/wx/src/gen/wxPrintData.erl
+++ b/lib/wx/src/gen/wxPrintData.erl
@@ -205,7 +205,7 @@ setPaperId(#wx_ref{type=ThisT,ref=ThisRef},SizeId)
-spec setPrinterName(This, Name) -> 'ok' when
This::wxPrintData(), Name::unicode:chardata().
setPrinterName(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxPrintData),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:cast(?wxPrintData_SetPrinterName,
diff --git a/lib/wx/src/gen/wxPrintDialog.erl b/lib/wx/src/gen/wxPrintDialog.erl
index d4188e79c4..4024036166 100644
--- a/lib/wx/src/gen/wxPrintDialog.erl
+++ b/lib/wx/src/gen/wxPrintDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -214,6 +214,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -530,6 +532,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxPrinter.erl b/lib/wx/src/gen/wxPrinter.erl
index b9fb1c07bd..bdca37b4a8 100644
--- a/lib/wx/src/gen/wxPrinter.erl
+++ b/lib/wx/src/gen/wxPrinter.erl
@@ -122,7 +122,7 @@ printDialog(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef})
-spec reportError(This, Parent, Printout, Message) -> 'ok' when
This::wxPrinter(), Parent::wxWindow:wxWindow(), Printout::wxPrintout:wxPrintout(), Message::unicode:chardata().
reportError(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=PrintoutT,ref=PrintoutRef},Message)
- when is_list(Message) ->
+ when ?is_chardata(Message) ->
?CLASS(ThisT,wxPrinter),
?CLASS(ParentT,wxWindow),
?CLASS(PrintoutT,wxPrintout),
diff --git a/lib/wx/src/gen/wxProgressDialog.erl b/lib/wx/src/gen/wxProgressDialog.erl
index 8e275f9dc8..a17cb0383a 100644
--- a/lib/wx/src/gen/wxProgressDialog.erl
+++ b/lib/wx/src/gen/wxProgressDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,updateWindowUI/1,
@@ -93,7 +93,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
Title::unicode:chardata(), Message::unicode:chardata().
new(Title,Message)
- when is_list(Title),is_list(Message) ->
+ when ?is_chardata(Title),?is_chardata(Message) ->
new(Title,Message, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxprogressdialog.html#wxprogressdialogwxprogressdialog">external documentation</a>.
@@ -103,7 +103,7 @@ new(Title,Message)
| {'parent', wxWindow:wxWindow()}
| {'style', integer()}.
new(Title,Message, Options)
- when is_list(Title),is_list(Message),is_list(Options) ->
+ when ?is_chardata(Title),?is_chardata(Message),is_list(Options) ->
Title_UC = unicode:characters_to_binary([Title,0]),
Message_UC = unicode:characters_to_binary([Message,0]),
MOpts = fun({maximum, Maximum}, Acc) -> [<<1:32/?UI,Maximum:32/?UI>>|Acc];
@@ -229,6 +229,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -543,6 +545,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxRadioBox.erl b/lib/wx/src/gen/wxRadioBox.erl
index 348d75db2a..13d3a496ac 100644
--- a/lib/wx/src/gen/wxRadioBox.erl
+++ b/lib/wx/src/gen/wxRadioBox.erl
@@ -41,12 +41,13 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1,
- getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,
- getChildren/1,getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ dragAcceptFiles/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
+ getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
+ getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
+ getContentScaleFactor/1,getCursor/1,getDropTarget/1,getEventHandler/1,
+ getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
+ getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
@@ -86,7 +87,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[unicode:chardata()].
new(Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
new(Parent,Id,Title,Pos,Size,Choices, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxradiobox.html#wxradioboxwxradiobox">external documentation</a>.
@@ -96,7 +97,7 @@ new(Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
| {'style', integer()}
| {'val', wx:wx_object()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options)
- when is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
Choices_UCA = [unicode:characters_to_binary([ChoicesTemp,0]) ||
@@ -114,7 +115,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choic
This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::unicode:chardata(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[unicode:chardata()].
create(This,Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
create(This,Parent,Id,Title,Pos,Size,Choices, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxradiobox.html#wxradioboxcreate">external documentation</a>.
@@ -124,7 +125,7 @@ create(This,Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
| {'style', integer()}
| {'val', wx:wx_object()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options)
- when is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices),is_list(Options) ->
?CLASS(ThisT,wxRadioBox),
?CLASS(ParentT,wxWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
@@ -319,7 +320,7 @@ isItemShown(#wx_ref{type=ThisT,ref=ThisRef},N)
-spec setItemHelpText(This, N, HelpText) -> 'ok' when
This::wxRadioBox(), N::integer(), HelpText::unicode:chardata().
setItemHelpText(#wx_ref{type=ThisT,ref=ThisRef},N,HelpText)
- when is_integer(N),is_list(HelpText) ->
+ when is_integer(N),?is_chardata(HelpText) ->
?CLASS(ThisT,wxRadioBox),
HelpText_UC = unicode:characters_to_binary([HelpText,0]),
wxe_util:cast(?wxRadioBox_SetItemHelpText,
@@ -329,7 +330,7 @@ setItemHelpText(#wx_ref{type=ThisT,ref=ThisRef},N,HelpText)
-spec setItemToolTip(This, Item, Text) -> 'ok' when
This::wxRadioBox(), Item::integer(), Text::unicode:chardata().
setItemToolTip(#wx_ref{type=ThisT,ref=ThisRef},Item,Text)
- when is_integer(Item),is_list(Text) ->
+ when is_integer(Item),?is_chardata(Text) ->
?CLASS(ThisT,wxRadioBox),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxRadioBox_SetItemToolTip,
@@ -348,6 +349,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -656,6 +659,8 @@ fit(This) -> wxWindow:fit(This).
%% @hidden
findWindow(This,Winid) -> wxWindow:findWindow(This,Winid).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxRadioButton.erl b/lib/wx/src/gen/wxRadioButton.erl
index 4487724be6..b5635e8afe 100644
--- a/lib/wx/src/gen/wxRadioButton.erl
+++ b/lib/wx/src/gen/wxRadioButton.erl
@@ -38,29 +38,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -90,7 +90,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
new(Parent,Id,Label)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
new(Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxradiobutton.html#wxradiobuttonwxradiobutton">external documentation</a>.
@@ -101,7 +101,7 @@ new(Parent,Id,Label)
| {'style', integer()}
| {'validator', wx:wx_object()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -118,7 +118,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
This::wxRadioButton(), Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
create(This,Parent,Id,Label)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
create(This,Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxradiobutton.html#wxradiobuttoncreate">external documentation</a>.
@@ -129,7 +129,7 @@ create(This,Parent,Id,Label)
| {'style', integer()}
| {'validator', wx:wx_object()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxRadioButton),
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
@@ -172,6 +172,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -488,6 +490,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSashLayoutWindow.erl b/lib/wx/src/gen/wxSashLayoutWindow.erl
index ae081ae800..a0e240b25d 100644
--- a/lib/wx/src/gen/wxSashLayoutWindow.erl
+++ b/lib/wx/src/gen/wxSashLayoutWindow.erl
@@ -39,30 +39,31 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMaximumSizeX/1,getMaximumSizeY/1,
- getMinSize/1,getMinimumSizeX/1,getMinimumSizeY/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getSashVisible/2,getScreenPosition/1,getScreenRect/1,
- getScrollPos/2,getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,
- getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
- getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
- hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1,
- invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,
- lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,
- scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
- setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMaximumSizeX/1,getMaximumSizeY/1,getMinSize/1,getMinimumSizeX/1,
+ getMinimumSizeY/1,getName/1,getParent/1,getPosition/1,getRect/1,getSashVisible/2,
+ getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
+ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
+ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
+ isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
+ isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
+ move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
+ refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
+ reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
+ scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
+ setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
+ setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
+ setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
+ setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMaximumSizeX/2,setMaximumSizeY/2,setMinSize/2,setMinimumSizeX/2,
setMinimumSizeY/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
setOwnForegroundColour/2,setPalette/2,setSashVisible/3,setScrollPos/3,
@@ -220,6 +221,8 @@ getMaximumSizeX(This) -> wxSashWindow:getMaximumSizeX(This).
getSashVisible(This,Edge) -> wxSashWindow:getSashVisible(This,Edge).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -540,6 +543,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSashWindow.erl b/lib/wx/src/gen/wxSashWindow.erl
index 773e0f1ab0..5e66d79b11 100644
--- a/lib/wx/src/gen/wxSashWindow.erl
+++ b/lib/wx/src/gen/wxSashWindow.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -208,6 +208,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -528,6 +530,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxScrollBar.erl b/lib/wx/src/gen/wxScrollBar.erl
index 7f70d9d97b..a1138725cd 100644
--- a/lib/wx/src/gen/wxScrollBar.erl
+++ b/lib/wx/src/gen/wxScrollBar.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setSize/2,setSize/3,setSize/5,
setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
@@ -216,6 +216,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -528,6 +530,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxScrolledWindow.erl b/lib/wx/src/gen/wxScrolledWindow.erl
index 70bc5adbd9..e3f6122cfa 100644
--- a/lib/wx/src/gen/wxScrolledWindow.erl
+++ b/lib/wx/src/gen/wxScrolledWindow.erl
@@ -41,38 +41,39 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
- setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
- setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
- setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
- setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
- setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
- setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
- setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
- show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,
- update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3,
+ setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5,
+ setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2,
+ setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2,
+ setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,
+ setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,
+ setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1,
+ transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2,
+ validate/1,warpPointer/3]).
-export_type([wxScrolledWindow/0]).
%% @hidden
@@ -259,6 +260,8 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This).
initDialog(This) -> wxPanel:initDialog(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -577,6 +580,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSingleChoiceDialog.erl b/lib/wx/src/gen/wxSingleChoiceDialog.erl
index baff296d11..8b2991da4d 100644
--- a/lib/wx/src/gen/wxSingleChoiceDialog.erl
+++ b/lib/wx/src/gen/wxSingleChoiceDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -99,7 +99,7 @@ new() ->
Parent::wxWindow:wxWindow(), Message::unicode:chardata(), Caption::unicode:chardata(), Choices::[unicode:chardata()].
new(Parent,Message,Caption,Choices)
- when is_record(Parent, wx_ref),is_list(Message),is_list(Caption),is_list(Choices) ->
+ when is_record(Parent, wx_ref),?is_chardata(Message),?is_chardata(Caption),is_list(Choices) ->
new(Parent,Message,Caption,Choices, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxsinglechoicedialog.html#wxsinglechoicedialogwxsinglechoicedialog">external documentation</a>.
@@ -108,7 +108,7 @@ new(Parent,Message,Caption,Choices)
Option :: {'style', integer()}
| {'pos', {X::integer(), Y::integer()}}.
new(#wx_ref{type=ParentT,ref=ParentRef},Message,Caption,Choices, Options)
- when is_list(Message),is_list(Caption),is_list(Choices),is_list(Options) ->
+ when ?is_chardata(Message),?is_chardata(Caption),is_list(Choices),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Message_UC = unicode:characters_to_binary([Message,0]),
Caption_UC = unicode:characters_to_binary([Caption,0]),
@@ -224,6 +224,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -540,6 +542,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSlider.erl b/lib/wx/src/gen/wxSlider.erl
index a215b3c1d5..7bdff00589 100644
--- a/lib/wx/src/gen/wxSlider.erl
+++ b/lib/wx/src/gen/wxSlider.erl
@@ -40,29 +40,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -248,6 +248,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -564,6 +566,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSpinButton.erl b/lib/wx/src/gen/wxSpinButton.erl
index 1c8d674d05..6c24176974 100644
--- a/lib/wx/src/gen/wxSpinButton.erl
+++ b/lib/wx/src/gen/wxSpinButton.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -196,6 +196,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -512,6 +514,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSpinCtrl.erl b/lib/wx/src/gen/wxSpinCtrl.erl
index f8a46dd146..c229b4caf1 100644
--- a/lib/wx/src/gen/wxSpinCtrl.erl
+++ b/lib/wx/src/gen/wxSpinCtrl.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -172,7 +172,7 @@ setValue(#wx_ref{type=ThisT,ref=ThisRef},Value)
wxe_util:cast(?wxSpinCtrl_SetValue_1_0,
<<ThisRef:32/?UI,Value:32/?UI>>);
setValue(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxSpinCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxSpinCtrl_SetValue_1_1,
@@ -233,6 +233,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -549,6 +551,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSplashScreen.erl b/lib/wx/src/gen/wxSplashScreen.erl
index 3b53e670c1..9729b3529b 100644
--- a/lib/wx/src/gen/wxSplashScreen.erl
+++ b/lib/wx/src/gen/wxSplashScreen.erl
@@ -41,27 +41,28 @@
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientAreaOrigin/1,
- getClientSize/1,getContainingSizer/1,getCursor/1,getDropTarget/1,
- getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
- getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
- getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getStatusBar/1,
- getStatusBarPane/1,getTextExtent/2,getTextExtent/3,getTitle/1,getToolBar/1,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,
- releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientAreaOrigin/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,getMenuBar/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getStatusBar/1,getStatusBarPane/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolBar/1,getToolTip/1,getUpdateRegion/1,
+ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,
+ hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2,
+ inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1,
+ isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,
+ isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,
+ maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,
+ raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
+ removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,
setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
@@ -230,6 +231,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -550,6 +553,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSplitterWindow.erl b/lib/wx/src/gen/wxSplitterWindow.erl
index f311d5011f..fb2f355f43 100644
--- a/lib/wx/src/gen/wxSplitterWindow.erl
+++ b/lib/wx/src/gen/wxSplitterWindow.erl
@@ -42,29 +42,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -359,6 +359,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -679,6 +681,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxStaticBitmap.erl b/lib/wx/src/gen/wxStaticBitmap.erl
index 3ef1499a28..64d8cc4364 100644
--- a/lib/wx/src/gen/wxStaticBitmap.erl
+++ b/lib/wx/src/gen/wxStaticBitmap.erl
@@ -38,29 +38,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -168,6 +168,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -484,6 +486,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxStaticBox.erl b/lib/wx/src/gen/wxStaticBox.erl
index 46cca3b6f3..728c02e9e4 100644
--- a/lib/wx/src/gen/wxStaticBox.erl
+++ b/lib/wx/src/gen/wxStaticBox.erl
@@ -38,29 +38,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -90,7 +90,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
new(Parent,Id,Label)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
new(Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstaticbox.html#wxstaticboxwxstaticbox">external documentation</a>.
@@ -100,7 +100,7 @@ new(Parent,Id,Label)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -116,7 +116,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
This::wxStaticBox(), Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
create(This,Parent,Id,Label)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
create(This,Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstaticbox.html#wxstaticboxcreate">external documentation</a>.
@@ -126,7 +126,7 @@ create(This,Parent,Id,Label)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxStaticBox),
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
@@ -151,6 +151,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -467,6 +469,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxStaticLine.erl b/lib/wx/src/gen/wxStaticLine.erl
index 94dd339cfc..3c648b7746 100644
--- a/lib/wx/src/gen/wxStaticLine.erl
+++ b/lib/wx/src/gen/wxStaticLine.erl
@@ -39,29 +39,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -168,6 +168,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -484,6 +486,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxStaticText.erl b/lib/wx/src/gen/wxStaticText.erl
index 37d0219bc6..34216f975f 100644
--- a/lib/wx/src/gen/wxStaticText.erl
+++ b/lib/wx/src/gen/wxStaticText.erl
@@ -38,30 +38,30 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
- getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2,
- setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getMaxSize/1,getMinSize/1,
+ getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,
+ setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
@@ -90,7 +90,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
new(Parent,Id,Label)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
new(Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstatictext.html#wxstatictextwxstatictext">external documentation</a>.
@@ -100,7 +100,7 @@ new(Parent,Id,Label)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -116,7 +116,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
This::wxStaticText(), Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
create(This,Parent,Id,Label)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
create(This,Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstatictext.html#wxstatictextcreate">external documentation</a>.
@@ -126,7 +126,7 @@ create(This,Parent,Id,Label)
| {'size', {W::integer(), H::integer()}}
| {'style', integer()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxStaticText),
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
@@ -150,7 +150,7 @@ getLabel(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setLabel(This, Label) -> 'ok' when
This::wxStaticText(), Label::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label)
- when is_list(Label) ->
+ when ?is_chardata(Label) ->
?CLASS(ThisT,wxStaticText),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxStaticText_SetLabel,
@@ -174,6 +174,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
%% From wxControl
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -490,6 +492,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxStatusBar.erl b/lib/wx/src/gen/wxStatusBar.erl
index d0ce65273b..8d9f77c209 100644
--- a/lib/wx/src/gen/wxStatusBar.erl
+++ b/lib/wx/src/gen/wxStatusBar.erl
@@ -40,29 +40,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -198,7 +198,7 @@ popStatusText(#wx_ref{type=ThisT,ref=ThisRef}, Options)
This::wxStatusBar(), Text::unicode:chardata().
pushStatusText(This,Text)
- when is_record(This, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),?is_chardata(Text) ->
pushStatusText(This,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstatusbar.html#wxstatusbarpushstatustext">external documentation</a>.
@@ -206,7 +206,7 @@ pushStatusText(This,Text)
This::wxStatusBar(), Text::unicode:chardata(),
Option :: {'number', integer()}.
pushStatusText(#wx_ref{type=ThisT,ref=ThisRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxStatusBar),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({number, Number}, Acc) -> [<<1:32/?UI,Number:32/?UI>>|Acc];
@@ -251,7 +251,7 @@ setMinHeight(#wx_ref{type=ThisT,ref=ThisRef},Height)
This::wxStatusBar(), Text::unicode:chardata().
setStatusText(This,Text)
- when is_record(This, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),?is_chardata(Text) ->
setStatusText(This,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstatusbar.html#wxstatusbarsetstatustext">external documentation</a>.
@@ -259,7 +259,7 @@ setStatusText(This,Text)
This::wxStatusBar(), Text::unicode:chardata(),
Option :: {'number', integer()}.
setStatusText(#wx_ref{type=ThisT,ref=ThisRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxStatusBar),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({number, Number}, Acc) -> [<<1:32/?UI,Number:32/?UI>>|Acc];
@@ -296,6 +296,8 @@ destroy(Obj=#wx_ref{type=Type}) ->
ok.
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -616,6 +618,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxStyledTextCtrl.erl b/lib/wx/src/gen/wxStyledTextCtrl.erl
index 15ef728659..7e45245a72 100644
--- a/lib/wx/src/gen/wxStyledTextCtrl.erl
+++ b/lib/wx/src/gen/wxStyledTextCtrl.erl
@@ -140,28 +140,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,
- move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
- parent_class/1,popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,
- popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,
- releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,screenToClient/2,
- scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
- setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,
- setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
+ moveBeforeInTabOrder/2,navigate/1,navigate/2,parent_class/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
+ refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
+ reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
+ scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
+ setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
+ setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
+ setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
+ setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -245,7 +246,7 @@ create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Opti
-spec addText(This, Text) -> 'ok' when
This::wxStyledTextCtrl(), Text::unicode:chardata().
addText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_AddText,
@@ -264,7 +265,7 @@ addStyledText(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DataT,ref=DataRef}) -
-spec insertText(This, Pos, Text) -> 'ok' when
This::wxStyledTextCtrl(), Pos::integer(), Text::unicode:chardata().
insertText(#wx_ref{type=ThisT,ref=ThisRef},Pos,Text)
- when is_integer(Pos),is_list(Text) ->
+ when is_integer(Pos),?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_InsertText,
@@ -822,7 +823,7 @@ styleSetSize(#wx_ref{type=ThisT,ref=ThisRef},Style,SizePoints)
-spec styleSetFaceName(This, Style, FontName) -> 'ok' when
This::wxStyledTextCtrl(), Style::integer(), FontName::unicode:chardata().
styleSetFaceName(#wx_ref{type=ThisT,ref=ThisRef},Style,FontName)
- when is_integer(Style),is_list(FontName) ->
+ when is_integer(Style),?is_chardata(FontName) ->
?CLASS(ThisT,wxStyledTextCtrl),
FontName_UC = unicode:characters_to_binary([FontName,0]),
wxe_util:cast(?wxStyledTextCtrl_StyleSetFaceName,
@@ -981,7 +982,7 @@ setCaretPeriod(#wx_ref{type=ThisT,ref=ThisRef},PeriodMilliseconds)
-spec setWordChars(This, Characters) -> 'ok' when
This::wxStyledTextCtrl(), Characters::unicode:chardata().
setWordChars(#wx_ref{type=ThisT,ref=ThisRef},Characters)
- when is_list(Characters) ->
+ when ?is_chardata(Characters) ->
?CLASS(ThisT,wxStyledTextCtrl),
Characters_UC = unicode:characters_to_binary([Characters,0]),
wxe_util:cast(?wxStyledTextCtrl_SetWordChars,
@@ -1129,7 +1130,7 @@ setCaretLineBackground(#wx_ref{type=ThisT,ref=ThisRef},Back)
-spec autoCompShow(This, LenEntered, ItemList) -> 'ok' when
This::wxStyledTextCtrl(), LenEntered::integer(), ItemList::unicode:chardata().
autoCompShow(#wx_ref{type=ThisT,ref=ThisRef},LenEntered,ItemList)
- when is_integer(LenEntered),is_list(ItemList) ->
+ when is_integer(LenEntered),?is_chardata(ItemList) ->
?CLASS(ThisT,wxStyledTextCtrl),
ItemList_UC = unicode:characters_to_binary([ItemList,0]),
wxe_util:cast(?wxStyledTextCtrl_AutoCompShow,
@@ -1171,7 +1172,7 @@ autoCompComplete(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec autoCompStops(This, CharacterSet) -> 'ok' when
This::wxStyledTextCtrl(), CharacterSet::unicode:chardata().
autoCompStops(#wx_ref{type=ThisT,ref=ThisRef},CharacterSet)
- when is_list(CharacterSet) ->
+ when ?is_chardata(CharacterSet) ->
?CLASS(ThisT,wxStyledTextCtrl),
CharacterSet_UC = unicode:characters_to_binary([CharacterSet,0]),
wxe_util:cast(?wxStyledTextCtrl_AutoCompStops,
@@ -1198,7 +1199,7 @@ autoCompGetSeparator(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec autoCompSelect(This, Text) -> 'ok' when
This::wxStyledTextCtrl(), Text::unicode:chardata().
autoCompSelect(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_AutoCompSelect,
@@ -1225,7 +1226,7 @@ autoCompGetCancelAtStart(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec autoCompSetFillUps(This, CharacterSet) -> 'ok' when
This::wxStyledTextCtrl(), CharacterSet::unicode:chardata().
autoCompSetFillUps(#wx_ref{type=ThisT,ref=ThisRef},CharacterSet)
- when is_list(CharacterSet) ->
+ when ?is_chardata(CharacterSet) ->
?CLASS(ThisT,wxStyledTextCtrl),
CharacterSet_UC = unicode:characters_to_binary([CharacterSet,0]),
wxe_util:cast(?wxStyledTextCtrl_AutoCompSetFillUps,
@@ -1269,7 +1270,7 @@ autoCompGetIgnoreCase(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec userListShow(This, ListType, ItemList) -> 'ok' when
This::wxStyledTextCtrl(), ListType::integer(), ItemList::unicode:chardata().
userListShow(#wx_ref{type=ThisT,ref=ThisRef},ListType,ItemList)
- when is_integer(ListType),is_list(ItemList) ->
+ when is_integer(ListType),?is_chardata(ItemList) ->
?CLASS(ThisT,wxStyledTextCtrl),
ItemList_UC = unicode:characters_to_binary([ItemList,0]),
wxe_util:cast(?wxStyledTextCtrl_UserListShow,
@@ -1614,7 +1615,7 @@ getPrintColourMode(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxStyledTextCtrl(), MinPos::integer(), MaxPos::integer(), Text::unicode:chardata().
findText(This,MinPos,MaxPos,Text)
- when is_record(This, wx_ref),is_integer(MinPos),is_integer(MaxPos),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(MinPos),is_integer(MaxPos),?is_chardata(Text) ->
findText(This,MinPos,MaxPos,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstyledtextctrl.html#wxstyledtextctrlfindtext">external documentation</a>.
@@ -1622,7 +1623,7 @@ findText(This,MinPos,MaxPos,Text)
This::wxStyledTextCtrl(), MinPos::integer(), MaxPos::integer(), Text::unicode:chardata(),
Option :: {'flags', integer()}.
findText(#wx_ref{type=ThisT,ref=ThisRef},MinPos,MaxPos,Text, Options)
- when is_integer(MinPos),is_integer(MaxPos),is_list(Text),is_list(Options) ->
+ when is_integer(MinPos),is_integer(MaxPos),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({flags, Flags}, Acc) -> [<<1:32/?UI,Flags:32/?UI>>|Acc];
@@ -1783,7 +1784,7 @@ ensureCaretVisible(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec replaceSelection(This, Text) -> 'ok' when
This::wxStyledTextCtrl(), Text::unicode:chardata().
replaceSelection(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_ReplaceSelection,
@@ -1866,7 +1867,7 @@ clear(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setText(This, Text) -> 'ok' when
This::wxStyledTextCtrl(), Text::unicode:chardata().
setText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_SetText,
@@ -1951,7 +1952,7 @@ getTargetEnd(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec replaceTarget(This, Text) -> integer() when
This::wxStyledTextCtrl(), Text::unicode:chardata().
replaceTarget(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxStyledTextCtrl_ReplaceTarget,
@@ -1961,7 +1962,7 @@ replaceTarget(#wx_ref{type=ThisT,ref=ThisRef},Text)
-spec searchInTarget(This, Text) -> integer() when
This::wxStyledTextCtrl(), Text::unicode:chardata().
searchInTarget(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxStyledTextCtrl_SearchInTarget,
@@ -1988,7 +1989,7 @@ getSearchFlags(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec callTipShow(This, Pos, Definition) -> 'ok' when
This::wxStyledTextCtrl(), Pos::integer(), Definition::unicode:chardata().
callTipShow(#wx_ref{type=ThisT,ref=ThisRef},Pos,Definition)
- when is_integer(Pos),is_list(Definition) ->
+ when is_integer(Pos),?is_chardata(Definition) ->
?CLASS(ThisT,wxStyledTextCtrl),
Definition_UC = unicode:characters_to_binary([Definition,0]),
wxe_util:cast(?wxStyledTextCtrl_CallTipShow,
@@ -2382,7 +2383,7 @@ getScrollWidth(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec textWidth(This, Style, Text) -> integer() when
This::wxStyledTextCtrl(), Style::integer(), Text::unicode:chardata().
textWidth(#wx_ref{type=ThisT,ref=ThisRef},Style,Text)
- when is_integer(Style),is_list(Text) ->
+ when is_integer(Style),?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxStyledTextCtrl_TextWidth,
@@ -2426,7 +2427,7 @@ getUseVerticalScrollBar(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec appendText(This, Text) -> 'ok' when
This::wxStyledTextCtrl(), Text::unicode:chardata().
appendText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_AppendText,
@@ -3073,7 +3074,7 @@ searchAnchor(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec searchNext(This, Flags, Text) -> integer() when
This::wxStyledTextCtrl(), Flags::integer(), Text::unicode:chardata().
searchNext(#wx_ref{type=ThisT,ref=ThisRef},Flags,Text)
- when is_integer(Flags),is_list(Text) ->
+ when is_integer(Flags),?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxStyledTextCtrl_SearchNext,
@@ -3083,7 +3084,7 @@ searchNext(#wx_ref{type=ThisT,ref=ThisRef},Flags,Text)
-spec searchPrev(This, Flags, Text) -> integer() when
This::wxStyledTextCtrl(), Flags::integer(), Text::unicode:chardata().
searchPrev(#wx_ref{type=ThisT,ref=ThisRef},Flags,Text)
- when is_integer(Flags),is_list(Text) ->
+ when is_integer(Flags),?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:call(?wxStyledTextCtrl_SearchPrev,
@@ -3414,7 +3415,7 @@ copyRange(#wx_ref{type=ThisT,ref=ThisRef},Start,End)
-spec copyText(This, Length, Text) -> 'ok' when
This::wxStyledTextCtrl(), Length::integer(), Text::unicode:chardata().
copyText(#wx_ref{type=ThisT,ref=ThisRef},Length,Text)
- when is_integer(Length),is_list(Text) ->
+ when is_integer(Length),?is_chardata(Text) ->
?CLASS(ThisT,wxStyledTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxStyledTextCtrl_CopyText,
@@ -3577,7 +3578,7 @@ wordRightEndExtend(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setWhitespaceChars(This, Characters) -> 'ok' when
This::wxStyledTextCtrl(), Characters::unicode:chardata().
setWhitespaceChars(#wx_ref{type=ThisT,ref=ThisRef},Characters)
- when is_list(Characters) ->
+ when ?is_chardata(Characters) ->
?CLASS(ThisT,wxStyledTextCtrl),
Characters_UC = unicode:characters_to_binary([Characters,0]),
wxe_util:cast(?wxStyledTextCtrl_SetWhitespaceChars,
@@ -3730,7 +3731,7 @@ colourise(#wx_ref{type=ThisT,ref=ThisRef},Start,End)
-spec setProperty(This, Key, Value) -> 'ok' when
This::wxStyledTextCtrl(), Key::unicode:chardata(), Value::unicode:chardata().
setProperty(#wx_ref{type=ThisT,ref=ThisRef},Key,Value)
- when is_list(Key),is_list(Value) ->
+ when ?is_chardata(Key),?is_chardata(Value) ->
?CLASS(ThisT,wxStyledTextCtrl),
Key_UC = unicode:characters_to_binary([Key,0]),
Value_UC = unicode:characters_to_binary([Value,0]),
@@ -3741,7 +3742,7 @@ setProperty(#wx_ref{type=ThisT,ref=ThisRef},Key,Value)
-spec setKeyWords(This, KeywordSet, KeyWords) -> 'ok' when
This::wxStyledTextCtrl(), KeywordSet::integer(), KeyWords::unicode:chardata().
setKeyWords(#wx_ref{type=ThisT,ref=ThisRef},KeywordSet,KeyWords)
- when is_integer(KeywordSet),is_list(KeyWords) ->
+ when is_integer(KeywordSet),?is_chardata(KeyWords) ->
?CLASS(ThisT,wxStyledTextCtrl),
KeyWords_UC = unicode:characters_to_binary([KeyWords,0]),
wxe_util:cast(?wxStyledTextCtrl_SetKeyWords,
@@ -3751,7 +3752,7 @@ setKeyWords(#wx_ref{type=ThisT,ref=ThisRef},KeywordSet,KeyWords)
-spec setLexerLanguage(This, Language) -> 'ok' when
This::wxStyledTextCtrl(), Language::unicode:chardata().
setLexerLanguage(#wx_ref{type=ThisT,ref=ThisRef},Language)
- when is_list(Language) ->
+ when ?is_chardata(Language) ->
?CLASS(ThisT,wxStyledTextCtrl),
Language_UC = unicode:characters_to_binary([Language,0]),
wxe_util:cast(?wxStyledTextCtrl_SetLexerLanguage,
@@ -3761,7 +3762,7 @@ setLexerLanguage(#wx_ref{type=ThisT,ref=ThisRef},Language)
-spec getProperty(This, Key) -> unicode:charlist() when
This::wxStyledTextCtrl(), Key::unicode:chardata().
getProperty(#wx_ref{type=ThisT,ref=ThisRef},Key)
- when is_list(Key) ->
+ when ?is_chardata(Key) ->
?CLASS(ThisT,wxStyledTextCtrl),
Key_UC = unicode:characters_to_binary([Key,0]),
wxe_util:call(?wxStyledTextCtrl_GetProperty,
@@ -3787,7 +3788,7 @@ getCurrentLine(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec styleSetSpec(This, StyleNum, Spec) -> 'ok' when
This::wxStyledTextCtrl(), StyleNum::integer(), Spec::unicode:chardata().
styleSetSpec(#wx_ref{type=ThisT,ref=ThisRef},StyleNum,Spec)
- when is_integer(StyleNum),is_list(Spec) ->
+ when is_integer(StyleNum),?is_chardata(Spec) ->
?CLASS(ThisT,wxStyledTextCtrl),
Spec_UC = unicode:characters_to_binary([Spec,0]),
wxe_util:cast(?wxStyledTextCtrl_StyleSetSpec,
@@ -3808,7 +3809,7 @@ styleSetFont(#wx_ref{type=ThisT,ref=ThisRef},StyleNum,#wx_ref{type=FontT,ref=Fon
This::wxStyledTextCtrl(), StyleNum::integer(), Size::integer(), FaceName::unicode:chardata(), Bold::boolean(), Italic::boolean(), Underline::boolean().
styleSetFontAttr(This,StyleNum,Size,FaceName,Bold,Italic,Underline)
- when is_record(This, wx_ref),is_integer(StyleNum),is_integer(Size),is_list(FaceName),is_boolean(Bold),is_boolean(Italic),is_boolean(Underline) ->
+ when is_record(This, wx_ref),is_integer(StyleNum),is_integer(Size),?is_chardata(FaceName),is_boolean(Bold),is_boolean(Italic),is_boolean(Underline) ->
styleSetFontAttr(This,StyleNum,Size,FaceName,Bold,Italic,Underline, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxstyledtextctrl.html#wxstyledtextctrlstylesetfontattr">external documentation</a>.
@@ -3817,7 +3818,7 @@ styleSetFontAttr(This,StyleNum,Size,FaceName,Bold,Italic,Underline)
This::wxStyledTextCtrl(), StyleNum::integer(), Size::integer(), FaceName::unicode:chardata(), Bold::boolean(), Italic::boolean(), Underline::boolean(),
Option :: {'encoding', wx:wx_enum()}.
styleSetFontAttr(#wx_ref{type=ThisT,ref=ThisRef},StyleNum,Size,FaceName,Bold,Italic,Underline, Options)
- when is_integer(StyleNum),is_integer(Size),is_list(FaceName),is_boolean(Bold),is_boolean(Italic),is_boolean(Underline),is_list(Options) ->
+ when is_integer(StyleNum),is_integer(Size),?is_chardata(FaceName),is_boolean(Bold),is_boolean(Italic),is_boolean(Underline),is_list(Options) ->
?CLASS(ThisT,wxStyledTextCtrl),
FaceName_UC = unicode:characters_to_binary([FaceName,0]),
MOpts = fun({encoding, Encoding}, Acc) -> [<<1:32/?UI,Encoding:32/?UI>>|Acc];
@@ -3937,7 +3938,7 @@ setLastKeydownProcessed(#wx_ref{type=ThisT,ref=ThisRef},Val)
-spec saveFile(This, Filename) -> boolean() when
This::wxStyledTextCtrl(), Filename::unicode:chardata().
saveFile(#wx_ref{type=ThisT,ref=ThisRef},Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
?CLASS(ThisT,wxStyledTextCtrl),
Filename_UC = unicode:characters_to_binary([Filename,0]),
wxe_util:call(?wxStyledTextCtrl_SaveFile,
@@ -3947,7 +3948,7 @@ saveFile(#wx_ref{type=ThisT,ref=ThisRef},Filename)
-spec loadFile(This, Filename) -> boolean() when
This::wxStyledTextCtrl(), Filename::unicode:chardata().
loadFile(#wx_ref{type=ThisT,ref=ThisRef},Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
?CLASS(ThisT,wxStyledTextCtrl),
Filename_UC = unicode:characters_to_binary([Filename,0]),
wxe_util:call(?wxStyledTextCtrl_LoadFile,
@@ -3968,7 +3969,7 @@ doDragOver(#wx_ref{type=ThisT,ref=ThisRef},X,Y,Def)
-spec doDropText(This, X, Y, Data) -> boolean() when
This::wxStyledTextCtrl(), X::integer(), Y::integer(), Data::unicode:chardata().
doDropText(#wx_ref{type=ThisT,ref=ThisRef},X,Y,Data)
- when is_integer(X),is_integer(Y),is_list(Data) ->
+ when is_integer(X),is_integer(Y),?is_chardata(Data) ->
?CLASS(ThisT,wxStyledTextCtrl),
Data_UC = unicode:characters_to_binary([Data,0]),
wxe_util:call(?wxStyledTextCtrl_DoDropText,
@@ -4078,6 +4079,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -4386,6 +4389,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxSystemOptions.erl b/lib/wx/src/gen/wxSystemOptions.erl
index 28d77b1e26..c613d66c73 100644
--- a/lib/wx/src/gen/wxSystemOptions.erl
+++ b/lib/wx/src/gen/wxSystemOptions.erl
@@ -39,7 +39,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-spec getOption(Name) -> unicode:charlist() when
Name::unicode:chardata().
getOption(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxSystemOptions_GetOption,
<<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -48,7 +48,7 @@ getOption(Name)
-spec getOptionInt(Name) -> integer() when
Name::unicode:chardata().
getOptionInt(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxSystemOptions_GetOptionInt,
<<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -57,7 +57,7 @@ getOptionInt(Name)
-spec hasOption(Name) -> boolean() when
Name::unicode:chardata().
hasOption(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxSystemOptions_HasOption,
<<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -66,7 +66,7 @@ hasOption(Name)
-spec isFalse(Name) -> boolean() when
Name::unicode:chardata().
isFalse(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxSystemOptions_IsFalse,
<<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -81,12 +81,12 @@ isFalse(Name)
(Name, Value) -> 'ok' when
Name::unicode:chardata(), Value::unicode:chardata().
setOption(Name,Value)
- when is_list(Name),is_integer(Value) ->
+ when ?is_chardata(Name),is_integer(Value) ->
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:cast(?wxSystemOptions_SetOption_2_0,
<<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,Value:32/?UI>>);
setOption(Name,Value)
- when is_list(Name),is_list(Value) ->
+ when ?is_chardata(Name),?is_chardata(Value) ->
Name_UC = unicode:characters_to_binary([Name,0]),
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:cast(?wxSystemOptions_SetOption_2_1,
diff --git a/lib/wx/src/gen/wxTextCtrl.erl b/lib/wx/src/gen/wxTextCtrl.erl
index 5f03398959..3acc61ce02 100644
--- a/lib/wx/src/gen/wxTextCtrl.erl
+++ b/lib/wx/src/gen/wxTextCtrl.erl
@@ -46,29 +46,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -126,7 +126,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
-spec appendText(This, Text) -> 'ok' when
This::wxTextCtrl(), Text::unicode:chardata().
appendText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxTextCtrl_AppendText,
@@ -238,7 +238,7 @@ discardEdits(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec changeValue(This, Value) -> 'ok' when
This::wxTextCtrl(), Value::unicode:chardata().
changeValue(#wx_ref{type=ThisT,ref=ThisRef},Value)
- when is_list(Value) ->
+ when ?is_chardata(Value) ->
?CLASS(ThisT,wxTextCtrl),
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:cast(?wxTextCtrl_ChangeValue,
@@ -383,7 +383,7 @@ isSingleLine(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxTextCtrl(), File::unicode:chardata().
loadFile(This,File)
- when is_record(This, wx_ref),is_list(File) ->
+ when is_record(This, wx_ref),?is_chardata(File) ->
loadFile(This,File, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtextctrl.html#wxtextctrlloadfile">external documentation</a>.
@@ -391,7 +391,7 @@ loadFile(This,File)
This::wxTextCtrl(), File::unicode:chardata(),
Option :: {'fileType', integer()}.
loadFile(#wx_ref{type=ThisT,ref=ThisRef},File, Options)
- when is_list(File),is_list(Options) ->
+ when ?is_chardata(File),is_list(Options) ->
?CLASS(ThisT,wxTextCtrl),
File_UC = unicode:characters_to_binary([File,0]),
MOpts = fun({fileType, FileType}, Acc) -> [<<1:32/?UI,FileType:32/?UI>>|Acc];
@@ -447,7 +447,7 @@ remove(#wx_ref{type=ThisT,ref=ThisRef},From,To)
-spec replace(This, From, To, Value) -> 'ok' when
This::wxTextCtrl(), From::integer(), To::integer(), Value::unicode:chardata().
replace(#wx_ref{type=ThisT,ref=ThisRef},From,To,Value)
- when is_integer(From),is_integer(To),is_list(Value) ->
+ when is_integer(From),is_integer(To),?is_chardata(Value) ->
?CLASS(ThisT,wxTextCtrl),
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:cast(?wxTextCtrl_Replace,
@@ -543,7 +543,7 @@ setStyle(#wx_ref{type=ThisT,ref=ThisRef},Start,End,#wx_ref{type=StyleT,ref=Style
-spec setValue(This, Value) -> 'ok' when
This::wxTextCtrl(), Value::unicode:chardata().
setValue(#wx_ref{type=ThisT,ref=ThisRef},Value)
- when is_list(Value) ->
+ when ?is_chardata(Value) ->
?CLASS(ThisT,wxTextCtrl),
Value_UC = unicode:characters_to_binary([Value,0]),
wxe_util:cast(?wxTextCtrl_SetValue,
@@ -570,7 +570,7 @@ undo(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec writeText(This, Text) -> 'ok' when
This::wxTextCtrl(), Text::unicode:chardata().
writeText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxTextCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxTextCtrl_WriteText,
@@ -598,6 +598,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -914,6 +916,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxTextDataObject.erl b/lib/wx/src/gen/wxTextDataObject.erl
index eb3e1f4bff..5c8a44a879 100644
--- a/lib/wx/src/gen/wxTextDataObject.erl
+++ b/lib/wx/src/gen/wxTextDataObject.erl
@@ -76,7 +76,7 @@ getText(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setText(This, Text) -> 'ok' when
This::wxTextDataObject(), Text::unicode:chardata().
setText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxTextDataObject),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxTextDataObject_SetText,
diff --git a/lib/wx/src/gen/wxTextEntryDialog.erl b/lib/wx/src/gen/wxTextEntryDialog.erl
index eaf6dc3926..c43a2d12b8 100644
--- a/lib/wx/src/gen/wxTextEntryDialog.erl
+++ b/lib/wx/src/gen/wxTextEntryDialog.erl
@@ -40,40 +40,40 @@
centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1,
- disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2,
- endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,getLabel/1,getMaxSize/1,
- getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getReturnCode/1,
- getScreenPosition/1,getScreenRect/1,getScrollPos/2,getScrollRange/2,
- getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,
- getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1,
- isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,
- isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1,
- isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,
- makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,
- moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,
- popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,
- raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,
- removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2,
- screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,
- scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,
- setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,
- setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3,
- setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,
- setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,
- setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,
- setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,
- setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
+ disable/1,disconnect/1,disconnect/2,disconnect/3,dragAcceptFiles/2,
+ enable/1,enable/2,endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,
+ getAcceleratorTable/1,getAffirmativeId/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getIcon/1,getIcons/1,getId/1,
+ getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,getPosition/1,
+ getRect/1,getReturnCode/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,
+ getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2,
+ hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,
+ isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,
+ lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3,
+ move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2,
+ pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,
+ requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2,
+ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,
+ setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,
+ setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,
+ setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2,
+ setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,
+ setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
+ setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,
+ setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,
+ setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4,
setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,
show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1,
transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1,
@@ -93,7 +93,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
Parent::wxWindow:wxWindow(), Message::unicode:chardata().
new(Parent,Message)
- when is_record(Parent, wx_ref),is_list(Message) ->
+ when is_record(Parent, wx_ref),?is_chardata(Message) ->
new(Parent,Message, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtextentrydialog.html#wxtextentrydialogwxtextentrydialog">external documentation</a>.
@@ -104,7 +104,7 @@ new(Parent,Message)
| {'style', integer()}
| {'pos', {X::integer(), Y::integer()}}.
new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options)
- when is_list(Message),is_list(Options) ->
+ when ?is_chardata(Message),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Message_UC = unicode:characters_to_binary([Message,0]),
MOpts = fun({caption, Caption}, Acc) -> Caption_UC = unicode:characters_to_binary([Caption,0]),[<<1:32/?UI,(byte_size(Caption_UC)):32/?UI,(Caption_UC)/binary, 0:(((8- ((0+byte_size(Caption_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -128,7 +128,7 @@ getValue(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setValue(This, Val) -> 'ok' when
This::wxTextEntryDialog(), Val::unicode:chardata().
setValue(#wx_ref{type=ThisT,ref=ThisRef},Val)
- when is_list(Val) ->
+ when ?is_chardata(Val) ->
?CLASS(ThisT,wxTextEntryDialog),
Val_UC = unicode:characters_to_binary([Val,0]),
wxe_util:cast(?wxTextEntryDialog_SetValue,
@@ -212,6 +212,8 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This).
getIcon(This) -> wxTopLevelWindow:getIcon(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -528,6 +530,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxToggleButton.erl b/lib/wx/src/gen/wxToggleButton.erl
index 9e8dab1c32..b82ff4fe68 100644
--- a/lib/wx/src/gen/wxToggleButton.erl
+++ b/lib/wx/src/gen/wxToggleButton.erl
@@ -38,29 +38,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -90,7 +90,7 @@ new() ->
Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
new(Parent,Id,Label)
- when is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
new(Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtogglebutton.html#wxtogglebuttonwxtogglebutton">external documentation</a>.
@@ -101,7 +101,7 @@ new(Parent,Id,Label)
| {'style', integer()}
| {'validator', wx:wx_object()}.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({pos, {PosX,PosY}}, Acc) -> [<<1:32/?UI,PosX:32/?UI,PosY:32/?UI,0:32>>|Acc];
@@ -118,7 +118,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
This::wxToggleButton(), Parent::wxWindow:wxWindow(), Id::integer(), Label::unicode:chardata().
create(This,Parent,Id,Label)
- when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Label) ->
+ when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),?is_chardata(Label) ->
create(This,Parent,Id,Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtogglebutton.html#wxtogglebuttoncreate">external documentation</a>.
@@ -129,7 +129,7 @@ create(This,Parent,Id,Label)
| {'style', integer()}
| {'validator', wx:wx_object()}.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
- when is_integer(Id),is_list(Label),is_list(Options) ->
+ when is_integer(Id),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxToggleButton),
?CLASS(ParentT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
@@ -172,6 +172,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -488,6 +490,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxToolBar.erl b/lib/wx/src/gen/wxToolBar.erl
index 9be37f943c..e2835bf7c4 100644
--- a/lib/wx/src/gen/wxToolBar.erl
+++ b/lib/wx/src/gen/wxToolBar.erl
@@ -47,29 +47,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -142,7 +142,7 @@ addTool(This,Toolid,Bitmap)
| {'longHelpString', unicode:chardata()}.
addTool(This,Toolid,Label,Bitmap)
- when is_record(This, wx_ref),is_integer(Toolid),is_list(Label),is_record(Bitmap, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Toolid),?is_chardata(Label),is_record(Bitmap, wx_ref) ->
addTool(This,Toolid,Label,Bitmap, []);
addTool(This,Toolid,Bitmap,BmpDisabled)
@@ -187,10 +187,10 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,#wx_ref{type=BitmapT,ref=BitmapRe
| {'longHelpString', unicode:chardata()}.
addTool(This,Toolid,Label,Bitmap,BmpDisabled)
- when is_record(This, wx_ref),is_integer(Toolid),is_list(Label),is_record(Bitmap, wx_ref),is_record(BmpDisabled, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Toolid),?is_chardata(Label),is_record(Bitmap, wx_ref),is_record(BmpDisabled, wx_ref) ->
addTool(This,Toolid,Label,Bitmap,BmpDisabled, []);
addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
- when is_integer(Toolid),is_list(Label),is_list(Options) ->
+ when is_integer(Toolid),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxToolBar),
Label_UC = unicode:characters_to_binary([Label,0]),
?CLASS(BitmapT,wxBitmap),
@@ -237,7 +237,7 @@ addTool(This,Toolid,Bitmap,BmpDisabled,Toggle,XPos)
when is_record(This, wx_ref),is_integer(Toolid),is_record(Bitmap, wx_ref),is_record(BmpDisabled, wx_ref),is_boolean(Toggle),is_integer(XPos) ->
addTool(This,Toolid,Bitmap,BmpDisabled,Toggle,XPos, []);
addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef},#wx_ref{type=BmpDisabledT,ref=BmpDisabledRef}, Options)
- when is_integer(Toolid),is_list(Label),is_list(Options) ->
+ when is_integer(Toolid),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxToolBar),
Label_UC = unicode:characters_to_binary([Label,0]),
?CLASS(BitmapT,wxBitmap),
@@ -277,7 +277,7 @@ addTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,#wx_ref{type=BitmapT,ref=BitmapRe
This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap().
addCheckTool(This,Toolid,Label,Bitmap)
- when is_record(This, wx_ref),is_integer(Toolid),is_list(Label),is_record(Bitmap, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Toolid),?is_chardata(Label),is_record(Bitmap, wx_ref) ->
addCheckTool(This,Toolid,Label,Bitmap, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbar.html#wxtoolbaraddchecktool">external documentation</a>.
@@ -288,7 +288,7 @@ addCheckTool(This,Toolid,Label,Bitmap)
| {'longHelp', unicode:chardata()}
| {'data', wx:wx_object()}.
addCheckTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
- when is_integer(Toolid),is_list(Label),is_list(Options) ->
+ when is_integer(Toolid),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxToolBar),
Label_UC = unicode:characters_to_binary([Label,0]),
?CLASS(BitmapT,wxBitmap),
@@ -306,7 +306,7 @@ addCheckTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,r
This::wxToolBar(), Toolid::integer(), Label::unicode:chardata(), Bitmap::wxBitmap:wxBitmap().
addRadioTool(This,Toolid,Label,Bitmap)
- when is_record(This, wx_ref),is_integer(Toolid),is_list(Label),is_record(Bitmap, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Toolid),?is_chardata(Label),is_record(Bitmap, wx_ref) ->
addRadioTool(This,Toolid,Label,Bitmap, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbar.html#wxtoolbaraddradiotool">external documentation</a>.
@@ -317,7 +317,7 @@ addRadioTool(This,Toolid,Label,Bitmap)
| {'longHelp', unicode:chardata()}
| {'data', wx:wx_object()}.
addRadioTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
- when is_integer(Toolid),is_list(Label),is_list(Options) ->
+ when is_integer(Toolid),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxToolBar),
Label_UC = unicode:characters_to_binary([Label,0]),
?CLASS(BitmapT,wxBitmap),
@@ -545,7 +545,7 @@ insertTool(This,Pos,Toolid,Bitmap)
| {'longHelp', unicode:chardata()}.
insertTool(This,Pos,Toolid,Label,Bitmap)
- when is_record(This, wx_ref),is_integer(Pos),is_integer(Toolid),is_list(Label),is_record(Bitmap, wx_ref) ->
+ when is_record(This, wx_ref),is_integer(Pos),is_integer(Toolid),?is_chardata(Label),is_record(Bitmap, wx_ref) ->
insertTool(This,Pos,Toolid,Label,Bitmap, []);
insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,Toolid,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
when is_integer(Pos),is_integer(Toolid),is_list(Options) ->
@@ -571,7 +571,7 @@ insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,Toolid,#wx_ref{type=BitmapT,ref=B
| {'longHelp', unicode:chardata()}
| {'clientData', wx:wx_object()}.
insertTool(#wx_ref{type=ThisT,ref=ThisRef},Pos,Toolid,Label,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
- when is_integer(Pos),is_integer(Toolid),is_list(Label),is_list(Options) ->
+ when is_integer(Pos),is_integer(Toolid),?is_chardata(Label),is_list(Options) ->
?CLASS(ThisT,wxToolBar),
Label_UC = unicode:characters_to_binary([Label,0]),
?CLASS(BitmapT,wxBitmap),
@@ -624,7 +624,7 @@ setToolBitmapSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
-spec setToolLongHelp(This, Toolid, HelpString) -> 'ok' when
This::wxToolBar(), Toolid::integer(), HelpString::unicode:chardata().
setToolLongHelp(#wx_ref{type=ThisT,ref=ThisRef},Toolid,HelpString)
- when is_integer(Toolid),is_list(HelpString) ->
+ when is_integer(Toolid),?is_chardata(HelpString) ->
?CLASS(ThisT,wxToolBar),
HelpString_UC = unicode:characters_to_binary([HelpString,0]),
wxe_util:cast(?wxToolBar_SetToolLongHelp,
@@ -643,7 +643,7 @@ setToolPacking(#wx_ref{type=ThisT,ref=ThisRef},Packing)
-spec setToolShortHelp(This, Id, HelpString) -> 'ok' when
This::wxToolBar(), Id::integer(), HelpString::unicode:chardata().
setToolShortHelp(#wx_ref{type=ThisT,ref=ThisRef},Id,HelpString)
- when is_integer(Id),is_list(HelpString) ->
+ when is_integer(Id),?is_chardata(HelpString) ->
?CLASS(ThisT,wxToolBar),
HelpString_UC = unicode:characters_to_binary([HelpString,0]),
wxe_util:cast(?wxToolBar_SetToolShortHelp,
@@ -674,6 +674,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -990,6 +992,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxToolTip.erl b/lib/wx/src/gen/wxToolTip.erl
index 163e764d8c..0596173ebe 100644
--- a/lib/wx/src/gen/wxToolTip.erl
+++ b/lib/wx/src/gen/wxToolTip.erl
@@ -55,7 +55,7 @@ setDelay(Msecs)
-spec new(Tip) -> wxToolTip() when
Tip::unicode:chardata().
new(Tip)
- when is_list(Tip) ->
+ when ?is_chardata(Tip) ->
Tip_UC = unicode:characters_to_binary([Tip,0]),
wxe_util:construct(?wxToolTip_new,
<<(byte_size(Tip_UC)):32/?UI,(Tip_UC)/binary, 0:(((8- ((4+byte_size(Tip_UC)) band 16#7)) band 16#7))/unit:8>>).
@@ -64,7 +64,7 @@ new(Tip)
-spec setTip(This, Tip) -> 'ok' when
This::wxToolTip(), Tip::unicode:chardata().
setTip(#wx_ref{type=ThisT,ref=ThisRef},Tip)
- when is_list(Tip) ->
+ when ?is_chardata(Tip) ->
?CLASS(ThisT,wxToolTip),
Tip_UC = unicode:characters_to_binary([Tip,0]),
wxe_util:cast(?wxToolTip_SetTip,
diff --git a/lib/wx/src/gen/wxToolbook.erl b/lib/wx/src/gen/wxToolbook.erl
index 92dcbc726b..c22719680c 100644
--- a/lib/wx/src/gen/wxToolbook.erl
+++ b/lib/wx/src/gen/wxToolbook.erl
@@ -43,29 +43,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -120,7 +120,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
This::wxToolbook(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
addPage(This,Page,Text)
- when is_record(This, wx_ref),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_record(Page, wx_ref),?is_chardata(Text) ->
addPage(This,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbook.html#wxtoolbookaddpage">external documentation</a>.
@@ -129,7 +129,7 @@ addPage(This,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
addPage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxToolbook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -296,7 +296,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
This::wxToolbook(), N::integer(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
insertPage(This,N,Page,Text)
- when is_record(This, wx_ref),is_integer(N),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(N),is_record(Page, wx_ref),?is_chardata(Text) ->
insertPage(This,N,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbook.html#wxtoolbookinsertpage">external documentation</a>.
@@ -305,7 +305,7 @@ insertPage(This,N,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
insertPage(#wx_ref{type=ThisT,ref=ThisRef},N,#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_integer(N),is_list(Text),is_list(Options) ->
+ when is_integer(N),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxToolbook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -347,7 +347,7 @@ setPageImage(#wx_ref{type=ThisT,ref=ThisRef},N,ImageId)
-spec setPageText(This, N, StrText) -> boolean() when
This::wxToolbook(), N::integer(), StrText::unicode:chardata().
setPageText(#wx_ref{type=ThisT,ref=ThisRef},N,StrText)
- when is_integer(N),is_list(StrText) ->
+ when is_integer(N),?is_chardata(StrText) ->
?CLASS(ThisT,wxToolbook),
StrText_UC = unicode:characters_to_binary([StrText,0]),
wxe_util:call(?wxToolbook_SetPageText,
@@ -384,6 +384,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -700,6 +702,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxTopLevelWindow.erl b/lib/wx/src/gen/wxTopLevelWindow.erl
index 6ba81691c7..64713099f6 100644
--- a/lib/wx/src/gen/wxTopLevelWindow.erl
+++ b/lib/wx/src/gen/wxTopLevelWindow.erl
@@ -41,29 +41,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -273,7 +273,7 @@ setShape(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) ->
-spec setTitle(This, Title) -> 'ok' when
This::wxTopLevelWindow(), Title::unicode:chardata().
setTitle(#wx_ref{type=ThisT,ref=ThisRef},Title)
- when is_list(Title) ->
+ when ?is_chardata(Title) ->
?CLASS(ThisT,wxTopLevelWindow),
Title_UC = unicode:characters_to_binary([Title,0]),
wxe_util:cast(?wxTopLevelWindow_SetTitle,
@@ -302,6 +302,8 @@ showFullScreen(#wx_ref{type=ThisT,ref=ThisRef},Show, Options)
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -622,6 +624,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxTreeCtrl.erl b/lib/wx/src/gen/wxTreeCtrl.erl
index 97b43309ad..373cb4c77f 100644
--- a/lib/wx/src/gen/wxTreeCtrl.erl
+++ b/lib/wx/src/gen/wxTreeCtrl.erl
@@ -59,29 +59,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -140,7 +140,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
This::wxTreeCtrl(), Text::unicode:chardata().
addRoot(This,Text)
- when is_record(This, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),?is_chardata(Text) ->
addRoot(This,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreectrl.html#wxtreectrladdroot">external documentation</a>.
@@ -150,7 +150,7 @@ addRoot(This,Text)
| {'selectedImage', integer()}
| {'data', term()}.
addRoot(#wx_ref{type=ThisT,ref=ThisRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreeCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({image, Image}, Acc) -> [<<1:32/?UI,Image:32/?UI>>|Acc];
@@ -166,7 +166,7 @@ addRoot(#wx_ref{type=ThisT,ref=ThisRef},Text, Options)
This::wxTreeCtrl(), Parent::integer(), Text::unicode:chardata().
appendItem(This,Parent,Text)
- when is_record(This, wx_ref),is_integer(Parent),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Parent),?is_chardata(Text) ->
appendItem(This,Parent,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreectrl.html#wxtreectrlappenditem">external documentation</a>.
@@ -176,7 +176,7 @@ appendItem(This,Parent,Text)
| {'selectedImage', integer()}
| {'data', term()}.
appendItem(#wx_ref{type=ThisT,ref=ThisRef},Parent,Text, Options)
- when is_integer(Parent),is_list(Text),is_list(Options) ->
+ when is_integer(Parent),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreeCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({image, Image}, Acc) -> [<<1:32/?UI,Image:32/?UI>>|Acc];
@@ -580,7 +580,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY})
This::wxTreeCtrl(), Parent::integer(), Pos::integer(), Text::unicode:chardata().
insertItem(This,Parent,Pos,Text)
- when is_record(This, wx_ref),is_integer(Parent),is_integer(Pos),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Parent),is_integer(Pos),?is_chardata(Text) ->
insertItem(This,Parent,Pos,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreectrl.html#wxtreectrlinsertitem">external documentation</a>.
@@ -590,7 +590,7 @@ insertItem(This,Parent,Pos,Text)
| {'selImage', integer()}
| {'data', term()}.
insertItem(#wx_ref{type=ThisT,ref=ThisRef},Parent,Pos,Text, Options)
- when is_integer(Parent),is_integer(Pos),is_list(Text),is_list(Options) ->
+ when is_integer(Parent),is_integer(Pos),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreeCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({image, Image}, Acc) -> [<<1:32/?UI,Image:32/?UI>>|Acc];
@@ -659,7 +659,7 @@ isTreeItemIdOk(Id)
This::wxTreeCtrl(), Parent::integer(), Text::unicode:chardata().
prependItem(This,Parent,Text)
- when is_record(This, wx_ref),is_integer(Parent),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Parent),?is_chardata(Text) ->
prependItem(This,Parent,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreectrl.html#wxtreectrlprependitem">external documentation</a>.
@@ -669,7 +669,7 @@ prependItem(This,Parent,Text)
| {'selectedImage', integer()}
| {'data', term()}.
prependItem(#wx_ref{type=ThisT,ref=ThisRef},Parent,Text, Options)
- when is_integer(Parent),is_list(Text),is_list(Options) ->
+ when is_integer(Parent),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreeCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
MOpts = fun({image, Image}, Acc) -> [<<1:32/?UI,Image:32/?UI>>|Acc];
@@ -848,7 +848,7 @@ setItemImage(#wx_ref{type=ThisT,ref=ThisRef},Item,Image, Options)
-spec setItemText(This, Item, Text) -> 'ok' when
This::wxTreeCtrl(), Item::integer(), Text::unicode:chardata().
setItemText(#wx_ref{type=ThisT,ref=ThisRef},Item,Text)
- when is_integer(Item),is_list(Text) ->
+ when is_integer(Item),?is_chardata(Text) ->
?CLASS(ThisT,wxTreeCtrl),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxTreeCtrl_SetItemText,
@@ -946,6 +946,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -1260,6 +1262,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxTreeEvent.erl b/lib/wx/src/gen/wxTreeEvent.erl
index 41e86fe41f..368f32a386 100644
--- a/lib/wx/src/gen/wxTreeEvent.erl
+++ b/lib/wx/src/gen/wxTreeEvent.erl
@@ -111,7 +111,7 @@ isEditCancelled(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec setToolTip(This, ToolTip) -> 'ok' when
This::wxTreeEvent(), ToolTip::unicode:chardata().
setToolTip(#wx_ref{type=ThisT,ref=ThisRef},ToolTip)
- when is_list(ToolTip) ->
+ when ?is_chardata(ToolTip) ->
?CLASS(ThisT,wxTreeEvent),
ToolTip_UC = unicode:characters_to_binary([ToolTip,0]),
wxe_util:cast(?wxTreeEvent_SetToolTip,
diff --git a/lib/wx/src/gen/wxTreebook.erl b/lib/wx/src/gen/wxTreebook.erl
index 5d3c177f7e..dc95730224 100644
--- a/lib/wx/src/gen/wxTreebook.erl
+++ b/lib/wx/src/gen/wxTreebook.erl
@@ -44,29 +44,29 @@
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2,
destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3,
- enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1,
- getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,getContainingSizer/1,
- getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
- getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
- getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
- getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
- getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
- getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
- getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
- hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
- isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
- isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
- move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
- navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,
- popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
- refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
- reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
- scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
- setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
- setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
- setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
- setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ dragAcceptFiles/2,enable/1,enable/2,findWindow/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,
+ getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,getCursor/1,
+ getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1,
+ getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,
+ getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
+ getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
+ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
+ getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
+ hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
+ initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
+ isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
+ layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
+ move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
+ navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2,
+ popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
+ refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
+ screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
+ setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
+ setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
+ setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
+ setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -121,7 +121,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
This::wxTreebook(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
addPage(This,Page,Text)
- when is_record(This, wx_ref),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_record(Page, wx_ref),?is_chardata(Text) ->
addPage(This,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreebook.html#wxtreebookaddpage">external documentation</a>.
@@ -130,7 +130,7 @@ addPage(This,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
addPage(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_list(Text),is_list(Options) ->
+ when ?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreebook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -327,7 +327,7 @@ hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
This::wxTreebook(), Pos::integer(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
insertPage(This,Pos,Page,Text)
- when is_record(This, wx_ref),is_integer(Pos),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Pos),is_record(Page, wx_ref),?is_chardata(Text) ->
insertPage(This,Pos,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreebook.html#wxtreebookinsertpage">external documentation</a>.
@@ -336,7 +336,7 @@ insertPage(This,Pos,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
insertPage(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_integer(Pos),is_list(Text),is_list(Options) ->
+ when is_integer(Pos),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreebook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -352,7 +352,7 @@ insertPage(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=PageT,ref=PageRef},T
This::wxTreebook(), Pos::integer(), Page::wxWindow:wxWindow(), Text::unicode:chardata().
insertSubPage(This,Pos,Page,Text)
- when is_record(This, wx_ref),is_integer(Pos),is_record(Page, wx_ref),is_list(Text) ->
+ when is_record(This, wx_ref),is_integer(Pos),is_record(Page, wx_ref),?is_chardata(Text) ->
insertSubPage(This,Pos,Page,Text, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtreebook.html#wxtreebookinsertsubpage">external documentation</a>.
@@ -361,7 +361,7 @@ insertSubPage(This,Pos,Page,Text)
Option :: {'bSelect', boolean()}
| {'imageId', integer()}.
insertSubPage(#wx_ref{type=ThisT,ref=ThisRef},Pos,#wx_ref{type=PageT,ref=PageRef},Text, Options)
- when is_integer(Pos),is_list(Text),is_list(Options) ->
+ when is_integer(Pos),?is_chardata(Text),is_list(Options) ->
?CLASS(ThisT,wxTreebook),
?CLASS(PageT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
@@ -403,7 +403,7 @@ setPageImage(#wx_ref{type=ThisT,ref=ThisRef},N,ImageId)
-spec setPageText(This, N, StrText) -> boolean() when
This::wxTreebook(), N::integer(), StrText::unicode:chardata().
setPageText(#wx_ref{type=ThisT,ref=ThisRef},N,StrText)
- when is_integer(N),is_list(StrText) ->
+ when is_integer(N),?is_chardata(StrText) ->
?CLASS(ThisT,wxTreebook),
StrText_UC = unicode:characters_to_binary([StrText,0]),
wxe_util:call(?wxTreebook_SetPageText,
@@ -440,6 +440,8 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label).
getLabel(This) -> wxControl:getLabel(This).
%% From wxWindow
%% @hidden
+getContentScaleFactor(This) -> wxWindow:getContentScaleFactor(This).
+%% @hidden
setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On).
%% @hidden
isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This).
@@ -756,6 +758,8 @@ enable(This, Options) -> wxWindow:enable(This, Options).
%% @hidden
enable(This) -> wxWindow:enable(This).
%% @hidden
+dragAcceptFiles(This,Accept) -> wxWindow:dragAcceptFiles(This,Accept).
+%% @hidden
disable(This) -> wxWindow:disable(This).
%% @hidden
destroyChildren(This) -> wxWindow:destroyChildren(This).
diff --git a/lib/wx/src/gen/wxUpdateUIEvent.erl b/lib/wx/src/gen/wxUpdateUIEvent.erl
index fec42ed8eb..e7bda40a7a 100644
--- a/lib/wx/src/gen/wxUpdateUIEvent.erl
+++ b/lib/wx/src/gen/wxUpdateUIEvent.erl
@@ -181,7 +181,7 @@ setMode(Mode)
-spec setText(This, Text) -> 'ok' when
This::wxUpdateUIEvent(), Text::unicode:chardata().
setText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxUpdateUIEvent),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxUpdateUIEvent_SetText,
diff --git a/lib/wx/src/gen/wxWindow.erl b/lib/wx/src/gen/wxWindow.erl
index 4ac7cc5d75..9ace4533c8 100644
--- a/lib/wx/src/gen/wxWindow.erl
+++ b/lib/wx/src/gen/wxWindow.erl
@@ -32,31 +32,32 @@
center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1,
centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3,
close/1,close/2,convertDialogToPixels/2,convertPixelsToDialog/2,destroy/1,
- destroyChildren/1,disable/1,enable/1,enable/2,findFocus/0,findWindow/2,
- findWindowById/1,findWindowById/2,findWindowByLabel/1,findWindowByLabel/2,
- findWindowByName/1,findWindowByName/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,
- getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCapture/0,
- getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1,
- getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1,
- getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1,
- getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1,
- getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1,
- getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2,
- getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1,
- getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,
- hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1,
- initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,
- isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,
- layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,
- move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,
- navigate/2,new/0,new/2,new/3,pageDown/1,pageUp/1,popEventHandler/1,popEventHandler/2,
- popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,
- refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,
- screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,
- setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,
- setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2,
- setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,
- setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
+ destroyChildren/1,disable/1,dragAcceptFiles/2,enable/1,enable/2,findFocus/0,
+ findWindow/2,findWindowById/1,findWindowById/2,findWindowByLabel/1,
+ findWindowByLabel/2,findWindowByName/1,findWindowByName/2,fit/1,fitInside/1,
+ freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1,
+ getBestSize/1,getCapture/0,getCaret/1,getCharHeight/1,getCharWidth/1,
+ getChildren/1,getClientSize/1,getContainingSizer/1,getContentScaleFactor/1,
+ getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,
+ getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1,
+ getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1,
+ getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2,
+ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,
+ getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,
+ getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,
+ hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,
+ isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,
+ isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,
+ move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,
+ navigate/1,navigate/2,new/0,new/2,new/3,pageDown/1,pageUp/1,popEventHandler/1,
+ popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,
+ refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,
+ reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,
+ scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,
+ setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2,
+ setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2,
+ setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,
+ setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2,
setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,
setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,
setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,
@@ -297,6 +298,15 @@ disable(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_Disable,
<<ThisRef:32/?UI>>).
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowdragacceptfiles">external documentation</a>.
+-spec dragAcceptFiles(This, Accept) -> 'ok' when
+ This::wxWindow(), Accept::boolean().
+dragAcceptFiles(#wx_ref{type=ThisT,ref=ThisRef},Accept)
+ when is_boolean(Accept) ->
+ ?CLASS(ThisT,wxWindow),
+ wxe_util:cast(?wxWindow_DragAcceptFiles,
+ <<ThisRef:32/?UI,(wxe_util:from_bool(Accept)):32/?UI>>).
+
%% @equiv enable(This, [])
-spec enable(This) -> boolean() when
This::wxWindow().
@@ -339,7 +349,7 @@ findWindow(#wx_ref{type=ThisT,ref=ThisRef},Winid)
wxe_util:call(?wxWindow_FindWindow_1_0,
<<ThisRef:32/?UI,Winid:32/?UI>>);
findWindow(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxWindow_FindWindow_1_1,
@@ -370,7 +380,7 @@ findWindowById(Winid, Options)
Name::unicode:chardata().
findWindowByName(Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
findWindowByName(Name, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowfindwindowbyname">external documentation</a>.
@@ -378,7 +388,7 @@ findWindowByName(Name)
Name::unicode:chardata(),
Option :: {'parent', wxWindow()}.
findWindowByName(Name, Options)
- when is_list(Name),is_list(Options) ->
+ when ?is_chardata(Name),is_list(Options) ->
Name_UC = unicode:characters_to_binary([Name,0]),
MOpts = fun({parent, #wx_ref{type=ParentT,ref=ParentRef}}, Acc) -> ?CLASS(ParentT,wxWindow),[<<1:32/?UI,ParentRef:32/?UI>>|Acc];
(BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
@@ -391,7 +401,7 @@ findWindowByName(Name, Options)
Label::unicode:chardata().
findWindowByLabel(Label)
- when is_list(Label) ->
+ when ?is_chardata(Label) ->
findWindowByLabel(Label, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowfindwindowbylabel">external documentation</a>.
@@ -399,7 +409,7 @@ findWindowByLabel(Label)
Label::unicode:chardata(),
Option :: {'parent', wxWindow()}.
findWindowByLabel(Label, Options)
- when is_list(Label),is_list(Options) ->
+ when ?is_chardata(Label),is_list(Options) ->
Label_UC = unicode:characters_to_binary([Label,0]),
MOpts = fun({parent, #wx_ref{type=ParentT,ref=ParentRef}}, Acc) -> ?CLASS(ParentT,wxWindow),[<<1:32/?UI,ParentRef:32/?UI>>|Acc];
(BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
@@ -719,7 +729,7 @@ getSizer(#wx_ref{type=ThisT,ref=ThisRef}) ->
This::wxWindow(), String::unicode:chardata().
getTextExtent(This,String)
- when is_record(This, wx_ref),is_list(String) ->
+ when is_record(This, wx_ref),?is_chardata(String) ->
getTextExtent(This,String, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowgettextextent">external documentation</a>.
@@ -728,7 +738,7 @@ getTextExtent(This,String)
This::wxWindow(), String::unicode:chardata(),
Option :: {'theFont', wxFont:wxFont()}.
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
- when is_list(String),is_list(Options) ->
+ when ?is_chardata(String),is_list(Options) ->
?CLASS(ThisT,wxWindow),
String_UC = unicode:characters_to_binary([String,0]),
MOpts = fun({theFont, #wx_ref{type=TheFontT,ref=TheFontRef}}, Acc) -> ?CLASS(TheFontT,wxFont),[<<1:32/?UI,TheFontRef:32/?UI>>|Acc];
@@ -1439,7 +1449,7 @@ setForegroundColour(#wx_ref{type=ThisT,ref=ThisRef},Colour)
-spec setHelpText(This, Text) -> 'ok' when
This::wxWindow(), Text::unicode:chardata().
setHelpText(#wx_ref{type=ThisT,ref=ThisRef},Text)
- when is_list(Text) ->
+ when ?is_chardata(Text) ->
?CLASS(ThisT,wxWindow),
Text_UC = unicode:characters_to_binary([Text,0]),
wxe_util:cast(?wxWindow_SetHelpText,
@@ -1458,7 +1468,7 @@ setId(#wx_ref{type=ThisT,ref=ThisRef},Winid)
-spec setLabel(This, Label) -> 'ok' when
This::wxWindow(), Label::unicode:chardata().
setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label)
- when is_list(Label) ->
+ when ?is_chardata(Label) ->
?CLASS(ThisT,wxWindow),
Label_UC = unicode:characters_to_binary([Label,0]),
wxe_util:cast(?wxWindow_SetLabel,
@@ -1468,7 +1478,7 @@ setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label)
-spec setName(This, Name) -> 'ok' when
This::wxWindow(), Name::unicode:chardata().
setName(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:cast(?wxWindow_SetName,
@@ -1707,7 +1717,7 @@ setThemeEnabled(#wx_ref{type=ThisT,ref=ThisRef},EnableTheme)
(This, Tip) -> 'ok' when
This::wxWindow(), Tip::wxToolTip:wxToolTip().
setToolTip(#wx_ref{type=ThisT,ref=ThisRef},Tip)
- when is_list(Tip) ->
+ when ?is_chardata(Tip) ->
?CLASS(ThisT,wxWindow),
Tip_UC = unicode:characters_to_binary([Tip,0]),
wxe_util:cast(?wxWindow_SetToolTip_1_0,
@@ -1944,6 +1954,14 @@ setDoubleBuffered(#wx_ref{type=ThisT,ref=ThisRef},On)
wxe_util:cast(?wxWindow_SetDoubleBuffered,
<<ThisRef:32/?UI,(wxe_util:from_bool(On)):32/?UI>>).
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowgetcontentscalefactor">external documentation</a>.
+-spec getContentScaleFactor(This) -> number() when
+ This::wxWindow().
+getContentScaleFactor(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxWindow),
+ wxe_util:call(?wxWindow_GetContentScaleFactor,
+ <<ThisRef:32/?UI>>).
+
%% @doc Destroys this object, do not use object again
-spec destroy(This::wxWindow()) -> 'ok'.
destroy(Obj=#wx_ref{type=Type}) ->
diff --git a/lib/wx/src/gen/wxXmlResource.erl b/lib/wx/src/gen/wxXmlResource.erl
index ae02c74751..51f6231f48 100644
--- a/lib/wx/src/gen/wxXmlResource.erl
+++ b/lib/wx/src/gen/wxXmlResource.erl
@@ -65,7 +65,7 @@ new(Options)
Option :: {'flags', integer()}
| {'domain', unicode:chardata()}.
new(Filemask, Options)
- when is_list(Filemask),is_list(Options) ->
+ when ?is_chardata(Filemask),is_list(Options) ->
Filemask_UC = unicode:characters_to_binary([Filemask,0]),
MOpts = fun({flags, Flags}, Acc) -> [<<1:32/?UI,Flags:32/?UI>>|Acc];
({domain, Domain}, Acc) -> Domain_UC = unicode:characters_to_binary([Domain,0]),[<<2:32/?UI,(byte_size(Domain_UC)):32/?UI,(Domain_UC)/binary, 0:(((8- ((0+byte_size(Domain_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
@@ -79,7 +79,7 @@ new(Filemask, Options)
This::wxXmlResource(), Name::unicode:chardata(), Control::wxWindow:wxWindow().
attachUnknownControl(This,Name,Control)
- when is_record(This, wx_ref),is_list(Name),is_record(Control, wx_ref) ->
+ when is_record(This, wx_ref),?is_chardata(Name),is_record(Control, wx_ref) ->
attachUnknownControl(This,Name,Control, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxxmlresource.html#wxxmlresourceattachunknowncontrol">external documentation</a>.
@@ -87,7 +87,7 @@ attachUnknownControl(This,Name,Control)
This::wxXmlResource(), Name::unicode:chardata(), Control::wxWindow:wxWindow(),
Option :: {'parent', wxWindow:wxWindow()}.
attachUnknownControl(#wx_ref{type=ThisT,ref=ThisRef},Name,#wx_ref{type=ControlT,ref=ControlRef}, Options)
- when is_list(Name),is_list(Options) ->
+ when ?is_chardata(Name),is_list(Options) ->
?CLASS(ThisT,wxXmlResource),
Name_UC = unicode:characters_to_binary([Name,0]),
?CLASS(ControlT,wxWindow),
@@ -169,7 +169,7 @@ initAllHandlers(#wx_ref{type=ThisT,ref=ThisRef}) ->
-spec load(This, Filemask) -> boolean() when
This::wxXmlResource(), Filemask::unicode:chardata().
load(#wx_ref{type=ThisT,ref=ThisRef},Filemask)
- when is_list(Filemask) ->
+ when ?is_chardata(Filemask) ->
?CLASS(ThisT,wxXmlResource),
Filemask_UC = unicode:characters_to_binary([Filemask,0]),
wxe_util:call(?wxXmlResource_Load,
@@ -179,7 +179,7 @@ load(#wx_ref{type=ThisT,ref=ThisRef},Filemask)
-spec loadBitmap(This, Name) -> wxBitmap:wxBitmap() when
This::wxXmlResource(), Name::unicode:chardata().
loadBitmap(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxXmlResource_LoadBitmap,
@@ -189,7 +189,7 @@ loadBitmap(#wx_ref{type=ThisT,ref=ThisRef},Name)
-spec loadDialog(This, Parent, Name) -> wxDialog:wxDialog() when
This::wxXmlResource(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadDialog(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(ParentT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
@@ -200,7 +200,7 @@ loadDialog(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},N
-spec loadDialog(This, Dlg, Parent, Name) -> boolean() when
This::wxXmlResource(), Dlg::wxDialog:wxDialog(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadDialog(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DlgT,ref=DlgRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(DlgT,wxDialog),
?CLASS(ParentT,wxWindow),
@@ -212,7 +212,7 @@ loadDialog(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DlgT,ref=DlgRef},#wx_ref
-spec loadFrame(This, Parent, Name) -> wxFrame:wxFrame() when
This::wxXmlResource(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(ParentT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
@@ -223,7 +223,7 @@ loadFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Na
-spec loadFrame(This, Frame, Parent, Name) -> boolean() when
This::wxXmlResource(), Frame::wxFrame:wxFrame(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FrameT,ref=FrameRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(FrameT,wxFrame),
?CLASS(ParentT,wxWindow),
@@ -235,7 +235,7 @@ loadFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FrameT,ref=FrameRef},#wx_
-spec loadIcon(This, Name) -> wxIcon:wxIcon() when
This::wxXmlResource(), Name::unicode:chardata().
loadIcon(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxXmlResource_LoadIcon,
@@ -245,7 +245,7 @@ loadIcon(#wx_ref{type=ThisT,ref=ThisRef},Name)
-spec loadMenu(This, Name) -> wxMenu:wxMenu() when
This::wxXmlResource(), Name::unicode:chardata().
loadMenu(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxXmlResource_LoadMenu,
@@ -255,7 +255,7 @@ loadMenu(#wx_ref{type=ThisT,ref=ThisRef},Name)
-spec loadMenuBar(This, Name) -> wxMenuBar:wxMenuBar() when
This::wxXmlResource(), Name::unicode:chardata().
loadMenuBar(#wx_ref{type=ThisT,ref=ThisRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
Name_UC = unicode:characters_to_binary([Name,0]),
wxe_util:call(?wxXmlResource_LoadMenuBar_1,
@@ -265,7 +265,7 @@ loadMenuBar(#wx_ref{type=ThisT,ref=ThisRef},Name)
-spec loadMenuBar(This, Parent, Name) -> wxMenuBar:wxMenuBar() when
This::wxXmlResource(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadMenuBar(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(ParentT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
@@ -276,7 +276,7 @@ loadMenuBar(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},
-spec loadPanel(This, Parent, Name) -> wxPanel:wxPanel() when
This::wxXmlResource(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadPanel(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(ParentT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
@@ -287,7 +287,7 @@ loadPanel(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Na
-spec loadPanel(This, Panel, Parent, Name) -> boolean() when
This::wxXmlResource(), Panel::wxPanel:wxPanel(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadPanel(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PanelT,ref=PanelRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(PanelT,wxPanel),
?CLASS(ParentT,wxWindow),
@@ -299,7 +299,7 @@ loadPanel(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PanelT,ref=PanelRef},#wx_
-spec loadToolBar(This, Parent, Name) -> wxToolBar:wxToolBar() when
This::wxXmlResource(), Parent::wxWindow:wxWindow(), Name::unicode:chardata().
loadToolBar(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Name)
- when is_list(Name) ->
+ when ?is_chardata(Name) ->
?CLASS(ThisT,wxXmlResource),
?CLASS(ParentT,wxWindow),
Name_UC = unicode:characters_to_binary([Name,0]),
@@ -327,15 +327,13 @@ setFlags(#wx_ref{type=ThisT,ref=ThisRef},Flags)
-spec unload(This, Filename) -> boolean() when
This::wxXmlResource(), Filename::unicode:chardata().
unload(#wx_ref{type=ThisT,ref=ThisRef},Filename)
- when is_list(Filename) ->
+ when ?is_chardata(Filename) ->
?CLASS(ThisT,wxXmlResource),
Filename_UC = unicode:characters_to_binary([Filename,0]),
wxe_util:call(?wxXmlResource_Unload,
<<ThisRef:32/?UI,(byte_size(Filename_UC)):32/?UI,(Filename_UC)/binary, 0:(((8- ((0+byte_size(Filename_UC)) band 16#7)) band 16#7))/unit:8>>).
-%% @spec (Window::wxWindow:wxWindow(),Name::string(), Type::atom()) -> wx:wxObject()
-
%% @doc Looks up a control with Name in a window created with XML
%% resources. You can use it to set/get values from controls.
%% The object is type casted to <b>Type</b>.
@@ -345,6 +343,10 @@ unload(#wx_ref{type=ThisT,ref=ThisRef},Filename)
%% true = wxXmlResource:loadDialog(Xrc, Dlg, Frame, "controls_dialog"), <br />
%% LCtrl = xrcctrl(Dlg, "controls_listctrl", wxListCtrl), <br />
%% wxListCtrl:insertColumn(LCtrl, 0, "Name", [{width, 200}]), <br />
+-spec xrcctrl(Window, Name, Type) -> wx:wx_object() when
+ Window::wxWindow:wxWindow(),
+ Name::string(),
+ Type::atom().
xrcctrl(Window = #wx_ref{}, Name, Type) when is_list(Name), is_atom(Type) ->
%% Func Id ?wxXmlResource_xrcctrl
diff --git a/lib/wx/src/gen/wx_misc.erl b/lib/wx/src/gen/wx_misc.erl
index ce5d917136..66b1756a2f 100644
--- a/lib/wx/src/gen/wx_misc.erl
+++ b/lib/wx/src/gen/wx_misc.erl
@@ -72,7 +72,7 @@ bell() ->
-spec findMenuItemId(Frame, MenuString, ItemString) -> integer() when
Frame::wxFrame:wxFrame(), MenuString::unicode:chardata(), ItemString::unicode:chardata().
findMenuItemId(#wx_ref{type=FrameT,ref=FrameRef},MenuString,ItemString)
- when is_list(MenuString),is_list(ItemString) ->
+ when ?is_chardata(MenuString),?is_chardata(ItemString) ->
?CLASS(FrameT,wxFrame),
MenuString_UC = unicode:characters_to_binary([MenuString,0]),
ItemString_UC = unicode:characters_to_binary([ItemString,0]),
@@ -155,7 +155,7 @@ shell(Options)
Url::unicode:chardata().
launchDefaultBrowser(Url)
- when is_list(Url) ->
+ when ?is_chardata(Url) ->
launchDefaultBrowser(Url, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_miscellany.html#wxlaunchdefaultbrowser">external documentation</a>.
@@ -163,7 +163,7 @@ launchDefaultBrowser(Url)
Url::unicode:chardata(),
Option :: {'flags', integer()}.
launchDefaultBrowser(Url, Options)
- when is_list(Url),is_list(Options) ->
+ when ?is_chardata(Url),is_list(Options) ->
Url_UC = unicode:characters_to_binary([Url,0]),
MOpts = fun({flags, Flags}, Acc) -> [<<1:32/?UI,Flags:32/?UI>>|Acc];
(BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl
index 78c6577439..58cb5298e6 100644
--- a/lib/wx/src/gen/wxe_debug.hrl
+++ b/lib/wx/src/gen/wxe_debug.hrl
@@ -45,3333 +45,3338 @@ wxdebug_table() ->
{123, {wxWindow, 'Destroy', 0}},
{124, {wxWindow, destroyChildren, 0}},
{125, {wxWindow, disable, 0}},
- {126, {wxWindow, enable, 1}},
- {127, {wxWindow, findFocus, 0}},
- {128, {wxWindow, findWindow_1_0, 1}},
- {129, {wxWindow, findWindow_1_1, 1}},
- {130, {wxWindow, findWindowById, 2}},
- {131, {wxWindow, findWindowByName, 2}},
- {132, {wxWindow, findWindowByLabel, 2}},
- {133, {wxWindow, fit, 0}},
- {134, {wxWindow, fitInside, 0}},
- {135, {wxWindow, freeze, 0}},
- {136, {wxWindow, getAcceleratorTable, 0}},
- {137, {wxWindow, getBackgroundColour, 0}},
- {138, {wxWindow, getBackgroundStyle, 0}},
- {139, {wxWindow, getBestSize, 0}},
- {141, {wxWindow, getCaret, 0}},
- {142, {wxWindow, getCapture, 0}},
- {143, {wxWindow, getCharHeight, 0}},
- {144, {wxWindow, getCharWidth, 0}},
- {145, {wxWindow, getChildren, 0}},
- {148, {wxWindow, getClientSize, 0}},
- {149, {wxWindow, getContainingSizer, 0}},
- {150, {wxWindow, getCursor, 0}},
- {151, {wxWindow, getDropTarget, 0}},
- {152, {wxWindow, getEventHandler, 0}},
- {153, {wxWindow, getExtraStyle, 0}},
- {154, {wxWindow, getFont, 0}},
- {155, {wxWindow, getForegroundColour, 0}},
- {156, {wxWindow, getGrandParent, 0}},
- {157, {wxWindow, getHandle, 0}},
- {158, {wxWindow, getHelpText, 0}},
- {159, {wxWindow, getId, 0}},
- {160, {wxWindow, getLabel, 0}},
- {161, {wxWindow, getMaxSize, 0}},
- {162, {wxWindow, getMinSize, 0}},
- {163, {wxWindow, getName, 0}},
- {164, {wxWindow, getParent, 0}},
- {166, {wxWindow, getPosition, 0}},
- {167, {wxWindow, getRect, 0}},
- {169, {wxWindow, getScreenPosition, 0}},
- {170, {wxWindow, getScreenRect, 0}},
- {171, {wxWindow, getScrollPos, 1}},
- {172, {wxWindow, getScrollRange, 1}},
- {173, {wxWindow, getScrollThumb, 1}},
- {175, {wxWindow, getSize, 0}},
- {176, {wxWindow, getSizer, 0}},
- {177, {wxWindow, getTextExtent, 4}},
- {178, {wxWindow, getToolTip, 0}},
- {179, {wxWindow, getUpdateRegion, 0}},
- {181, {wxWindow, getVirtualSize, 0}},
- {183, {wxWindow, getWindowStyleFlag, 0}},
- {184, {wxWindow, getWindowVariant, 0}},
- {185, {wxWindow, hasCapture, 0}},
- {186, {wxWindow, hasScrollbar, 1}},
- {187, {wxWindow, hasTransparentBackground, 0}},
- {188, {wxWindow, hide, 0}},
- {189, {wxWindow, inheritAttributes, 0}},
- {190, {wxWindow, initDialog, 0}},
- {191, {wxWindow, invalidateBestSize, 0}},
- {192, {wxWindow, isEnabled, 0}},
- {193, {wxWindow, isExposed_2, 2}},
- {194, {wxWindow, isExposed_4, 4}},
- {195, {wxWindow, isExposed_1_0, 1}},
- {196, {wxWindow, isExposed_1_1, 1}},
- {197, {wxWindow, isRetained, 0}},
- {198, {wxWindow, isShown, 0}},
- {199, {wxWindow, isTopLevel, 0}},
- {200, {wxWindow, layout, 0}},
- {201, {wxWindow, lineDown, 0}},
- {202, {wxWindow, lineUp, 0}},
- {203, {wxWindow, lower, 0}},
- {204, {wxWindow, makeModal, 1}},
- {205, {wxWindow, move_3, 3}},
- {206, {wxWindow, move_2, 2}},
- {207, {wxWindow, moveAfterInTabOrder, 1}},
- {208, {wxWindow, moveBeforeInTabOrder, 1}},
- {209, {wxWindow, navigate, 1}},
- {210, {wxWindow, pageDown, 0}},
- {211, {wxWindow, pageUp, 0}},
- {212, {wxWindow, popEventHandler, 1}},
- {213, {wxWindow, popupMenu_2, 2}},
- {214, {wxWindow, popupMenu_3, 3}},
- {215, {wxWindow, raise, 0}},
- {216, {wxWindow, refresh, 1}},
- {217, {wxWindow, refreshRect, 2}},
- {218, {wxWindow, releaseMouse, 0}},
- {219, {wxWindow, removeChild, 1}},
- {220, {wxWindow, reparent, 1}},
- {221, {wxWindow, screenToClient_2, 2}},
- {222, {wxWindow, screenToClient_1, 1}},
- {224, {wxWindow, scrollLines, 1}},
- {226, {wxWindow, scrollPages, 1}},
- {227, {wxWindow, scrollWindow, 3}},
- {228, {wxWindow, setAcceleratorTable, 1}},
- {229, {wxWindow, setAutoLayout, 1}},
- {230, {wxWindow, setBackgroundColour, 1}},
- {231, {wxWindow, setBackgroundStyle, 1}},
- {232, {wxWindow, setCaret, 1}},
- {233, {wxWindow, setClientSize_2, 2}},
- {234, {wxWindow, setClientSize_1_0, 1}},
- {235, {wxWindow, setClientSize_1_1, 1}},
- {236, {wxWindow, setContainingSizer, 1}},
- {237, {wxWindow, setCursor, 1}},
- {238, {wxWindow, setMaxSize, 1}},
- {239, {wxWindow, setMinSize, 1}},
- {240, {wxWindow, setOwnBackgroundColour, 1}},
- {241, {wxWindow, setOwnFont, 1}},
- {242, {wxWindow, setOwnForegroundColour, 1}},
- {243, {wxWindow, setDropTarget, 1}},
- {244, {wxWindow, setExtraStyle, 1}},
- {245, {wxWindow, setFocus, 0}},
- {246, {wxWindow, setFocusFromKbd, 0}},
- {247, {wxWindow, setFont, 1}},
- {248, {wxWindow, setForegroundColour, 1}},
- {249, {wxWindow, setHelpText, 1}},
- {250, {wxWindow, setId, 1}},
- {252, {wxWindow, setLabel, 1}},
- {253, {wxWindow, setName, 1}},
- {254, {wxWindow, setPalette, 1}},
- {255, {wxWindow, setScrollbar, 5}},
- {256, {wxWindow, setScrollPos, 3}},
- {257, {wxWindow, setSize_5, 5}},
- {258, {wxWindow, setSize_2_0, 2}},
- {259, {wxWindow, setSize_1, 1}},
- {260, {wxWindow, setSize_2_1, 2}},
- {261, {wxWindow, setSizeHints_3, 3}},
- {262, {wxWindow, setSizeHints_2, 2}},
- {263, {wxWindow, setSizer, 2}},
- {264, {wxWindow, setSizerAndFit, 2}},
- {265, {wxWindow, setThemeEnabled, 1}},
- {266, {wxWindow, setToolTip_1_0, 1}},
- {267, {wxWindow, setToolTip_1_1, 1}},
- {268, {wxWindow, setVirtualSize_1, 1}},
- {269, {wxWindow, setVirtualSize_2, 2}},
- {270, {wxWindow, setVirtualSizeHints_3, 3}},
- {271, {wxWindow, setVirtualSizeHints_2, 2}},
- {272, {wxWindow, setWindowStyle, 1}},
- {273, {wxWindow, setWindowStyleFlag, 1}},
- {274, {wxWindow, setWindowVariant, 1}},
- {275, {wxWindow, shouldInheritColours, 0}},
- {276, {wxWindow, show, 1}},
- {277, {wxWindow, thaw, 0}},
- {278, {wxWindow, transferDataFromWindow, 0}},
- {279, {wxWindow, transferDataToWindow, 0}},
- {280, {wxWindow, update, 0}},
- {281, {wxWindow, updateWindowUI, 1}},
- {282, {wxWindow, validate, 0}},
- {283, {wxWindow, warpPointer, 2}},
- {284, {wxWindow, setTransparent, 1}},
- {285, {wxWindow, canSetTransparent, 0}},
- {286, {wxWindow, isDoubleBuffered, 0}},
- {287, {wxWindow, setDoubleBuffered, 1}},
- {288, {wxTopLevelWindow, getIcon, 0}},
- {289, {wxTopLevelWindow, getIcons, 0}},
- {290, {wxTopLevelWindow, getTitle, 0}},
- {291, {wxTopLevelWindow, isActive, 0}},
- {292, {wxTopLevelWindow, iconize, 1}},
- {293, {wxTopLevelWindow, isFullScreen, 0}},
- {294, {wxTopLevelWindow, isIconized, 0}},
- {295, {wxTopLevelWindow, isMaximized, 0}},
- {296, {wxTopLevelWindow, maximize, 1}},
- {297, {wxTopLevelWindow, requestUserAttention, 1}},
- {298, {wxTopLevelWindow, setIcon, 1}},
- {299, {wxTopLevelWindow, setIcons, 1}},
- {300, {wxTopLevelWindow, centerOnScreen, 1}},
- {301, {wxTopLevelWindow, centreOnScreen, 1}},
- {303, {wxTopLevelWindow, setShape, 1}},
- {304, {wxTopLevelWindow, setTitle, 1}},
- {305, {wxTopLevelWindow, showFullScreen, 2}},
- {307, {wxFrame, new_4, 4}},
- {308, {wxFrame, new_0, 0}},
- {310, {wxFrame, destruct, 0}},
- {311, {wxFrame, create, 4}},
- {312, {wxFrame, createStatusBar, 1}},
- {313, {wxFrame, createToolBar, 1}},
- {314, {wxFrame, getClientAreaOrigin, 0}},
- {315, {wxFrame, getMenuBar, 0}},
- {316, {wxFrame, getStatusBar, 0}},
- {317, {wxFrame, getStatusBarPane, 0}},
- {318, {wxFrame, getToolBar, 0}},
- {319, {wxFrame, processCommand, 1}},
- {320, {wxFrame, sendSizeEvent, 0}},
- {321, {wxFrame, setMenuBar, 1}},
- {322, {wxFrame, setStatusBar, 1}},
- {323, {wxFrame, setStatusBarPane, 1}},
- {324, {wxFrame, setStatusText, 2}},
- {325, {wxFrame, setStatusWidths, 2}},
- {326, {wxFrame, setToolBar, 1}},
- {327, {wxMiniFrame, new_0, 0}},
- {328, {wxMiniFrame, new_4, 4}},
- {329, {wxMiniFrame, create, 4}},
- {330, {wxMiniFrame, 'Destroy', undefined}},
- {331, {wxSplashScreen, new_0, 0}},
- {332, {wxSplashScreen, new_6, 6}},
- {333, {wxSplashScreen, destruct, 0}},
- {334, {wxSplashScreen, getSplashStyle, 0}},
- {335, {wxSplashScreen, getTimeout, 0}},
- {336, {wxPanel, new_0, 0}},
- {337, {wxPanel, new_6, 6}},
- {338, {wxPanel, new_2, 2}},
- {339, {wxPanel, destruct, 0}},
- {340, {wxPanel, initDialog, 0}},
- {341, {wxPanel, setFocusIgnoringChildren, 0}},
- {342, {wxScrolledWindow, new_0, 0}},
- {343, {wxScrolledWindow, new_2, 2}},
- {344, {wxScrolledWindow, destruct, 0}},
- {345, {wxScrolledWindow, calcScrolledPosition_4, 4}},
- {346, {wxScrolledWindow, calcScrolledPosition_1, 1}},
- {347, {wxScrolledWindow, calcUnscrolledPosition_4, 4}},
- {348, {wxScrolledWindow, calcUnscrolledPosition_1, 1}},
- {349, {wxScrolledWindow, enableScrolling, 2}},
- {350, {wxScrolledWindow, getScrollPixelsPerUnit, 2}},
- {351, {wxScrolledWindow, getViewStart, 2}},
- {352, {wxScrolledWindow, doPrepareDC, 1}},
- {353, {wxScrolledWindow, prepareDC, 1}},
- {354, {wxScrolledWindow, scroll, 2}},
- {355, {wxScrolledWindow, setScrollbars, 5}},
- {356, {wxScrolledWindow, setScrollRate, 2}},
- {357, {wxScrolledWindow, setTargetWindow, 1}},
- {358, {wxSashWindow, new_0, 0}},
- {359, {wxSashWindow, new_2, 2}},
- {360, {wxSashWindow, destruct, 0}},
- {361, {wxSashWindow, getSashVisible, 1}},
- {362, {wxSashWindow, getMaximumSizeX, 0}},
- {363, {wxSashWindow, getMaximumSizeY, 0}},
- {364, {wxSashWindow, getMinimumSizeX, 0}},
- {365, {wxSashWindow, getMinimumSizeY, 0}},
- {366, {wxSashWindow, setMaximumSizeX, 1}},
- {367, {wxSashWindow, setMaximumSizeY, 1}},
- {368, {wxSashWindow, setMinimumSizeX, 1}},
- {369, {wxSashWindow, setMinimumSizeY, 1}},
- {370, {wxSashWindow, setSashVisible, 2}},
- {371, {wxSashLayoutWindow, new_0, 0}},
- {372, {wxSashLayoutWindow, new_2, 2}},
- {373, {wxSashLayoutWindow, create, 2}},
- {374, {wxSashLayoutWindow, getAlignment, 0}},
- {375, {wxSashLayoutWindow, getOrientation, 0}},
- {376, {wxSashLayoutWindow, setAlignment, 1}},
- {377, {wxSashLayoutWindow, setDefaultSize, 1}},
- {378, {wxSashLayoutWindow, setOrientation, 1}},
- {379, {wxSashLayoutWindow, 'Destroy', undefined}},
- {380, {wxGrid, new_0, 0}},
- {381, {wxGrid, new_3, 3}},
- {382, {wxGrid, new_4, 4}},
- {383, {wxGrid, destruct, 0}},
- {384, {wxGrid, appendCols, 1}},
- {385, {wxGrid, appendRows, 1}},
- {386, {wxGrid, autoSize, 0}},
- {387, {wxGrid, autoSizeColumn, 2}},
- {388, {wxGrid, autoSizeColumns, 1}},
- {389, {wxGrid, autoSizeRow, 2}},
- {390, {wxGrid, autoSizeRows, 1}},
- {391, {wxGrid, beginBatch, 0}},
- {392, {wxGrid, blockToDeviceRect, 2}},
- {393, {wxGrid, canDragColSize, 0}},
- {394, {wxGrid, canDragRowSize, 0}},
- {395, {wxGrid, canDragGridSize, 0}},
- {396, {wxGrid, canEnableCellControl, 0}},
- {397, {wxGrid, cellToRect_2, 2}},
- {398, {wxGrid, cellToRect_1, 1}},
- {399, {wxGrid, clearGrid, 0}},
- {400, {wxGrid, clearSelection, 0}},
- {401, {wxGrid, createGrid, 3}},
- {402, {wxGrid, deleteCols, 1}},
- {403, {wxGrid, deleteRows, 1}},
- {404, {wxGrid, disableCellEditControl, 0}},
- {405, {wxGrid, disableDragColSize, 0}},
- {406, {wxGrid, disableDragGridSize, 0}},
- {407, {wxGrid, disableDragRowSize, 0}},
- {408, {wxGrid, enableCellEditControl, 1}},
- {409, {wxGrid, enableDragColSize, 1}},
- {410, {wxGrid, enableDragGridSize, 1}},
- {411, {wxGrid, enableDragRowSize, 1}},
- {412, {wxGrid, enableEditing, 1}},
- {413, {wxGrid, enableGridLines, 1}},
- {414, {wxGrid, endBatch, 0}},
- {415, {wxGrid, fit, 0}},
- {416, {wxGrid, forceRefresh, 0}},
- {417, {wxGrid, getBatchCount, 0}},
- {418, {wxGrid, getCellAlignment, 4}},
- {419, {wxGrid, getCellBackgroundColour, 2}},
- {420, {wxGrid, getCellEditor, 2}},
- {421, {wxGrid, getCellFont, 2}},
- {422, {wxGrid, getCellRenderer, 2}},
- {423, {wxGrid, getCellTextColour, 2}},
- {424, {wxGrid, getCellValue_2, 2}},
- {425, {wxGrid, getCellValue_1, 1}},
- {426, {wxGrid, getColLabelAlignment, 2}},
- {427, {wxGrid, getColLabelSize, 0}},
- {428, {wxGrid, getColLabelValue, 1}},
- {429, {wxGrid, getColMinimalAcceptableWidth, 0}},
- {430, {wxGrid, getDefaultCellAlignment, 2}},
- {431, {wxGrid, getDefaultCellBackgroundColour, 0}},
- {432, {wxGrid, getDefaultCellFont, 0}},
- {433, {wxGrid, getDefaultCellTextColour, 0}},
- {434, {wxGrid, getDefaultColLabelSize, 0}},
- {435, {wxGrid, getDefaultColSize, 0}},
- {436, {wxGrid, getDefaultEditor, 0}},
- {437, {wxGrid, getDefaultEditorForCell_2, 2}},
- {438, {wxGrid, getDefaultEditorForCell_1, 1}},
- {439, {wxGrid, getDefaultEditorForType, 1}},
- {440, {wxGrid, getDefaultRenderer, 0}},
- {441, {wxGrid, getDefaultRendererForCell, 2}},
- {442, {wxGrid, getDefaultRendererForType, 1}},
- {443, {wxGrid, getDefaultRowLabelSize, 0}},
- {444, {wxGrid, getDefaultRowSize, 0}},
- {445, {wxGrid, getGridCursorCol, 0}},
- {446, {wxGrid, getGridCursorRow, 0}},
- {447, {wxGrid, getGridLineColour, 0}},
- {448, {wxGrid, gridLinesEnabled, 0}},
- {449, {wxGrid, getLabelBackgroundColour, 0}},
- {450, {wxGrid, getLabelFont, 0}},
- {451, {wxGrid, getLabelTextColour, 0}},
- {452, {wxGrid, getNumberCols, 0}},
- {453, {wxGrid, getNumberRows, 0}},
- {454, {wxGrid, getOrCreateCellAttr, 2}},
- {455, {wxGrid, getRowMinimalAcceptableHeight, 0}},
- {456, {wxGrid, getRowLabelAlignment, 2}},
- {457, {wxGrid, getRowLabelSize, 0}},
- {458, {wxGrid, getRowLabelValue, 1}},
- {459, {wxGrid, getRowSize, 1}},
- {460, {wxGrid, getScrollLineX, 0}},
- {461, {wxGrid, getScrollLineY, 0}},
- {462, {wxGrid, getSelectedCells, 0}},
- {463, {wxGrid, getSelectedCols, 0}},
- {464, {wxGrid, getSelectedRows, 0}},
- {465, {wxGrid, getSelectionBackground, 0}},
- {466, {wxGrid, getSelectionBlockTopLeft, 0}},
- {467, {wxGrid, getSelectionBlockBottomRight, 0}},
- {468, {wxGrid, getSelectionForeground, 0}},
- {469, {wxGrid, getViewWidth, 0}},
- {470, {wxGrid, getGridWindow, 0}},
- {471, {wxGrid, getGridRowLabelWindow, 0}},
- {472, {wxGrid, getGridColLabelWindow, 0}},
- {473, {wxGrid, getGridCornerLabelWindow, 0}},
- {474, {wxGrid, hideCellEditControl, 0}},
- {475, {wxGrid, insertCols, 1}},
- {476, {wxGrid, insertRows, 1}},
- {477, {wxGrid, isCellEditControlEnabled, 0}},
- {478, {wxGrid, isCurrentCellReadOnly, 0}},
- {479, {wxGrid, isEditable, 0}},
- {480, {wxGrid, isInSelection_2, 2}},
- {481, {wxGrid, isInSelection_1, 1}},
- {482, {wxGrid, isReadOnly, 2}},
- {483, {wxGrid, isSelection, 0}},
- {484, {wxGrid, isVisible_3, 3}},
- {485, {wxGrid, isVisible_2, 2}},
- {486, {wxGrid, makeCellVisible_2, 2}},
- {487, {wxGrid, makeCellVisible_1, 1}},
- {488, {wxGrid, moveCursorDown, 1}},
- {489, {wxGrid, moveCursorLeft, 1}},
- {490, {wxGrid, moveCursorRight, 1}},
- {491, {wxGrid, moveCursorUp, 1}},
- {492, {wxGrid, moveCursorDownBlock, 1}},
- {493, {wxGrid, moveCursorLeftBlock, 1}},
- {494, {wxGrid, moveCursorRightBlock, 1}},
- {495, {wxGrid, moveCursorUpBlock, 1}},
- {496, {wxGrid, movePageDown, 0}},
- {497, {wxGrid, movePageUp, 0}},
- {498, {wxGrid, registerDataType, 3}},
- {499, {wxGrid, saveEditControlValue, 0}},
- {500, {wxGrid, selectAll, 0}},
- {501, {wxGrid, selectBlock_5, 5}},
- {502, {wxGrid, selectBlock_3, 3}},
- {503, {wxGrid, selectCol, 2}},
- {504, {wxGrid, selectRow, 2}},
- {505, {wxGrid, setCellAlignment_4, 4}},
- {506, {wxGrid, setCellAlignment_3, 3}},
- {507, {wxGrid, setCellAlignment_1, 1}},
- {508, {wxGrid, setCellBackgroundColour_3_0, 3}},
- {509, {wxGrid, setCellBackgroundColour_1, 1}},
- {510, {wxGrid, setCellBackgroundColour_3_1, 3}},
- {511, {wxGrid, setCellEditor, 3}},
- {512, {wxGrid, setCellFont, 3}},
- {513, {wxGrid, setCellRenderer, 3}},
- {514, {wxGrid, setCellTextColour_3_0, 3}},
- {515, {wxGrid, setCellTextColour_3_1, 3}},
- {516, {wxGrid, setCellTextColour_1, 1}},
- {517, {wxGrid, setCellValue_3_0, 3}},
- {518, {wxGrid, setCellValue_2, 2}},
- {519, {wxGrid, setCellValue_3_1, 3}},
- {520, {wxGrid, setColAttr, 2}},
- {521, {wxGrid, setColFormatBool, 1}},
- {522, {wxGrid, setColFormatNumber, 1}},
- {523, {wxGrid, setColFormatFloat, 2}},
- {524, {wxGrid, setColFormatCustom, 2}},
- {525, {wxGrid, setColLabelAlignment, 2}},
- {526, {wxGrid, setColLabelSize, 1}},
- {527, {wxGrid, setColLabelValue, 2}},
- {528, {wxGrid, setColMinimalWidth, 2}},
- {529, {wxGrid, setColMinimalAcceptableWidth, 1}},
- {530, {wxGrid, setColSize, 2}},
- {531, {wxGrid, setDefaultCellAlignment, 2}},
- {532, {wxGrid, setDefaultCellBackgroundColour, 1}},
- {533, {wxGrid, setDefaultCellFont, 1}},
- {534, {wxGrid, setDefaultCellTextColour, 1}},
- {535, {wxGrid, setDefaultEditor, 1}},
- {536, {wxGrid, setDefaultRenderer, 1}},
- {537, {wxGrid, setDefaultColSize, 2}},
- {538, {wxGrid, setDefaultRowSize, 2}},
- {539, {wxGrid, setGridCursor, 2}},
- {540, {wxGrid, setGridLineColour, 1}},
- {541, {wxGrid, setLabelBackgroundColour, 1}},
- {542, {wxGrid, setLabelFont, 1}},
- {543, {wxGrid, setLabelTextColour, 1}},
- {544, {wxGrid, setMargins, 2}},
- {545, {wxGrid, setReadOnly, 3}},
- {546, {wxGrid, setRowAttr, 2}},
- {547, {wxGrid, setRowLabelAlignment, 2}},
- {548, {wxGrid, setRowLabelSize, 1}},
- {549, {wxGrid, setRowLabelValue, 2}},
- {550, {wxGrid, setRowMinimalHeight, 2}},
- {551, {wxGrid, setRowMinimalAcceptableHeight, 1}},
- {552, {wxGrid, setRowSize, 2}},
- {553, {wxGrid, setScrollLineX, 1}},
- {554, {wxGrid, setScrollLineY, 1}},
- {555, {wxGrid, setSelectionBackground, 1}},
- {556, {wxGrid, setSelectionForeground, 1}},
- {557, {wxGrid, setSelectionMode, 1}},
- {558, {wxGrid, showCellEditControl, 0}},
- {559, {wxGrid, xToCol, 2}},
- {560, {wxGrid, xToEdgeOfCol, 1}},
- {561, {wxGrid, yToEdgeOfRow, 1}},
- {562, {wxGrid, yToRow, 1}},
- {563, {wxGridCellRenderer, draw, 7}},
- {564, {wxGridCellRenderer, getBestSize, 5}},
- {565, {wxGridCellEditor, create, 3}},
- {566, {wxGridCellEditor, isCreated, 0}},
- {567, {wxGridCellEditor, setSize, 1}},
- {568, {wxGridCellEditor, show, 2}},
- {569, {wxGridCellEditor, paintBackground, 2}},
- {570, {wxGridCellEditor, beginEdit, 3}},
- {571, {wxGridCellEditor, endEdit, 3}},
- {572, {wxGridCellEditor, reset, 0}},
- {573, {wxGridCellEditor, startingKey, 1}},
- {574, {wxGridCellEditor, startingClick, 0}},
- {575, {wxGridCellEditor, handleReturn, 1}},
- {576, {wxGridCellBoolRenderer, new, 0}},
- {577, {wxGridCellBoolRenderer, 'Destroy', undefined}},
- {578, {wxGridCellBoolEditor, new, 0}},
- {579, {wxGridCellBoolEditor, isTrueValue, 1}},
- {580, {wxGridCellBoolEditor, useStringValues, 1}},
- {581, {wxGridCellBoolEditor, 'Destroy', undefined}},
- {582, {wxGridCellFloatRenderer, new, 1}},
- {583, {wxGridCellFloatRenderer, getPrecision, 0}},
- {584, {wxGridCellFloatRenderer, getWidth, 0}},
- {585, {wxGridCellFloatRenderer, setParameters, 1}},
- {586, {wxGridCellFloatRenderer, setPrecision, 1}},
- {587, {wxGridCellFloatRenderer, setWidth, 1}},
- {588, {wxGridCellFloatRenderer, 'Destroy', undefined}},
- {589, {wxGridCellFloatEditor, new, 1}},
- {590, {wxGridCellFloatEditor, setParameters, 1}},
- {591, {wxGridCellFloatEditor, 'Destroy', undefined}},
- {592, {wxGridCellStringRenderer, new, 0}},
- {593, {wxGridCellStringRenderer, 'Destroy', undefined}},
- {594, {wxGridCellTextEditor, new, 0}},
- {595, {wxGridCellTextEditor, setParameters, 1}},
- {596, {wxGridCellTextEditor, 'Destroy', undefined}},
- {598, {wxGridCellChoiceEditor, new, 2}},
- {599, {wxGridCellChoiceEditor, setParameters, 1}},
- {600, {wxGridCellChoiceEditor, 'Destroy', undefined}},
- {601, {wxGridCellNumberRenderer, new, 0}},
- {602, {wxGridCellNumberRenderer, 'Destroy', undefined}},
- {603, {wxGridCellNumberEditor, new, 1}},
- {604, {wxGridCellNumberEditor, getValue, 0}},
- {605, {wxGridCellNumberEditor, setParameters, 1}},
- {606, {wxGridCellNumberEditor, 'Destroy', undefined}},
- {607, {wxGridCellAttr, setTextColour, 1}},
- {608, {wxGridCellAttr, setBackgroundColour, 1}},
- {609, {wxGridCellAttr, setFont, 1}},
- {610, {wxGridCellAttr, setAlignment, 2}},
- {611, {wxGridCellAttr, setReadOnly, 1}},
- {612, {wxGridCellAttr, setRenderer, 1}},
- {613, {wxGridCellAttr, setEditor, 1}},
- {614, {wxGridCellAttr, hasTextColour, 0}},
- {615, {wxGridCellAttr, hasBackgroundColour, 0}},
- {616, {wxGridCellAttr, hasFont, 0}},
- {617, {wxGridCellAttr, hasAlignment, 0}},
- {618, {wxGridCellAttr, hasRenderer, 0}},
- {619, {wxGridCellAttr, hasEditor, 0}},
- {620, {wxGridCellAttr, getTextColour, 0}},
- {621, {wxGridCellAttr, getBackgroundColour, 0}},
- {622, {wxGridCellAttr, getFont, 0}},
- {623, {wxGridCellAttr, getAlignment, 2}},
- {624, {wxGridCellAttr, getRenderer, 3}},
- {625, {wxGridCellAttr, getEditor, 3}},
- {626, {wxGridCellAttr, isReadOnly, 0}},
- {627, {wxGridCellAttr, setDefAttr, 1}},
- {628, {wxDC, blit, 5}},
- {629, {wxDC, calcBoundingBox, 2}},
- {630, {wxDC, clear, 0}},
- {631, {wxDC, computeScaleAndOrigin, 0}},
- {632, {wxDC, crossHair, 1}},
- {633, {wxDC, destroyClippingRegion, 0}},
- {634, {wxDC, deviceToLogicalX, 1}},
- {635, {wxDC, deviceToLogicalXRel, 1}},
- {636, {wxDC, deviceToLogicalY, 1}},
- {637, {wxDC, deviceToLogicalYRel, 1}},
- {638, {wxDC, drawArc, 3}},
- {639, {wxDC, drawBitmap, 3}},
- {640, {wxDC, drawCheckMark, 1}},
- {641, {wxDC, drawCircle, 2}},
- {643, {wxDC, drawEllipse_2, 2}},
- {644, {wxDC, drawEllipse_1, 1}},
- {645, {wxDC, drawEllipticArc, 4}},
- {646, {wxDC, drawIcon, 2}},
- {647, {wxDC, drawLabel, 3}},
- {648, {wxDC, drawLine, 2}},
- {649, {wxDC, drawLines, 3}},
- {651, {wxDC, drawPolygon, 3}},
- {653, {wxDC, drawPoint, 1}},
- {655, {wxDC, drawRectangle_2, 2}},
- {656, {wxDC, drawRectangle_1, 1}},
- {657, {wxDC, drawRotatedText, 3}},
- {659, {wxDC, drawRoundedRectangle_3, 3}},
- {660, {wxDC, drawRoundedRectangle_2, 2}},
- {661, {wxDC, drawText, 2}},
- {662, {wxDC, endDoc, 0}},
- {663, {wxDC, endPage, 0}},
- {664, {wxDC, floodFill, 3}},
- {665, {wxDC, getBackground, 0}},
- {666, {wxDC, getBackgroundMode, 0}},
- {667, {wxDC, getBrush, 0}},
- {668, {wxDC, getCharHeight, 0}},
- {669, {wxDC, getCharWidth, 0}},
- {670, {wxDC, getClippingBox, 4}},
- {672, {wxDC, getFont, 0}},
- {673, {wxDC, getLayoutDirection, 0}},
- {674, {wxDC, getLogicalFunction, 0}},
- {675, {wxDC, getMapMode, 0}},
- {676, {wxDC, getMultiLineTextExtent_4, 4}},
- {677, {wxDC, getMultiLineTextExtent_1, 1}},
- {678, {wxDC, getPartialTextExtents, 2}},
- {679, {wxDC, getPen, 0}},
- {680, {wxDC, getPixel, 2}},
- {681, {wxDC, getPPI, 0}},
- {683, {wxDC, getSize, 0}},
- {685, {wxDC, getSizeMM, 0}},
- {686, {wxDC, getTextBackground, 0}},
- {687, {wxDC, getTextExtent_4, 4}},
- {688, {wxDC, getTextExtent_1, 1}},
- {690, {wxDC, getTextForeground, 0}},
- {691, {wxDC, getUserScale, 2}},
- {692, {wxDC, gradientFillConcentric_3, 3}},
- {693, {wxDC, gradientFillConcentric_4, 4}},
- {694, {wxDC, gradientFillLinear, 4}},
- {695, {wxDC, logicalToDeviceX, 1}},
- {696, {wxDC, logicalToDeviceXRel, 1}},
- {697, {wxDC, logicalToDeviceY, 1}},
- {698, {wxDC, logicalToDeviceYRel, 1}},
- {699, {wxDC, maxX, 0}},
- {700, {wxDC, maxY, 0}},
- {701, {wxDC, minX, 0}},
- {702, {wxDC, minY, 0}},
- {703, {wxDC, isOk, 0}},
- {704, {wxDC, resetBoundingBox, 0}},
- {705, {wxDC, setAxisOrientation, 2}},
- {706, {wxDC, setBackground, 1}},
- {707, {wxDC, setBackgroundMode, 1}},
- {708, {wxDC, setBrush, 1}},
- {710, {wxDC, setClippingRegion_2, 2}},
- {711, {wxDC, setClippingRegion_1_1, 1}},
- {712, {wxDC, setClippingRegion_1_0, 1}},
- {713, {wxDC, setDeviceOrigin, 2}},
- {714, {wxDC, setFont, 1}},
- {715, {wxDC, setLayoutDirection, 1}},
- {716, {wxDC, setLogicalFunction, 1}},
- {717, {wxDC, setMapMode, 1}},
- {718, {wxDC, setPalette, 1}},
- {719, {wxDC, setPen, 1}},
- {720, {wxDC, setTextBackground, 1}},
- {721, {wxDC, setTextForeground, 1}},
- {722, {wxDC, setUserScale, 2}},
- {723, {wxDC, startDoc, 1}},
- {724, {wxDC, startPage, 0}},
- {725, {wxMirrorDC, new, 2}},
- {726, {wxMirrorDC, 'Destroy', undefined}},
- {727, {wxScreenDC, new, 0}},
- {728, {wxScreenDC, destruct, 0}},
- {729, {wxPostScriptDC, new_0, 0}},
- {730, {wxPostScriptDC, new_1, 1}},
- {731, {wxPostScriptDC, destruct, 0}},
- {732, {wxPostScriptDC, setResolution, 1}},
- {733, {wxPostScriptDC, getResolution, 0}},
- {734, {wxWindowDC, new_0, 0}},
- {735, {wxWindowDC, new_1, 1}},
- {736, {wxWindowDC, destruct, 0}},
- {737, {wxClientDC, new_0, 0}},
- {738, {wxClientDC, new_1, 1}},
- {739, {wxClientDC, 'Destroy', undefined}},
- {740, {wxPaintDC, new_0, 0}},
- {741, {wxPaintDC, new_1, 1}},
- {742, {wxPaintDC, 'Destroy', undefined}},
- {744, {wxMemoryDC, new_1_0, 1}},
- {745, {wxMemoryDC, new_1_1, 1}},
- {746, {wxMemoryDC, new_0, 0}},
- {748, {wxMemoryDC, destruct, 0}},
- {749, {wxMemoryDC, selectObject, 1}},
- {750, {wxMemoryDC, selectObjectAsSource, 1}},
- {751, {wxBufferedDC, new_0, 0}},
- {752, {wxBufferedDC, new_2, 2}},
- {753, {wxBufferedDC, new_3, 3}},
- {754, {wxBufferedDC, destruct, 0}},
- {755, {wxBufferedDC, init_2, 2}},
- {756, {wxBufferedDC, init_3, 3}},
- {757, {wxBufferedPaintDC, new_3, 3}},
- {758, {wxBufferedPaintDC, new_2, 2}},
- {759, {wxBufferedPaintDC, destruct, 0}},
- {760, {wxGraphicsObject, destruct, 0}},
- {761, {wxGraphicsObject, getRenderer, 0}},
- {762, {wxGraphicsObject, isNull, 0}},
- {763, {wxGraphicsContext, destruct, 0}},
- {764, {wxGraphicsContext, create_1_1, 1}},
- {765, {wxGraphicsContext, create_1_0, 1}},
- {766, {wxGraphicsContext, create_0, 0}},
- {767, {wxGraphicsContext, createPen, 1}},
- {768, {wxGraphicsContext, createBrush, 1}},
- {769, {wxGraphicsContext, createRadialGradientBrush, 7}},
- {770, {wxGraphicsContext, createLinearGradientBrush, 6}},
- {771, {wxGraphicsContext, createFont, 2}},
- {772, {wxGraphicsContext, createMatrix, 1}},
- {773, {wxGraphicsContext, createPath, 0}},
- {774, {wxGraphicsContext, clip_1, 1}},
- {775, {wxGraphicsContext, clip_4, 4}},
- {776, {wxGraphicsContext, resetClip, 0}},
- {777, {wxGraphicsContext, drawBitmap, 5}},
- {778, {wxGraphicsContext, drawEllipse, 4}},
- {779, {wxGraphicsContext, drawIcon, 5}},
- {780, {wxGraphicsContext, drawLines, 3}},
- {781, {wxGraphicsContext, drawPath, 2}},
- {782, {wxGraphicsContext, drawRectangle, 4}},
- {783, {wxGraphicsContext, drawRoundedRectangle, 5}},
- {784, {wxGraphicsContext, drawText_3, 3}},
- {785, {wxGraphicsContext, drawText_4_0, 4}},
- {786, {wxGraphicsContext, drawText_4_1, 4}},
- {787, {wxGraphicsContext, drawText_5, 5}},
- {788, {wxGraphicsContext, fillPath, 2}},
- {789, {wxGraphicsContext, strokePath, 1}},
- {790, {wxGraphicsContext, getPartialTextExtents, 2}},
- {791, {wxGraphicsContext, getTextExtent, 5}},
- {792, {wxGraphicsContext, rotate, 1}},
- {793, {wxGraphicsContext, scale, 2}},
- {794, {wxGraphicsContext, translate, 2}},
- {795, {wxGraphicsContext, getTransform, 0}},
- {796, {wxGraphicsContext, setTransform, 1}},
- {797, {wxGraphicsContext, concatTransform, 1}},
- {798, {wxGraphicsContext, setBrush_1_1, 1}},
- {799, {wxGraphicsContext, setBrush_1_0, 1}},
- {800, {wxGraphicsContext, setFont_1, 1}},
- {801, {wxGraphicsContext, setFont_2, 2}},
- {802, {wxGraphicsContext, setPen_1_0, 1}},
- {803, {wxGraphicsContext, setPen_1_1, 1}},
- {804, {wxGraphicsContext, strokeLine, 4}},
- {805, {wxGraphicsContext, strokeLines, 2}},
- {807, {wxGraphicsMatrix, concat, 1}},
- {809, {wxGraphicsMatrix, get, 1}},
- {810, {wxGraphicsMatrix, invert, 0}},
- {811, {wxGraphicsMatrix, isEqual, 1}},
- {813, {wxGraphicsMatrix, isIdentity, 0}},
- {814, {wxGraphicsMatrix, rotate, 1}},
- {815, {wxGraphicsMatrix, scale, 2}},
- {816, {wxGraphicsMatrix, translate, 2}},
- {817, {wxGraphicsMatrix, set, 1}},
- {818, {wxGraphicsMatrix, transformPoint, 2}},
- {819, {wxGraphicsMatrix, transformDistance, 2}},
- {820, {wxGraphicsPath, moveToPoint_2, 2}},
- {821, {wxGraphicsPath, moveToPoint_1, 1}},
- {822, {wxGraphicsPath, addArc_6, 6}},
- {823, {wxGraphicsPath, addArc_5, 5}},
- {824, {wxGraphicsPath, addArcToPoint, 5}},
- {825, {wxGraphicsPath, addCircle, 3}},
- {826, {wxGraphicsPath, addCurveToPoint_6, 6}},
- {827, {wxGraphicsPath, addCurveToPoint_3, 3}},
- {828, {wxGraphicsPath, addEllipse, 4}},
- {829, {wxGraphicsPath, addLineToPoint_2, 2}},
- {830, {wxGraphicsPath, addLineToPoint_1, 1}},
- {831, {wxGraphicsPath, addPath, 1}},
- {832, {wxGraphicsPath, addQuadCurveToPoint, 4}},
- {833, {wxGraphicsPath, addRectangle, 4}},
- {834, {wxGraphicsPath, addRoundedRectangle, 5}},
- {835, {wxGraphicsPath, closeSubpath, 0}},
- {836, {wxGraphicsPath, contains_3, 3}},
- {837, {wxGraphicsPath, contains_2, 2}},
- {839, {wxGraphicsPath, getBox, 0}},
- {841, {wxGraphicsPath, getCurrentPoint, 0}},
- {842, {wxGraphicsPath, transform, 1}},
- {843, {wxGraphicsRenderer, getDefaultRenderer, 0}},
- {844, {wxGraphicsRenderer, createContext_1_1, 1}},
- {845, {wxGraphicsRenderer, createContext_1_0, 1}},
- {846, {wxGraphicsRenderer, createPen, 1}},
- {847, {wxGraphicsRenderer, createBrush, 1}},
- {848, {wxGraphicsRenderer, createLinearGradientBrush, 6}},
- {849, {wxGraphicsRenderer, createRadialGradientBrush, 7}},
- {850, {wxGraphicsRenderer, createFont, 2}},
- {851, {wxGraphicsRenderer, createMatrix, 1}},
- {852, {wxGraphicsRenderer, createPath, 0}},
- {854, {wxMenuBar, new_1, 1}},
- {856, {wxMenuBar, new_0, 0}},
- {858, {wxMenuBar, destruct, 0}},
- {859, {wxMenuBar, append, 2}},
- {860, {wxMenuBar, check, 2}},
- {861, {wxMenuBar, enable_2, 2}},
- {862, {wxMenuBar, enable_1, 1}},
- {863, {wxMenuBar, enableTop, 2}},
- {864, {wxMenuBar, findMenu, 1}},
- {865, {wxMenuBar, findMenuItem, 2}},
- {866, {wxMenuBar, findItem, 2}},
- {867, {wxMenuBar, getHelpString, 1}},
- {868, {wxMenuBar, getLabel_1, 1}},
- {869, {wxMenuBar, getLabel_0, 0}},
- {870, {wxMenuBar, getLabelTop, 1}},
- {871, {wxMenuBar, getMenu, 1}},
- {872, {wxMenuBar, getMenuCount, 0}},
- {873, {wxMenuBar, insert, 3}},
- {874, {wxMenuBar, isChecked, 1}},
- {875, {wxMenuBar, isEnabled_1, 1}},
- {876, {wxMenuBar, isEnabled_0, 0}},
- {877, {wxMenuBar, remove, 1}},
- {878, {wxMenuBar, replace, 3}},
- {879, {wxMenuBar, setHelpString, 2}},
- {880, {wxMenuBar, setLabel_2, 2}},
- {881, {wxMenuBar, setLabel_1, 1}},
- {882, {wxMenuBar, setLabelTop, 2}},
- {883, {wxControl, getLabel, 0}},
- {884, {wxControl, setLabel, 1}},
- {885, {wxControlWithItems, append_1, 1}},
- {886, {wxControlWithItems, append_2, 2}},
- {887, {wxControlWithItems, appendStrings_1, 1}},
- {888, {wxControlWithItems, clear, 0}},
- {889, {wxControlWithItems, delete, 1}},
- {890, {wxControlWithItems, findString, 2}},
- {891, {wxControlWithItems, getClientData, 1}},
- {892, {wxControlWithItems, setClientData, 2}},
- {893, {wxControlWithItems, getCount, 0}},
- {894, {wxControlWithItems, getSelection, 0}},
- {895, {wxControlWithItems, getString, 1}},
- {896, {wxControlWithItems, getStringSelection, 0}},
- {897, {wxControlWithItems, insert_2, 2}},
- {898, {wxControlWithItems, insert_3, 3}},
- {899, {wxControlWithItems, isEmpty, 0}},
- {900, {wxControlWithItems, select, 1}},
- {901, {wxControlWithItems, setSelection, 1}},
- {902, {wxControlWithItems, setString, 2}},
- {903, {wxControlWithItems, setStringSelection, 1}},
- {906, {wxMenu, new_2, 2}},
- {907, {wxMenu, new_1, 1}},
- {909, {wxMenu, destruct, 0}},
- {910, {wxMenu, append_3, 3}},
- {911, {wxMenu, append_1, 1}},
- {912, {wxMenu, append_4_0, 4}},
- {913, {wxMenu, append_4_1, 4}},
- {914, {wxMenu, appendCheckItem, 3}},
- {915, {wxMenu, appendRadioItem, 3}},
- {916, {wxMenu, appendSeparator, 0}},
- {917, {wxMenu, break, 0}},
- {918, {wxMenu, check, 2}},
- {919, {wxMenu, delete_1_0, 1}},
- {920, {wxMenu, delete_1_1, 1}},
- {921, {wxMenu, destroy_1_0, 1}},
- {922, {wxMenu, destroy_1_1, 1}},
- {923, {wxMenu, enable, 2}},
- {924, {wxMenu, findItem_1, 1}},
- {925, {wxMenu, findItem_2, 2}},
- {926, {wxMenu, findItemByPosition, 1}},
- {927, {wxMenu, getHelpString, 1}},
- {928, {wxMenu, getLabel, 1}},
- {929, {wxMenu, getMenuItemCount, 0}},
- {930, {wxMenu, getMenuItems, 0}},
- {932, {wxMenu, getTitle, 0}},
- {933, {wxMenu, insert_2, 2}},
- {934, {wxMenu, insert_3, 3}},
- {935, {wxMenu, insert_5_1, 5}},
- {936, {wxMenu, insert_5_0, 5}},
- {937, {wxMenu, insertCheckItem, 4}},
- {938, {wxMenu, insertRadioItem, 4}},
- {939, {wxMenu, insertSeparator, 1}},
- {940, {wxMenu, isChecked, 1}},
- {941, {wxMenu, isEnabled, 1}},
- {942, {wxMenu, prepend_1, 1}},
- {943, {wxMenu, prepend_2, 2}},
- {944, {wxMenu, prepend_4_1, 4}},
- {945, {wxMenu, prepend_4_0, 4}},
- {946, {wxMenu, prependCheckItem, 3}},
- {947, {wxMenu, prependRadioItem, 3}},
- {948, {wxMenu, prependSeparator, 0}},
- {949, {wxMenu, remove_1_0, 1}},
- {950, {wxMenu, remove_1_1, 1}},
- {951, {wxMenu, setHelpString, 2}},
- {952, {wxMenu, setLabel, 2}},
- {953, {wxMenu, setTitle, 1}},
- {954, {wxMenuItem, new, 1}},
- {956, {wxMenuItem, destruct, 0}},
- {957, {wxMenuItem, check, 1}},
- {958, {wxMenuItem, enable, 1}},
- {959, {wxMenuItem, getBitmap, 0}},
- {960, {wxMenuItem, getHelp, 0}},
- {961, {wxMenuItem, getId, 0}},
- {962, {wxMenuItem, getKind, 0}},
- {963, {wxMenuItem, getLabel, 0}},
- {964, {wxMenuItem, getLabelFromText, 1}},
- {965, {wxMenuItem, getMenu, 0}},
- {966, {wxMenuItem, getText, 0}},
- {967, {wxMenuItem, getSubMenu, 0}},
- {968, {wxMenuItem, isCheckable, 0}},
- {969, {wxMenuItem, isChecked, 0}},
- {970, {wxMenuItem, isEnabled, 0}},
- {971, {wxMenuItem, isSeparator, 0}},
- {972, {wxMenuItem, isSubMenu, 0}},
- {973, {wxMenuItem, setBitmap, 1}},
- {974, {wxMenuItem, setHelp, 1}},
- {975, {wxMenuItem, setMenu, 1}},
- {976, {wxMenuItem, setSubMenu, 1}},
- {977, {wxMenuItem, setText, 1}},
- {978, {wxToolBar, addControl, 1}},
- {979, {wxToolBar, addSeparator, 0}},
- {980, {wxToolBar, addTool_5, 5}},
- {981, {wxToolBar, addTool_4_0, 4}},
- {982, {wxToolBar, addTool_1, 1}},
- {983, {wxToolBar, addTool_4_1, 4}},
- {984, {wxToolBar, addTool_3, 3}},
- {985, {wxToolBar, addTool_6, 6}},
- {986, {wxToolBar, addCheckTool, 4}},
- {987, {wxToolBar, addRadioTool, 4}},
- {988, {wxToolBar, addStretchableSpace, 0}},
- {989, {wxToolBar, insertStretchableSpace, 1}},
- {990, {wxToolBar, deleteTool, 1}},
- {991, {wxToolBar, deleteToolByPos, 1}},
- {992, {wxToolBar, enableTool, 2}},
- {993, {wxToolBar, findById, 1}},
- {994, {wxToolBar, findControl, 1}},
- {995, {wxToolBar, findToolForPosition, 2}},
- {996, {wxToolBar, getToolSize, 0}},
- {997, {wxToolBar, getToolBitmapSize, 0}},
- {998, {wxToolBar, getMargins, 0}},
- {999, {wxToolBar, getToolEnabled, 1}},
- {1000, {wxToolBar, getToolLongHelp, 1}},
- {1001, {wxToolBar, getToolPacking, 0}},
- {1002, {wxToolBar, getToolPos, 1}},
- {1003, {wxToolBar, getToolSeparation, 0}},
- {1004, {wxToolBar, getToolShortHelp, 1}},
- {1005, {wxToolBar, getToolState, 1}},
- {1006, {wxToolBar, insertControl, 2}},
- {1007, {wxToolBar, insertSeparator, 1}},
- {1008, {wxToolBar, insertTool_5, 5}},
- {1009, {wxToolBar, insertTool_2, 2}},
- {1010, {wxToolBar, insertTool_4, 4}},
- {1011, {wxToolBar, realize, 0}},
- {1012, {wxToolBar, removeTool, 1}},
- {1013, {wxToolBar, setMargins, 2}},
- {1014, {wxToolBar, setToolBitmapSize, 1}},
- {1015, {wxToolBar, setToolLongHelp, 2}},
- {1016, {wxToolBar, setToolPacking, 1}},
- {1017, {wxToolBar, setToolShortHelp, 2}},
- {1018, {wxToolBar, setToolSeparation, 1}},
- {1019, {wxToolBar, toggleTool, 2}},
- {1021, {wxStatusBar, new_0, 0}},
- {1022, {wxStatusBar, new_2, 2}},
- {1024, {wxStatusBar, destruct, 0}},
- {1025, {wxStatusBar, create, 2}},
- {1026, {wxStatusBar, getFieldRect, 2}},
- {1027, {wxStatusBar, getFieldsCount, 0}},
- {1028, {wxStatusBar, getStatusText, 1}},
- {1029, {wxStatusBar, popStatusText, 1}},
- {1030, {wxStatusBar, pushStatusText, 2}},
- {1031, {wxStatusBar, setFieldsCount, 2}},
- {1032, {wxStatusBar, setMinHeight, 1}},
- {1033, {wxStatusBar, setStatusText, 2}},
- {1034, {wxStatusBar, setStatusWidths, 2}},
- {1035, {wxStatusBar, setStatusStyles, 2}},
- {1036, {wxBitmap, new_0, 0}},
- {1037, {wxBitmap, new_3, 3}},
- {1038, {wxBitmap, new_4, 4}},
- {1039, {wxBitmap, new_2_0, 2}},
- {1040, {wxBitmap, new_2_1, 2}},
- {1041, {wxBitmap, destruct, 0}},
- {1042, {wxBitmap, convertToImage, 0}},
- {1043, {wxBitmap, copyFromIcon, 1}},
- {1044, {wxBitmap, create, 3}},
- {1045, {wxBitmap, getDepth, 0}},
- {1046, {wxBitmap, getHeight, 0}},
- {1047, {wxBitmap, getPalette, 0}},
- {1048, {wxBitmap, getMask, 0}},
- {1049, {wxBitmap, getWidth, 0}},
- {1050, {wxBitmap, getSubBitmap, 1}},
- {1051, {wxBitmap, loadFile, 2}},
- {1052, {wxBitmap, ok, 0}},
- {1053, {wxBitmap, saveFile, 3}},
- {1054, {wxBitmap, setDepth, 1}},
- {1055, {wxBitmap, setHeight, 1}},
- {1056, {wxBitmap, setMask, 1}},
- {1057, {wxBitmap, setPalette, 1}},
- {1058, {wxBitmap, setWidth, 1}},
- {1059, {wxIcon, new_0, 0}},
- {1060, {wxIcon, new_2, 2}},
- {1061, {wxIcon, new_1, 1}},
- {1062, {wxIcon, copyFromBitmap, 1}},
- {1063, {wxIcon, 'Destroy', undefined}},
- {1064, {wxIconBundle, new_0, 0}},
- {1065, {wxIconBundle, new_2, 2}},
- {1066, {wxIconBundle, new_1_0, 1}},
- {1067, {wxIconBundle, new_1_1, 1}},
- {1068, {wxIconBundle, destruct, 0}},
- {1069, {wxIconBundle, addIcon_2, 2}},
- {1070, {wxIconBundle, addIcon_1, 1}},
- {1071, {wxIconBundle, getIcon_1_1, 1}},
- {1072, {wxIconBundle, getIcon_1_0, 1}},
- {1073, {wxCursor, new_0, 0}},
- {1074, {wxCursor, new_1_0, 1}},
- {1075, {wxCursor, new_1_1, 1}},
- {1076, {wxCursor, new_4, 4}},
- {1077, {wxCursor, destruct, 0}},
- {1078, {wxCursor, ok, 0}},
- {1079, {wxMask, new_0, 0}},
- {1080, {wxMask, new_2_1, 2}},
- {1081, {wxMask, new_2_0, 2}},
- {1082, {wxMask, new_1, 1}},
- {1083, {wxMask, destruct, 0}},
- {1084, {wxMask, create_2_1, 2}},
- {1085, {wxMask, create_2_0, 2}},
- {1086, {wxMask, create_1, 1}},
- {1087, {wxImage, new_0, 0}},
- {1088, {wxImage, new_3_0, 3}},
- {1089, {wxImage, new_4, 4}},
- {1090, {wxImage, new_5, 5}},
- {1091, {wxImage, new_2, 2}},
- {1092, {wxImage, new_3_1, 3}},
- {1093, {wxImage, blur, 1}},
- {1094, {wxImage, blurHorizontal, 1}},
- {1095, {wxImage, blurVertical, 1}},
- {1096, {wxImage, convertAlphaToMask, 1}},
- {1097, {wxImage, convertToGreyscale, 1}},
- {1098, {wxImage, convertToMono, 3}},
- {1099, {wxImage, copy, 0}},
- {1100, {wxImage, create_3, 3}},
- {1101, {wxImage, create_4, 4}},
- {1102, {wxImage, create_5, 5}},
- {1103, {wxImage, 'Destroy', 0}},
- {1104, {wxImage, findFirstUnusedColour, 4}},
- {1105, {wxImage, getImageExtWildcard, 0}},
- {1106, {wxImage, getAlpha_2, 2}},
- {1107, {wxImage, getAlpha_0, 0}},
- {1108, {wxImage, getBlue, 2}},
- {1109, {wxImage, getData, 0}},
- {1110, {wxImage, getGreen, 2}},
- {1111, {wxImage, getImageCount, 2}},
- {1112, {wxImage, getHeight, 0}},
- {1113, {wxImage, getMaskBlue, 0}},
- {1114, {wxImage, getMaskGreen, 0}},
- {1115, {wxImage, getMaskRed, 0}},
- {1116, {wxImage, getOrFindMaskColour, 3}},
- {1117, {wxImage, getPalette, 0}},
- {1118, {wxImage, getRed, 2}},
- {1119, {wxImage, getSubImage, 1}},
- {1120, {wxImage, getWidth, 0}},
- {1121, {wxImage, hasAlpha, 0}},
- {1122, {wxImage, hasMask, 0}},
- {1123, {wxImage, getOption, 1}},
- {1124, {wxImage, getOptionInt, 1}},
- {1125, {wxImage, hasOption, 1}},
- {1126, {wxImage, initAlpha, 0}},
- {1127, {wxImage, initStandardHandlers, 0}},
- {1128, {wxImage, isTransparent, 3}},
- {1129, {wxImage, loadFile_2, 2}},
- {1130, {wxImage, loadFile_3, 3}},
- {1131, {wxImage, ok, 0}},
- {1132, {wxImage, removeHandler, 1}},
- {1133, {wxImage, mirror, 1}},
- {1134, {wxImage, replace, 6}},
- {1135, {wxImage, rescale, 3}},
- {1136, {wxImage, resize, 3}},
- {1137, {wxImage, rotate, 3}},
- {1138, {wxImage, rotateHue, 1}},
- {1139, {wxImage, rotate90, 1}},
- {1140, {wxImage, saveFile_1, 1}},
- {1141, {wxImage, saveFile_2_0, 2}},
- {1142, {wxImage, saveFile_2_1, 2}},
- {1143, {wxImage, scale, 3}},
- {1144, {wxImage, size, 3}},
- {1145, {wxImage, setAlpha_3, 3}},
- {1146, {wxImage, setAlpha_2, 2}},
- {1147, {wxImage, setData_2, 2}},
- {1148, {wxImage, setData_4, 4}},
- {1149, {wxImage, setMask, 1}},
- {1150, {wxImage, setMaskColour, 3}},
- {1151, {wxImage, setMaskFromImage, 4}},
- {1152, {wxImage, setOption_2_1, 2}},
- {1153, {wxImage, setOption_2_0, 2}},
- {1154, {wxImage, setPalette, 1}},
- {1155, {wxImage, setRGB_5, 5}},
- {1156, {wxImage, setRGB_4, 4}},
- {1157, {wxImage, 'Destroy', undefined}},
- {1158, {wxBrush, new_0, 0}},
- {1159, {wxBrush, new_2, 2}},
- {1160, {wxBrush, new_1, 1}},
- {1162, {wxBrush, destruct, 0}},
- {1163, {wxBrush, getColour, 0}},
- {1164, {wxBrush, getStipple, 0}},
- {1165, {wxBrush, getStyle, 0}},
- {1166, {wxBrush, isHatch, 0}},
- {1167, {wxBrush, isOk, 0}},
- {1168, {wxBrush, setColour_1, 1}},
- {1169, {wxBrush, setColour_3, 3}},
- {1170, {wxBrush, setStipple, 1}},
- {1171, {wxBrush, setStyle, 1}},
- {1172, {wxPen, new_0, 0}},
- {1173, {wxPen, new_2, 2}},
- {1174, {wxPen, destruct, 0}},
- {1175, {wxPen, getCap, 0}},
- {1176, {wxPen, getColour, 0}},
- {1177, {wxPen, getJoin, 0}},
- {1178, {wxPen, getStyle, 0}},
- {1179, {wxPen, getWidth, 0}},
- {1180, {wxPen, isOk, 0}},
- {1181, {wxPen, setCap, 1}},
- {1182, {wxPen, setColour_1, 1}},
- {1183, {wxPen, setColour_3, 3}},
- {1184, {wxPen, setJoin, 1}},
- {1185, {wxPen, setStyle, 1}},
- {1186, {wxPen, setWidth, 1}},
- {1187, {wxRegion, new_0, 0}},
- {1188, {wxRegion, new_4, 4}},
- {1189, {wxRegion, new_2, 2}},
- {1190, {wxRegion, new_1_1, 1}},
- {1192, {wxRegion, new_1_0, 1}},
- {1194, {wxRegion, destruct, 0}},
- {1195, {wxRegion, clear, 0}},
- {1196, {wxRegion, contains_2, 2}},
- {1197, {wxRegion, contains_1_0, 1}},
- {1198, {wxRegion, contains_4, 4}},
- {1199, {wxRegion, contains_1_1, 1}},
- {1200, {wxRegion, convertToBitmap, 0}},
- {1201, {wxRegion, getBox, 0}},
- {1202, {wxRegion, intersect_4, 4}},
- {1203, {wxRegion, intersect_1_1, 1}},
- {1204, {wxRegion, intersect_1_0, 1}},
- {1205, {wxRegion, isEmpty, 0}},
- {1206, {wxRegion, subtract_4, 4}},
- {1207, {wxRegion, subtract_1_1, 1}},
- {1208, {wxRegion, subtract_1_0, 1}},
- {1209, {wxRegion, offset_2, 2}},
- {1210, {wxRegion, offset_1, 1}},
- {1211, {wxRegion, union_4, 4}},
- {1212, {wxRegion, union_1_2, 1}},
- {1213, {wxRegion, union_1_1, 1}},
- {1214, {wxRegion, union_1_0, 1}},
- {1215, {wxRegion, union_3, 3}},
- {1216, {wxRegion, xor_4, 4}},
- {1217, {wxRegion, xor_1_1, 1}},
- {1218, {wxRegion, xor_1_0, 1}},
- {1219, {wxAcceleratorTable, new_0, 0}},
- {1220, {wxAcceleratorTable, new_2, 2}},
- {1221, {wxAcceleratorTable, destruct, 0}},
- {1222, {wxAcceleratorTable, ok, 0}},
- {1223, {wxAcceleratorEntry, new_1_0, 1}},
- {1224, {wxAcceleratorEntry, new_1_1, 1}},
- {1225, {wxAcceleratorEntry, getCommand, 0}},
- {1226, {wxAcceleratorEntry, getFlags, 0}},
- {1227, {wxAcceleratorEntry, getKeyCode, 0}},
- {1228, {wxAcceleratorEntry, set, 4}},
- {1229, {wxAcceleratorEntry, 'Destroy', undefined}},
- {1234, {wxCaret, new_3, 3}},
- {1235, {wxCaret, new_2, 2}},
- {1237, {wxCaret, destruct, 0}},
- {1238, {wxCaret, create_3, 3}},
- {1239, {wxCaret, create_2, 2}},
- {1240, {wxCaret, getBlinkTime, 0}},
- {1242, {wxCaret, getPosition, 0}},
- {1244, {wxCaret, getSize, 0}},
- {1245, {wxCaret, getWindow, 0}},
- {1246, {wxCaret, hide, 0}},
- {1247, {wxCaret, isOk, 0}},
- {1248, {wxCaret, isVisible, 0}},
- {1249, {wxCaret, move_2, 2}},
- {1250, {wxCaret, move_1, 1}},
- {1251, {wxCaret, setBlinkTime, 1}},
- {1252, {wxCaret, setSize_2, 2}},
- {1253, {wxCaret, setSize_1, 1}},
- {1254, {wxCaret, show, 1}},
- {1255, {wxSizer, add_2_1, 2}},
- {1256, {wxSizer, add_2_0, 2}},
- {1257, {wxSizer, add_3, 3}},
- {1258, {wxSizer, add_2_3, 2}},
- {1259, {wxSizer, add_2_2, 2}},
- {1260, {wxSizer, addSpacer, 1}},
- {1261, {wxSizer, addStretchSpacer, 1}},
- {1262, {wxSizer, calcMin, 0}},
- {1263, {wxSizer, clear, 1}},
- {1264, {wxSizer, detach_1_2, 1}},
- {1265, {wxSizer, detach_1_1, 1}},
- {1266, {wxSizer, detach_1_0, 1}},
- {1267, {wxSizer, fit, 1}},
- {1268, {wxSizer, fitInside, 1}},
- {1269, {wxSizer, getChildren, 0}},
- {1270, {wxSizer, getItem_2_1, 2}},
- {1271, {wxSizer, getItem_2_0, 2}},
- {1272, {wxSizer, getItem_1, 1}},
- {1273, {wxSizer, getSize, 0}},
- {1274, {wxSizer, getPosition, 0}},
- {1275, {wxSizer, getMinSize, 0}},
- {1276, {wxSizer, hide_2_0, 2}},
- {1277, {wxSizer, hide_2_1, 2}},
- {1278, {wxSizer, hide_1, 1}},
- {1279, {wxSizer, insert_3_1, 3}},
- {1280, {wxSizer, insert_3_0, 3}},
- {1281, {wxSizer, insert_4, 4}},
- {1282, {wxSizer, insert_3_3, 3}},
- {1283, {wxSizer, insert_3_2, 3}},
- {1284, {wxSizer, insert_2, 2}},
- {1285, {wxSizer, insertSpacer, 2}},
- {1286, {wxSizer, insertStretchSpacer, 2}},
- {1287, {wxSizer, isShown_1_2, 1}},
- {1288, {wxSizer, isShown_1_1, 1}},
- {1289, {wxSizer, isShown_1_0, 1}},
- {1290, {wxSizer, layout, 0}},
- {1291, {wxSizer, prepend_2_1, 2}},
- {1292, {wxSizer, prepend_2_0, 2}},
- {1293, {wxSizer, prepend_3, 3}},
- {1294, {wxSizer, prepend_2_3, 2}},
- {1295, {wxSizer, prepend_2_2, 2}},
- {1296, {wxSizer, prepend_1, 1}},
- {1297, {wxSizer, prependSpacer, 1}},
- {1298, {wxSizer, prependStretchSpacer, 1}},
- {1299, {wxSizer, recalcSizes, 0}},
- {1300, {wxSizer, remove_1_1, 1}},
- {1301, {wxSizer, remove_1_0, 1}},
- {1302, {wxSizer, replace_3_1, 3}},
- {1303, {wxSizer, replace_3_0, 3}},
- {1304, {wxSizer, replace_2, 2}},
- {1305, {wxSizer, setDimension, 4}},
- {1306, {wxSizer, setMinSize_2, 2}},
- {1307, {wxSizer, setMinSize_1, 1}},
- {1308, {wxSizer, setItemMinSize_3_2, 3}},
- {1309, {wxSizer, setItemMinSize_2_2, 2}},
- {1310, {wxSizer, setItemMinSize_3_1, 3}},
- {1311, {wxSizer, setItemMinSize_2_1, 2}},
- {1312, {wxSizer, setItemMinSize_3_0, 3}},
- {1313, {wxSizer, setItemMinSize_2_0, 2}},
- {1314, {wxSizer, setSizeHints, 1}},
- {1315, {wxSizer, setVirtualSizeHints, 1}},
- {1316, {wxSizer, show_2_2, 2}},
- {1317, {wxSizer, show_2_1, 2}},
- {1318, {wxSizer, show_2_0, 2}},
- {1319, {wxSizer, show_1, 1}},
- {1320, {wxSizerFlags, new, 1}},
- {1321, {wxSizerFlags, align, 1}},
- {1322, {wxSizerFlags, border_2, 2}},
- {1323, {wxSizerFlags, border_1, 1}},
- {1324, {wxSizerFlags, center, 0}},
- {1325, {wxSizerFlags, centre, 0}},
- {1326, {wxSizerFlags, expand, 0}},
- {1327, {wxSizerFlags, left, 0}},
- {1328, {wxSizerFlags, proportion, 1}},
- {1329, {wxSizerFlags, right, 0}},
- {1330, {wxSizerFlags, 'Destroy', undefined}},
- {1331, {wxSizerItem, new_5_1, 5}},
- {1332, {wxSizerItem, new_2_1, 2}},
- {1333, {wxSizerItem, new_5_0, 5}},
- {1334, {wxSizerItem, new_2_0, 2}},
- {1335, {wxSizerItem, new_6, 6}},
- {1336, {wxSizerItem, new_3, 3}},
- {1337, {wxSizerItem, new_0, 0}},
- {1338, {wxSizerItem, destruct, 0}},
- {1339, {wxSizerItem, calcMin, 0}},
- {1340, {wxSizerItem, deleteWindows, 0}},
- {1341, {wxSizerItem, detachSizer, 0}},
- {1342, {wxSizerItem, getBorder, 0}},
- {1343, {wxSizerItem, getFlag, 0}},
- {1344, {wxSizerItem, getMinSize, 0}},
- {1345, {wxSizerItem, getPosition, 0}},
- {1346, {wxSizerItem, getProportion, 0}},
- {1347, {wxSizerItem, getRatio, 0}},
- {1348, {wxSizerItem, getRect, 0}},
- {1349, {wxSizerItem, getSize, 0}},
- {1350, {wxSizerItem, getSizer, 0}},
- {1351, {wxSizerItem, getSpacer, 0}},
- {1352, {wxSizerItem, getUserData, 0}},
- {1353, {wxSizerItem, getWindow, 0}},
- {1354, {wxSizerItem, isSizer, 0}},
- {1355, {wxSizerItem, isShown, 0}},
- {1356, {wxSizerItem, isSpacer, 0}},
- {1357, {wxSizerItem, isWindow, 0}},
- {1358, {wxSizerItem, setBorder, 1}},
- {1359, {wxSizerItem, setDimension, 2}},
- {1360, {wxSizerItem, setFlag, 1}},
- {1361, {wxSizerItem, setInitSize, 2}},
- {1362, {wxSizerItem, setMinSize_1, 1}},
- {1363, {wxSizerItem, setMinSize_2, 2}},
- {1364, {wxSizerItem, setProportion, 1}},
- {1365, {wxSizerItem, setRatio_2, 2}},
- {1366, {wxSizerItem, setRatio_1_1, 1}},
- {1367, {wxSizerItem, setRatio_1_0, 1}},
- {1368, {wxSizerItem, setSizer, 1}},
- {1369, {wxSizerItem, setSpacer_1, 1}},
- {1370, {wxSizerItem, setSpacer_2, 2}},
- {1371, {wxSizerItem, setWindow, 1}},
- {1372, {wxSizerItem, show, 1}},
- {1373, {wxBoxSizer, new, 1}},
- {1374, {wxBoxSizer, getOrientation, 0}},
- {1375, {wxBoxSizer, 'Destroy', undefined}},
- {1376, {wxStaticBoxSizer, new_2, 2}},
- {1377, {wxStaticBoxSizer, new_3, 3}},
- {1378, {wxStaticBoxSizer, getStaticBox, 0}},
- {1379, {wxStaticBoxSizer, 'Destroy', undefined}},
- {1380, {wxGridSizer, new_4, 4}},
- {1381, {wxGridSizer, new_2, 2}},
- {1382, {wxGridSizer, getCols, 0}},
- {1383, {wxGridSizer, getHGap, 0}},
- {1384, {wxGridSizer, getRows, 0}},
- {1385, {wxGridSizer, getVGap, 0}},
- {1386, {wxGridSizer, setCols, 1}},
- {1387, {wxGridSizer, setHGap, 1}},
- {1388, {wxGridSizer, setRows, 1}},
- {1389, {wxGridSizer, setVGap, 1}},
- {1390, {wxGridSizer, 'Destroy', undefined}},
- {1391, {wxFlexGridSizer, new_4, 4}},
- {1392, {wxFlexGridSizer, new_2, 2}},
- {1393, {wxFlexGridSizer, addGrowableCol, 2}},
- {1394, {wxFlexGridSizer, addGrowableRow, 2}},
- {1395, {wxFlexGridSizer, getFlexibleDirection, 0}},
- {1396, {wxFlexGridSizer, getNonFlexibleGrowMode, 0}},
- {1397, {wxFlexGridSizer, removeGrowableCol, 1}},
- {1398, {wxFlexGridSizer, removeGrowableRow, 1}},
- {1399, {wxFlexGridSizer, setFlexibleDirection, 1}},
- {1400, {wxFlexGridSizer, setNonFlexibleGrowMode, 1}},
- {1401, {wxFlexGridSizer, 'Destroy', undefined}},
- {1402, {wxGridBagSizer, new, 1}},
- {1403, {wxGridBagSizer, add_3_2, 3}},
- {1404, {wxGridBagSizer, add_3_1, 3}},
- {1405, {wxGridBagSizer, add_4, 4}},
- {1406, {wxGridBagSizer, add_1_0, 1}},
- {1407, {wxGridBagSizer, add_2_1, 2}},
- {1408, {wxGridBagSizer, add_2_0, 2}},
- {1409, {wxGridBagSizer, add_3_0, 3}},
- {1410, {wxGridBagSizer, add_1_1, 1}},
- {1411, {wxGridBagSizer, calcMin, 0}},
- {1412, {wxGridBagSizer, checkForIntersection_2, 2}},
- {1413, {wxGridBagSizer, checkForIntersection_3, 3}},
- {1414, {wxGridBagSizer, findItem_1_1, 1}},
- {1415, {wxGridBagSizer, findItem_1_0, 1}},
- {1416, {wxGridBagSizer, findItemAtPoint, 1}},
- {1417, {wxGridBagSizer, findItemAtPosition, 1}},
- {1418, {wxGridBagSizer, findItemWithData, 1}},
- {1419, {wxGridBagSizer, getCellSize, 2}},
- {1420, {wxGridBagSizer, getEmptyCellSize, 0}},
- {1421, {wxGridBagSizer, getItemPosition_1_2, 1}},
- {1422, {wxGridBagSizer, getItemPosition_1_1, 1}},
- {1423, {wxGridBagSizer, getItemPosition_1_0, 1}},
- {1424, {wxGridBagSizer, getItemSpan_1_2, 1}},
- {1425, {wxGridBagSizer, getItemSpan_1_1, 1}},
- {1426, {wxGridBagSizer, getItemSpan_1_0, 1}},
- {1427, {wxGridBagSizer, setEmptyCellSize, 1}},
- {1428, {wxGridBagSizer, setItemPosition_2_2, 2}},
- {1429, {wxGridBagSizer, setItemPosition_2_1, 2}},
- {1430, {wxGridBagSizer, setItemPosition_2_0, 2}},
- {1431, {wxGridBagSizer, setItemSpan_2_2, 2}},
- {1432, {wxGridBagSizer, setItemSpan_2_1, 2}},
- {1433, {wxGridBagSizer, setItemSpan_2_0, 2}},
- {1434, {wxGridBagSizer, 'Destroy', undefined}},
- {1435, {wxStdDialogButtonSizer, new, 0}},
- {1436, {wxStdDialogButtonSizer, addButton, 1}},
- {1437, {wxStdDialogButtonSizer, realize, 0}},
- {1438, {wxStdDialogButtonSizer, setAffirmativeButton, 1}},
- {1439, {wxStdDialogButtonSizer, setCancelButton, 1}},
- {1440, {wxStdDialogButtonSizer, setNegativeButton, 1}},
- {1441, {wxStdDialogButtonSizer, 'Destroy', undefined}},
- {1442, {wxFont, new_0, 0}},
- {1443, {wxFont, new_1, 1}},
- {1444, {wxFont, new_5, 5}},
- {1446, {wxFont, destruct, 0}},
- {1447, {wxFont, isFixedWidth, 0}},
- {1448, {wxFont, getDefaultEncoding, 0}},
- {1449, {wxFont, getFaceName, 0}},
- {1450, {wxFont, getFamily, 0}},
- {1451, {wxFont, getNativeFontInfoDesc, 0}},
- {1452, {wxFont, getNativeFontInfoUserDesc, 0}},
- {1453, {wxFont, getPointSize, 0}},
- {1454, {wxFont, getStyle, 0}},
- {1455, {wxFont, getUnderlined, 0}},
- {1456, {wxFont, getWeight, 0}},
- {1457, {wxFont, ok, 0}},
- {1458, {wxFont, setDefaultEncoding, 1}},
- {1459, {wxFont, setFaceName, 1}},
- {1460, {wxFont, setFamily, 1}},
- {1461, {wxFont, setPointSize, 1}},
- {1462, {wxFont, setStyle, 1}},
- {1463, {wxFont, setUnderlined, 1}},
- {1464, {wxFont, setWeight, 1}},
- {1465, {wxToolTip, enable, 1}},
- {1466, {wxToolTip, setDelay, 1}},
- {1467, {wxToolTip, new, 1}},
- {1468, {wxToolTip, setTip, 1}},
- {1469, {wxToolTip, getTip, 0}},
- {1470, {wxToolTip, getWindow, 0}},
- {1471, {wxToolTip, 'Destroy', undefined}},
- {1473, {wxButton, new_3, 3}},
- {1474, {wxButton, new_0, 0}},
- {1475, {wxButton, destruct, 0}},
- {1476, {wxButton, create, 3}},
- {1477, {wxButton, getDefaultSize, 0}},
- {1478, {wxButton, setDefault, 0}},
- {1479, {wxButton, setLabel, 1}},
- {1481, {wxBitmapButton, new_4, 4}},
- {1482, {wxBitmapButton, new_0, 0}},
- {1483, {wxBitmapButton, create, 4}},
- {1484, {wxBitmapButton, getBitmapDisabled, 0}},
- {1486, {wxBitmapButton, getBitmapFocus, 0}},
- {1488, {wxBitmapButton, getBitmapLabel, 0}},
- {1490, {wxBitmapButton, getBitmapSelected, 0}},
- {1492, {wxBitmapButton, setBitmapDisabled, 1}},
- {1493, {wxBitmapButton, setBitmapFocus, 1}},
- {1494, {wxBitmapButton, setBitmapLabel, 1}},
- {1495, {wxBitmapButton, setBitmapSelected, 1}},
- {1496, {wxBitmapButton, 'Destroy', undefined}},
- {1497, {wxToggleButton, new_0, 0}},
- {1498, {wxToggleButton, new_4, 4}},
- {1499, {wxToggleButton, create, 4}},
- {1500, {wxToggleButton, getValue, 0}},
- {1501, {wxToggleButton, setValue, 1}},
- {1502, {wxToggleButton, 'Destroy', undefined}},
- {1503, {wxCalendarCtrl, new_0, 0}},
- {1504, {wxCalendarCtrl, new_3, 3}},
- {1505, {wxCalendarCtrl, create, 3}},
- {1506, {wxCalendarCtrl, destruct, 0}},
- {1507, {wxCalendarCtrl, setDate, 1}},
- {1508, {wxCalendarCtrl, getDate, 0}},
- {1509, {wxCalendarCtrl, enableYearChange, 1}},
- {1510, {wxCalendarCtrl, enableMonthChange, 1}},
- {1511, {wxCalendarCtrl, enableHolidayDisplay, 1}},
- {1512, {wxCalendarCtrl, setHeaderColours, 2}},
- {1513, {wxCalendarCtrl, getHeaderColourFg, 0}},
- {1514, {wxCalendarCtrl, getHeaderColourBg, 0}},
- {1515, {wxCalendarCtrl, setHighlightColours, 2}},
- {1516, {wxCalendarCtrl, getHighlightColourFg, 0}},
- {1517, {wxCalendarCtrl, getHighlightColourBg, 0}},
- {1518, {wxCalendarCtrl, setHolidayColours, 2}},
- {1519, {wxCalendarCtrl, getHolidayColourFg, 0}},
- {1520, {wxCalendarCtrl, getHolidayColourBg, 0}},
- {1521, {wxCalendarCtrl, getAttr, 1}},
- {1522, {wxCalendarCtrl, setAttr, 2}},
- {1523, {wxCalendarCtrl, setHoliday, 1}},
- {1524, {wxCalendarCtrl, resetAttr, 1}},
- {1525, {wxCalendarCtrl, hitTest, 2}},
- {1526, {wxCalendarDateAttr, new_0, 0}},
- {1527, {wxCalendarDateAttr, new_2_1, 2}},
- {1528, {wxCalendarDateAttr, new_2_0, 2}},
- {1529, {wxCalendarDateAttr, setTextColour, 1}},
- {1530, {wxCalendarDateAttr, setBackgroundColour, 1}},
- {1531, {wxCalendarDateAttr, setBorderColour, 1}},
- {1532, {wxCalendarDateAttr, setFont, 1}},
- {1533, {wxCalendarDateAttr, setBorder, 1}},
- {1534, {wxCalendarDateAttr, setHoliday, 1}},
- {1535, {wxCalendarDateAttr, hasTextColour, 0}},
- {1536, {wxCalendarDateAttr, hasBackgroundColour, 0}},
- {1537, {wxCalendarDateAttr, hasBorderColour, 0}},
- {1538, {wxCalendarDateAttr, hasFont, 0}},
- {1539, {wxCalendarDateAttr, hasBorder, 0}},
- {1540, {wxCalendarDateAttr, isHoliday, 0}},
- {1541, {wxCalendarDateAttr, getTextColour, 0}},
- {1542, {wxCalendarDateAttr, getBackgroundColour, 0}},
- {1543, {wxCalendarDateAttr, getBorderColour, 0}},
- {1544, {wxCalendarDateAttr, getFont, 0}},
- {1545, {wxCalendarDateAttr, getBorder, 0}},
- {1546, {wxCalendarDateAttr, 'Destroy', undefined}},
- {1548, {wxCheckBox, new_4, 4}},
- {1549, {wxCheckBox, new_0, 0}},
- {1550, {wxCheckBox, create, 4}},
- {1551, {wxCheckBox, getValue, 0}},
- {1552, {wxCheckBox, get3StateValue, 0}},
- {1553, {wxCheckBox, is3rdStateAllowedForUser, 0}},
- {1554, {wxCheckBox, is3State, 0}},
- {1555, {wxCheckBox, isChecked, 0}},
- {1556, {wxCheckBox, setValue, 1}},
- {1557, {wxCheckBox, set3StateValue, 1}},
- {1558, {wxCheckBox, 'Destroy', undefined}},
- {1559, {wxCheckListBox, new_0, 0}},
- {1561, {wxCheckListBox, new_3, 3}},
- {1562, {wxCheckListBox, check, 2}},
- {1563, {wxCheckListBox, isChecked, 1}},
- {1564, {wxCheckListBox, 'Destroy', undefined}},
- {1567, {wxChoice, new_3, 3}},
- {1568, {wxChoice, new_0, 0}},
- {1570, {wxChoice, destruct, 0}},
- {1572, {wxChoice, create, 6}},
- {1573, {wxChoice, delete, 1}},
- {1574, {wxChoice, getColumns, 0}},
- {1575, {wxChoice, setColumns, 1}},
- {1576, {wxComboBox, new_0, 0}},
- {1578, {wxComboBox, new_3, 3}},
- {1579, {wxComboBox, destruct, 0}},
- {1581, {wxComboBox, create, 7}},
- {1582, {wxComboBox, canCopy, 0}},
- {1583, {wxComboBox, canCut, 0}},
- {1584, {wxComboBox, canPaste, 0}},
- {1585, {wxComboBox, canRedo, 0}},
- {1586, {wxComboBox, canUndo, 0}},
- {1587, {wxComboBox, copy, 0}},
- {1588, {wxComboBox, cut, 0}},
- {1589, {wxComboBox, getInsertionPoint, 0}},
- {1590, {wxComboBox, getLastPosition, 0}},
- {1591, {wxComboBox, getValue, 0}},
- {1592, {wxComboBox, paste, 0}},
- {1593, {wxComboBox, redo, 0}},
- {1594, {wxComboBox, replace, 3}},
- {1595, {wxComboBox, remove, 2}},
- {1596, {wxComboBox, setInsertionPoint, 1}},
- {1597, {wxComboBox, setInsertionPointEnd, 0}},
- {1598, {wxComboBox, setSelection_1, 1}},
- {1599, {wxComboBox, setSelection_2, 2}},
- {1600, {wxComboBox, setValue, 1}},
- {1601, {wxComboBox, undo, 0}},
- {1602, {wxGauge, new_0, 0}},
- {1603, {wxGauge, new_4, 4}},
- {1604, {wxGauge, create, 4}},
- {1605, {wxGauge, getRange, 0}},
- {1606, {wxGauge, getValue, 0}},
- {1607, {wxGauge, isVertical, 0}},
- {1608, {wxGauge, setRange, 1}},
- {1609, {wxGauge, setValue, 1}},
- {1610, {wxGauge, pulse, 0}},
- {1611, {wxGauge, 'Destroy', undefined}},
- {1612, {wxGenericDirCtrl, new_0, 0}},
- {1613, {wxGenericDirCtrl, new_2, 2}},
- {1614, {wxGenericDirCtrl, destruct, 0}},
- {1615, {wxGenericDirCtrl, create, 2}},
- {1616, {wxGenericDirCtrl, init, 0}},
- {1617, {wxGenericDirCtrl, collapseTree, 0}},
- {1618, {wxGenericDirCtrl, expandPath, 1}},
- {1619, {wxGenericDirCtrl, getDefaultPath, 0}},
- {1620, {wxGenericDirCtrl, getPath, 0}},
- {1621, {wxGenericDirCtrl, getFilePath, 0}},
- {1622, {wxGenericDirCtrl, getFilter, 0}},
- {1623, {wxGenericDirCtrl, getFilterIndex, 0}},
- {1624, {wxGenericDirCtrl, getRootId, 0}},
- {1625, {wxGenericDirCtrl, getTreeCtrl, 0}},
- {1626, {wxGenericDirCtrl, reCreateTree, 0}},
- {1627, {wxGenericDirCtrl, setDefaultPath, 1}},
- {1628, {wxGenericDirCtrl, setFilter, 1}},
- {1629, {wxGenericDirCtrl, setFilterIndex, 1}},
- {1630, {wxGenericDirCtrl, setPath, 1}},
- {1632, {wxStaticBox, new_4, 4}},
- {1633, {wxStaticBox, new_0, 0}},
- {1634, {wxStaticBox, create, 4}},
- {1635, {wxStaticBox, 'Destroy', undefined}},
- {1637, {wxStaticLine, new_2, 2}},
- {1638, {wxStaticLine, new_0, 0}},
- {1639, {wxStaticLine, create, 2}},
- {1640, {wxStaticLine, isVertical, 0}},
- {1641, {wxStaticLine, getDefaultSize, 0}},
- {1642, {wxStaticLine, 'Destroy', undefined}},
- {1645, {wxListBox, new_3, 3}},
- {1646, {wxListBox, new_0, 0}},
- {1648, {wxListBox, destruct, 0}},
- {1650, {wxListBox, create, 6}},
- {1651, {wxListBox, deselect, 1}},
- {1652, {wxListBox, getSelections, 1}},
- {1653, {wxListBox, insertItems, 2}},
- {1654, {wxListBox, isSelected, 1}},
- {1655, {wxListBox, set, 1}},
- {1656, {wxListBox, hitTest, 1}},
- {1657, {wxListBox, setFirstItem_1_0, 1}},
- {1658, {wxListBox, setFirstItem_1_1, 1}},
- {1659, {wxListCtrl, new_0, 0}},
- {1660, {wxListCtrl, new_2, 2}},
- {1661, {wxListCtrl, arrange, 1}},
- {1662, {wxListCtrl, assignImageList, 2}},
- {1663, {wxListCtrl, clearAll, 0}},
- {1664, {wxListCtrl, create, 2}},
- {1665, {wxListCtrl, deleteAllItems, 0}},
- {1666, {wxListCtrl, deleteColumn, 1}},
- {1667, {wxListCtrl, deleteItem, 1}},
- {1668, {wxListCtrl, editLabel, 1}},
- {1669, {wxListCtrl, ensureVisible, 1}},
- {1670, {wxListCtrl, findItem_3_0, 3}},
- {1671, {wxListCtrl, findItem_3_1, 3}},
- {1672, {wxListCtrl, getColumn, 2}},
- {1673, {wxListCtrl, getColumnCount, 0}},
- {1674, {wxListCtrl, getColumnWidth, 1}},
- {1675, {wxListCtrl, getCountPerPage, 0}},
- {1676, {wxListCtrl, getEditControl, 0}},
- {1677, {wxListCtrl, getImageList, 1}},
- {1678, {wxListCtrl, getItem, 1}},
- {1679, {wxListCtrl, getItemBackgroundColour, 1}},
- {1680, {wxListCtrl, getItemCount, 0}},
- {1681, {wxListCtrl, getItemData, 1}},
- {1682, {wxListCtrl, getItemFont, 1}},
- {1683, {wxListCtrl, getItemPosition, 2}},
- {1684, {wxListCtrl, getItemRect, 3}},
- {1685, {wxListCtrl, getItemSpacing, 0}},
- {1686, {wxListCtrl, getItemState, 2}},
- {1687, {wxListCtrl, getItemText, 1}},
- {1688, {wxListCtrl, getItemTextColour, 1}},
- {1689, {wxListCtrl, getNextItem, 2}},
- {1690, {wxListCtrl, getSelectedItemCount, 0}},
- {1691, {wxListCtrl, getTextColour, 0}},
- {1692, {wxListCtrl, getTopItem, 0}},
- {1693, {wxListCtrl, getViewRect, 0}},
- {1694, {wxListCtrl, hitTest, 3}},
- {1695, {wxListCtrl, insertColumn_2, 2}},
- {1696, {wxListCtrl, insertColumn_3, 3}},
- {1697, {wxListCtrl, insertItem_1, 1}},
- {1698, {wxListCtrl, insertItem_2_1, 2}},
- {1699, {wxListCtrl, insertItem_2_0, 2}},
- {1700, {wxListCtrl, insertItem_3, 3}},
- {1701, {wxListCtrl, refreshItem, 1}},
- {1702, {wxListCtrl, refreshItems, 2}},
- {1703, {wxListCtrl, scrollList, 2}},
- {1704, {wxListCtrl, setBackgroundColour, 1}},
- {1705, {wxListCtrl, setColumn, 2}},
- {1706, {wxListCtrl, setColumnWidth, 2}},
- {1707, {wxListCtrl, setImageList, 2}},
- {1708, {wxListCtrl, setItem_1, 1}},
- {1709, {wxListCtrl, setItem_4, 4}},
- {1710, {wxListCtrl, setItemBackgroundColour, 2}},
- {1711, {wxListCtrl, setItemCount, 1}},
- {1712, {wxListCtrl, setItemData, 2}},
- {1713, {wxListCtrl, setItemFont, 2}},
- {1714, {wxListCtrl, setItemImage, 3}},
- {1715, {wxListCtrl, setItemColumnImage, 3}},
- {1716, {wxListCtrl, setItemPosition, 2}},
- {1717, {wxListCtrl, setItemState, 3}},
- {1718, {wxListCtrl, setItemText, 2}},
- {1719, {wxListCtrl, setItemTextColour, 2}},
- {1720, {wxListCtrl, setSingleStyle, 2}},
- {1721, {wxListCtrl, setTextColour, 1}},
- {1722, {wxListCtrl, setWindowStyleFlag, 1}},
- {1723, {wxListCtrl, sortItems, 2}},
- {1724, {wxListCtrl, 'Destroy', undefined}},
- {1725, {wxListView, clearColumnImage, 1}},
- {1726, {wxListView, focus, 1}},
- {1727, {wxListView, getFirstSelected, 0}},
- {1728, {wxListView, getFocusedItem, 0}},
- {1729, {wxListView, getNextSelected, 1}},
- {1730, {wxListView, isSelected, 1}},
- {1731, {wxListView, select, 2}},
- {1732, {wxListView, setColumnImage, 2}},
- {1733, {wxListItem, new_0, 0}},
- {1734, {wxListItem, new_1, 1}},
- {1735, {wxListItem, destruct, 0}},
- {1736, {wxListItem, clear, 0}},
- {1737, {wxListItem, getAlign, 0}},
- {1738, {wxListItem, getBackgroundColour, 0}},
- {1739, {wxListItem, getColumn, 0}},
- {1740, {wxListItem, getFont, 0}},
- {1741, {wxListItem, getId, 0}},
- {1742, {wxListItem, getImage, 0}},
- {1743, {wxListItem, getMask, 0}},
- {1744, {wxListItem, getState, 0}},
- {1745, {wxListItem, getText, 0}},
- {1746, {wxListItem, getTextColour, 0}},
- {1747, {wxListItem, getWidth, 0}},
- {1748, {wxListItem, setAlign, 1}},
- {1749, {wxListItem, setBackgroundColour, 1}},
- {1750, {wxListItem, setColumn, 1}},
- {1751, {wxListItem, setFont, 1}},
- {1752, {wxListItem, setId, 1}},
- {1753, {wxListItem, setImage, 1}},
- {1754, {wxListItem, setMask, 1}},
- {1755, {wxListItem, setState, 1}},
- {1756, {wxListItem, setStateMask, 1}},
- {1757, {wxListItem, setText, 1}},
- {1758, {wxListItem, setTextColour, 1}},
- {1759, {wxListItem, setWidth, 1}},
- {1760, {wxListItemAttr, new_0, 0}},
- {1761, {wxListItemAttr, new_3, 3}},
- {1762, {wxListItemAttr, getBackgroundColour, 0}},
- {1763, {wxListItemAttr, getFont, 0}},
- {1764, {wxListItemAttr, getTextColour, 0}},
- {1765, {wxListItemAttr, hasBackgroundColour, 0}},
- {1766, {wxListItemAttr, hasFont, 0}},
- {1767, {wxListItemAttr, hasTextColour, 0}},
- {1768, {wxListItemAttr, setBackgroundColour, 1}},
- {1769, {wxListItemAttr, setFont, 1}},
- {1770, {wxListItemAttr, setTextColour, 1}},
- {1771, {wxListItemAttr, 'Destroy', undefined}},
- {1772, {wxImageList, new_0, 0}},
- {1773, {wxImageList, new_3, 3}},
- {1774, {wxImageList, add_1, 1}},
- {1775, {wxImageList, add_2_0, 2}},
- {1776, {wxImageList, add_2_1, 2}},
- {1777, {wxImageList, create, 3}},
- {1779, {wxImageList, draw, 5}},
- {1780, {wxImageList, getBitmap, 1}},
- {1781, {wxImageList, getIcon, 1}},
- {1782, {wxImageList, getImageCount, 0}},
- {1783, {wxImageList, getSize, 3}},
- {1784, {wxImageList, remove, 1}},
- {1785, {wxImageList, removeAll, 0}},
- {1786, {wxImageList, replace_2, 2}},
- {1787, {wxImageList, replace_3, 3}},
- {1788, {wxImageList, 'Destroy', undefined}},
- {1789, {wxTextAttr, new_0, 0}},
- {1790, {wxTextAttr, new_2, 2}},
- {1791, {wxTextAttr, getAlignment, 0}},
- {1792, {wxTextAttr, getBackgroundColour, 0}},
- {1793, {wxTextAttr, getFont, 0}},
- {1794, {wxTextAttr, getLeftIndent, 0}},
- {1795, {wxTextAttr, getLeftSubIndent, 0}},
- {1796, {wxTextAttr, getRightIndent, 0}},
- {1797, {wxTextAttr, getTabs, 0}},
- {1798, {wxTextAttr, getTextColour, 0}},
- {1799, {wxTextAttr, hasBackgroundColour, 0}},
- {1800, {wxTextAttr, hasFont, 0}},
- {1801, {wxTextAttr, hasTextColour, 0}},
- {1802, {wxTextAttr, getFlags, 0}},
- {1803, {wxTextAttr, isDefault, 0}},
- {1804, {wxTextAttr, setAlignment, 1}},
- {1805, {wxTextAttr, setBackgroundColour, 1}},
- {1806, {wxTextAttr, setFlags, 1}},
- {1807, {wxTextAttr, setFont, 2}},
- {1808, {wxTextAttr, setLeftIndent, 2}},
- {1809, {wxTextAttr, setRightIndent, 1}},
- {1810, {wxTextAttr, setTabs, 1}},
- {1811, {wxTextAttr, setTextColour, 1}},
- {1812, {wxTextAttr, 'Destroy', undefined}},
- {1814, {wxTextCtrl, new_3, 3}},
- {1815, {wxTextCtrl, new_0, 0}},
- {1817, {wxTextCtrl, destruct, 0}},
- {1818, {wxTextCtrl, appendText, 1}},
- {1819, {wxTextCtrl, canCopy, 0}},
- {1820, {wxTextCtrl, canCut, 0}},
- {1821, {wxTextCtrl, canPaste, 0}},
- {1822, {wxTextCtrl, canRedo, 0}},
- {1823, {wxTextCtrl, canUndo, 0}},
- {1824, {wxTextCtrl, clear, 0}},
- {1825, {wxTextCtrl, copy, 0}},
- {1826, {wxTextCtrl, create, 3}},
- {1827, {wxTextCtrl, cut, 0}},
- {1828, {wxTextCtrl, discardEdits, 0}},
- {1829, {wxTextCtrl, changeValue, 1}},
- {1830, {wxTextCtrl, emulateKeyPress, 1}},
- {1831, {wxTextCtrl, getDefaultStyle, 0}},
- {1832, {wxTextCtrl, getInsertionPoint, 0}},
- {1833, {wxTextCtrl, getLastPosition, 0}},
- {1834, {wxTextCtrl, getLineLength, 1}},
- {1835, {wxTextCtrl, getLineText, 1}},
- {1836, {wxTextCtrl, getNumberOfLines, 0}},
- {1837, {wxTextCtrl, getRange, 2}},
- {1838, {wxTextCtrl, getSelection, 2}},
- {1839, {wxTextCtrl, getStringSelection, 0}},
- {1840, {wxTextCtrl, getStyle, 2}},
- {1841, {wxTextCtrl, getValue, 0}},
- {1842, {wxTextCtrl, isEditable, 0}},
- {1843, {wxTextCtrl, isModified, 0}},
- {1844, {wxTextCtrl, isMultiLine, 0}},
- {1845, {wxTextCtrl, isSingleLine, 0}},
- {1846, {wxTextCtrl, loadFile, 2}},
- {1847, {wxTextCtrl, markDirty, 0}},
- {1848, {wxTextCtrl, paste, 0}},
- {1849, {wxTextCtrl, positionToXY, 3}},
- {1850, {wxTextCtrl, redo, 0}},
- {1851, {wxTextCtrl, remove, 2}},
- {1852, {wxTextCtrl, replace, 3}},
- {1853, {wxTextCtrl, saveFile, 1}},
- {1854, {wxTextCtrl, setDefaultStyle, 1}},
- {1855, {wxTextCtrl, setEditable, 1}},
- {1856, {wxTextCtrl, setInsertionPoint, 1}},
- {1857, {wxTextCtrl, setInsertionPointEnd, 0}},
- {1859, {wxTextCtrl, setMaxLength, 1}},
- {1860, {wxTextCtrl, setSelection, 2}},
- {1861, {wxTextCtrl, setStyle, 3}},
- {1862, {wxTextCtrl, setValue, 1}},
- {1863, {wxTextCtrl, showPosition, 1}},
- {1864, {wxTextCtrl, undo, 0}},
- {1865, {wxTextCtrl, writeText, 1}},
- {1866, {wxTextCtrl, xYToPosition, 2}},
- {1869, {wxNotebook, new_0, 0}},
- {1870, {wxNotebook, new_3, 3}},
- {1871, {wxNotebook, destruct, 0}},
- {1872, {wxNotebook, addPage, 3}},
- {1873, {wxNotebook, advanceSelection, 1}},
- {1874, {wxNotebook, assignImageList, 1}},
- {1875, {wxNotebook, create, 3}},
- {1876, {wxNotebook, deleteAllPages, 0}},
- {1877, {wxNotebook, deletePage, 1}},
- {1878, {wxNotebook, removePage, 1}},
- {1879, {wxNotebook, getCurrentPage, 0}},
- {1880, {wxNotebook, getImageList, 0}},
- {1882, {wxNotebook, getPage, 1}},
- {1883, {wxNotebook, getPageCount, 0}},
- {1884, {wxNotebook, getPageImage, 1}},
- {1885, {wxNotebook, getPageText, 1}},
- {1886, {wxNotebook, getRowCount, 0}},
- {1887, {wxNotebook, getSelection, 0}},
- {1888, {wxNotebook, getThemeBackgroundColour, 0}},
- {1890, {wxNotebook, hitTest, 2}},
- {1892, {wxNotebook, insertPage, 4}},
- {1893, {wxNotebook, setImageList, 1}},
- {1894, {wxNotebook, setPadding, 1}},
- {1895, {wxNotebook, setPageSize, 1}},
- {1896, {wxNotebook, setPageImage, 2}},
- {1897, {wxNotebook, setPageText, 2}},
- {1898, {wxNotebook, setSelection, 1}},
- {1899, {wxNotebook, changeSelection, 1}},
- {1900, {wxChoicebook, new_0, 0}},
- {1901, {wxChoicebook, new_3, 3}},
- {1902, {wxChoicebook, addPage, 3}},
- {1903, {wxChoicebook, advanceSelection, 1}},
- {1904, {wxChoicebook, assignImageList, 1}},
- {1905, {wxChoicebook, create, 3}},
- {1906, {wxChoicebook, deleteAllPages, 0}},
- {1907, {wxChoicebook, deletePage, 1}},
- {1908, {wxChoicebook, removePage, 1}},
- {1909, {wxChoicebook, getCurrentPage, 0}},
- {1910, {wxChoicebook, getImageList, 0}},
- {1912, {wxChoicebook, getPage, 1}},
- {1913, {wxChoicebook, getPageCount, 0}},
- {1914, {wxChoicebook, getPageImage, 1}},
- {1915, {wxChoicebook, getPageText, 1}},
- {1916, {wxChoicebook, getSelection, 0}},
- {1917, {wxChoicebook, hitTest, 2}},
- {1918, {wxChoicebook, insertPage, 4}},
- {1919, {wxChoicebook, setImageList, 1}},
- {1920, {wxChoicebook, setPageSize, 1}},
- {1921, {wxChoicebook, setPageImage, 2}},
- {1922, {wxChoicebook, setPageText, 2}},
- {1923, {wxChoicebook, setSelection, 1}},
- {1924, {wxChoicebook, changeSelection, 1}},
- {1925, {wxChoicebook, 'Destroy', undefined}},
- {1926, {wxToolbook, new_0, 0}},
- {1927, {wxToolbook, new_3, 3}},
- {1928, {wxToolbook, addPage, 3}},
- {1929, {wxToolbook, advanceSelection, 1}},
- {1930, {wxToolbook, assignImageList, 1}},
- {1931, {wxToolbook, create, 3}},
- {1932, {wxToolbook, deleteAllPages, 0}},
- {1933, {wxToolbook, deletePage, 1}},
- {1934, {wxToolbook, removePage, 1}},
- {1935, {wxToolbook, getCurrentPage, 0}},
- {1936, {wxToolbook, getImageList, 0}},
- {1938, {wxToolbook, getPage, 1}},
- {1939, {wxToolbook, getPageCount, 0}},
- {1940, {wxToolbook, getPageImage, 1}},
- {1941, {wxToolbook, getPageText, 1}},
- {1942, {wxToolbook, getSelection, 0}},
- {1944, {wxToolbook, hitTest, 2}},
- {1945, {wxToolbook, insertPage, 4}},
- {1946, {wxToolbook, setImageList, 1}},
- {1947, {wxToolbook, setPageSize, 1}},
- {1948, {wxToolbook, setPageImage, 2}},
- {1949, {wxToolbook, setPageText, 2}},
- {1950, {wxToolbook, setSelection, 1}},
- {1951, {wxToolbook, changeSelection, 1}},
- {1952, {wxToolbook, 'Destroy', undefined}},
- {1953, {wxListbook, new_0, 0}},
- {1954, {wxListbook, new_3, 3}},
- {1955, {wxListbook, addPage, 3}},
- {1956, {wxListbook, advanceSelection, 1}},
- {1957, {wxListbook, assignImageList, 1}},
- {1958, {wxListbook, create, 3}},
- {1959, {wxListbook, deleteAllPages, 0}},
- {1960, {wxListbook, deletePage, 1}},
- {1961, {wxListbook, removePage, 1}},
- {1962, {wxListbook, getCurrentPage, 0}},
- {1963, {wxListbook, getImageList, 0}},
- {1965, {wxListbook, getPage, 1}},
- {1966, {wxListbook, getPageCount, 0}},
- {1967, {wxListbook, getPageImage, 1}},
- {1968, {wxListbook, getPageText, 1}},
- {1969, {wxListbook, getSelection, 0}},
- {1971, {wxListbook, hitTest, 2}},
- {1972, {wxListbook, insertPage, 4}},
- {1973, {wxListbook, setImageList, 1}},
- {1974, {wxListbook, setPageSize, 1}},
- {1975, {wxListbook, setPageImage, 2}},
- {1976, {wxListbook, setPageText, 2}},
- {1977, {wxListbook, setSelection, 1}},
- {1978, {wxListbook, changeSelection, 1}},
- {1979, {wxListbook, 'Destroy', undefined}},
- {1980, {wxTreebook, new_0, 0}},
- {1981, {wxTreebook, new_3, 3}},
- {1982, {wxTreebook, addPage, 3}},
- {1983, {wxTreebook, advanceSelection, 1}},
- {1984, {wxTreebook, assignImageList, 1}},
- {1985, {wxTreebook, create, 3}},
- {1986, {wxTreebook, deleteAllPages, 0}},
- {1987, {wxTreebook, deletePage, 1}},
- {1988, {wxTreebook, removePage, 1}},
- {1989, {wxTreebook, getCurrentPage, 0}},
- {1990, {wxTreebook, getImageList, 0}},
- {1992, {wxTreebook, getPage, 1}},
- {1993, {wxTreebook, getPageCount, 0}},
- {1994, {wxTreebook, getPageImage, 1}},
- {1995, {wxTreebook, getPageText, 1}},
- {1996, {wxTreebook, getSelection, 0}},
- {1997, {wxTreebook, expandNode, 2}},
- {1998, {wxTreebook, isNodeExpanded, 1}},
- {2000, {wxTreebook, hitTest, 2}},
- {2001, {wxTreebook, insertPage, 4}},
- {2002, {wxTreebook, insertSubPage, 4}},
- {2003, {wxTreebook, setImageList, 1}},
- {2004, {wxTreebook, setPageSize, 1}},
- {2005, {wxTreebook, setPageImage, 2}},
- {2006, {wxTreebook, setPageText, 2}},
- {2007, {wxTreebook, setSelection, 1}},
- {2008, {wxTreebook, changeSelection, 1}},
- {2009, {wxTreebook, 'Destroy', undefined}},
- {2012, {wxTreeCtrl, new_2, 2}},
- {2013, {wxTreeCtrl, new_0, 0}},
- {2015, {wxTreeCtrl, destruct, 0}},
- {2016, {wxTreeCtrl, addRoot, 2}},
- {2017, {wxTreeCtrl, appendItem, 3}},
- {2018, {wxTreeCtrl, assignImageList, 1}},
- {2019, {wxTreeCtrl, assignStateImageList, 1}},
- {2020, {wxTreeCtrl, collapse, 1}},
- {2021, {wxTreeCtrl, collapseAndReset, 1}},
- {2022, {wxTreeCtrl, create, 2}},
- {2023, {wxTreeCtrl, delete, 1}},
- {2024, {wxTreeCtrl, deleteAllItems, 0}},
- {2025, {wxTreeCtrl, deleteChildren, 1}},
- {2026, {wxTreeCtrl, editLabel, 1}},
- {2027, {wxTreeCtrl, ensureVisible, 1}},
- {2028, {wxTreeCtrl, expand, 1}},
- {2029, {wxTreeCtrl, getBoundingRect, 3}},
- {2031, {wxTreeCtrl, getChildrenCount, 2}},
- {2032, {wxTreeCtrl, getCount, 0}},
- {2033, {wxTreeCtrl, getEditControl, 0}},
- {2034, {wxTreeCtrl, getFirstChild, 2}},
- {2035, {wxTreeCtrl, getNextChild, 2}},
- {2036, {wxTreeCtrl, getFirstVisibleItem, 0}},
- {2037, {wxTreeCtrl, getImageList, 0}},
- {2038, {wxTreeCtrl, getIndent, 0}},
- {2039, {wxTreeCtrl, getItemBackgroundColour, 1}},
- {2040, {wxTreeCtrl, getItemData, 1}},
- {2041, {wxTreeCtrl, getItemFont, 1}},
- {2042, {wxTreeCtrl, getItemImage_1, 1}},
- {2043, {wxTreeCtrl, getItemImage_2, 2}},
- {2044, {wxTreeCtrl, getItemText, 1}},
- {2045, {wxTreeCtrl, getItemTextColour, 1}},
- {2046, {wxTreeCtrl, getLastChild, 1}},
- {2047, {wxTreeCtrl, getNextSibling, 1}},
- {2048, {wxTreeCtrl, getNextVisible, 1}},
- {2049, {wxTreeCtrl, getItemParent, 1}},
- {2050, {wxTreeCtrl, getPrevSibling, 1}},
- {2051, {wxTreeCtrl, getPrevVisible, 1}},
- {2052, {wxTreeCtrl, getRootItem, 0}},
- {2053, {wxTreeCtrl, getSelection, 0}},
- {2054, {wxTreeCtrl, getSelections, 1}},
- {2055, {wxTreeCtrl, getStateImageList, 0}},
- {2056, {wxTreeCtrl, hitTest, 2}},
- {2058, {wxTreeCtrl, insertItem, 4}},
- {2059, {wxTreeCtrl, isBold, 1}},
- {2060, {wxTreeCtrl, isExpanded, 1}},
- {2061, {wxTreeCtrl, isSelected, 1}},
- {2062, {wxTreeCtrl, isVisible, 1}},
- {2063, {wxTreeCtrl, itemHasChildren, 1}},
- {2064, {wxTreeCtrl, isTreeItemIdOk, 1}},
- {2065, {wxTreeCtrl, prependItem, 3}},
- {2066, {wxTreeCtrl, scrollTo, 1}},
- {2067, {wxTreeCtrl, selectItem_1, 1}},
- {2068, {wxTreeCtrl, selectItem_2, 2}},
- {2069, {wxTreeCtrl, setIndent, 1}},
- {2070, {wxTreeCtrl, setImageList, 1}},
- {2071, {wxTreeCtrl, setItemBackgroundColour, 2}},
- {2072, {wxTreeCtrl, setItemBold, 2}},
- {2073, {wxTreeCtrl, setItemData, 2}},
- {2074, {wxTreeCtrl, setItemDropHighlight, 2}},
- {2075, {wxTreeCtrl, setItemFont, 2}},
- {2076, {wxTreeCtrl, setItemHasChildren, 2}},
- {2077, {wxTreeCtrl, setItemImage_2, 2}},
- {2078, {wxTreeCtrl, setItemImage_3, 3}},
- {2079, {wxTreeCtrl, setItemText, 2}},
- {2080, {wxTreeCtrl, setItemTextColour, 2}},
- {2081, {wxTreeCtrl, setStateImageList, 1}},
- {2082, {wxTreeCtrl, setWindowStyle, 1}},
- {2083, {wxTreeCtrl, sortChildren, 1}},
- {2084, {wxTreeCtrl, toggle, 1}},
- {2085, {wxTreeCtrl, toggleItemSelection, 1}},
- {2086, {wxTreeCtrl, unselect, 0}},
- {2087, {wxTreeCtrl, unselectAll, 0}},
- {2088, {wxTreeCtrl, unselectItem, 1}},
- {2089, {wxScrollBar, new_0, 0}},
- {2090, {wxScrollBar, new_3, 3}},
- {2091, {wxScrollBar, destruct, 0}},
- {2092, {wxScrollBar, create, 3}},
- {2093, {wxScrollBar, getRange, 0}},
- {2094, {wxScrollBar, getPageSize, 0}},
- {2095, {wxScrollBar, getThumbPosition, 0}},
- {2096, {wxScrollBar, getThumbSize, 0}},
- {2097, {wxScrollBar, setThumbPosition, 1}},
- {2098, {wxScrollBar, setScrollbar, 5}},
- {2100, {wxSpinButton, new_2, 2}},
- {2101, {wxSpinButton, new_0, 0}},
- {2102, {wxSpinButton, create, 2}},
- {2103, {wxSpinButton, getMax, 0}},
- {2104, {wxSpinButton, getMin, 0}},
- {2105, {wxSpinButton, getValue, 0}},
- {2106, {wxSpinButton, setRange, 2}},
- {2107, {wxSpinButton, setValue, 1}},
- {2108, {wxSpinButton, 'Destroy', undefined}},
- {2109, {wxSpinCtrl, new_0, 0}},
- {2110, {wxSpinCtrl, new_2, 2}},
- {2112, {wxSpinCtrl, create, 2}},
- {2115, {wxSpinCtrl, setValue_1_1, 1}},
- {2116, {wxSpinCtrl, setValue_1_0, 1}},
- {2118, {wxSpinCtrl, getValue, 0}},
- {2120, {wxSpinCtrl, setRange, 2}},
- {2121, {wxSpinCtrl, setSelection, 2}},
- {2123, {wxSpinCtrl, getMin, 0}},
- {2125, {wxSpinCtrl, getMax, 0}},
- {2126, {wxSpinCtrl, 'Destroy', undefined}},
- {2127, {wxStaticText, new_0, 0}},
- {2128, {wxStaticText, new_4, 4}},
- {2129, {wxStaticText, create, 4}},
- {2130, {wxStaticText, getLabel, 0}},
- {2131, {wxStaticText, setLabel, 1}},
- {2132, {wxStaticText, wrap, 1}},
- {2133, {wxStaticText, 'Destroy', undefined}},
- {2134, {wxStaticBitmap, new_0, 0}},
- {2135, {wxStaticBitmap, new_4, 4}},
- {2136, {wxStaticBitmap, create, 4}},
- {2137, {wxStaticBitmap, getBitmap, 0}},
- {2138, {wxStaticBitmap, setBitmap, 1}},
- {2139, {wxStaticBitmap, 'Destroy', undefined}},
- {2140, {wxRadioBox, new, 7}},
- {2142, {wxRadioBox, destruct, 0}},
- {2143, {wxRadioBox, create, 7}},
- {2144, {wxRadioBox, enable_2, 2}},
- {2145, {wxRadioBox, enable_1, 1}},
- {2146, {wxRadioBox, getSelection, 0}},
- {2147, {wxRadioBox, getString, 1}},
- {2148, {wxRadioBox, setSelection, 1}},
- {2149, {wxRadioBox, show_2, 2}},
- {2150, {wxRadioBox, show_1, 1}},
- {2151, {wxRadioBox, getColumnCount, 0}},
- {2152, {wxRadioBox, getItemHelpText, 1}},
- {2153, {wxRadioBox, getItemToolTip, 1}},
- {2155, {wxRadioBox, getItemFromPoint, 1}},
- {2156, {wxRadioBox, getRowCount, 0}},
- {2157, {wxRadioBox, isItemEnabled, 1}},
- {2158, {wxRadioBox, isItemShown, 1}},
- {2159, {wxRadioBox, setItemHelpText, 2}},
- {2160, {wxRadioBox, setItemToolTip, 2}},
- {2161, {wxRadioButton, new_0, 0}},
- {2162, {wxRadioButton, new_4, 4}},
- {2163, {wxRadioButton, create, 4}},
- {2164, {wxRadioButton, getValue, 0}},
- {2165, {wxRadioButton, setValue, 1}},
- {2166, {wxRadioButton, 'Destroy', undefined}},
- {2168, {wxSlider, new_6, 6}},
- {2169, {wxSlider, new_0, 0}},
- {2170, {wxSlider, create, 6}},
- {2171, {wxSlider, getLineSize, 0}},
- {2172, {wxSlider, getMax, 0}},
- {2173, {wxSlider, getMin, 0}},
- {2174, {wxSlider, getPageSize, 0}},
- {2175, {wxSlider, getThumbLength, 0}},
- {2176, {wxSlider, getValue, 0}},
- {2177, {wxSlider, setLineSize, 1}},
- {2178, {wxSlider, setPageSize, 1}},
- {2179, {wxSlider, setRange, 2}},
- {2180, {wxSlider, setThumbLength, 1}},
- {2181, {wxSlider, setValue, 1}},
- {2182, {wxSlider, 'Destroy', undefined}},
- {2184, {wxDialog, new_4, 4}},
- {2185, {wxDialog, new_0, 0}},
- {2187, {wxDialog, destruct, 0}},
- {2188, {wxDialog, create, 4}},
- {2189, {wxDialog, createButtonSizer, 1}},
- {2190, {wxDialog, createStdDialogButtonSizer, 1}},
- {2191, {wxDialog, endModal, 1}},
- {2192, {wxDialog, getAffirmativeId, 0}},
- {2193, {wxDialog, getReturnCode, 0}},
- {2194, {wxDialog, isModal, 0}},
- {2195, {wxDialog, setAffirmativeId, 1}},
- {2196, {wxDialog, setReturnCode, 1}},
- {2197, {wxDialog, show, 1}},
- {2198, {wxDialog, showModal, 0}},
- {2199, {wxColourDialog, new_0, 0}},
- {2200, {wxColourDialog, new_2, 2}},
- {2201, {wxColourDialog, destruct, 0}},
- {2202, {wxColourDialog, create, 2}},
- {2203, {wxColourDialog, getColourData, 0}},
- {2204, {wxColourData, new_0, 0}},
- {2205, {wxColourData, new_1, 1}},
- {2206, {wxColourData, destruct, 0}},
- {2207, {wxColourData, getChooseFull, 0}},
- {2208, {wxColourData, getColour, 0}},
- {2210, {wxColourData, getCustomColour, 1}},
- {2211, {wxColourData, setChooseFull, 1}},
- {2212, {wxColourData, setColour, 1}},
- {2213, {wxColourData, setCustomColour, 2}},
- {2214, {wxPalette, new_0, 0}},
- {2215, {wxPalette, new_4, 4}},
- {2217, {wxPalette, destruct, 0}},
- {2218, {wxPalette, create, 4}},
- {2219, {wxPalette, getColoursCount, 0}},
- {2220, {wxPalette, getPixel, 3}},
- {2221, {wxPalette, getRGB, 4}},
- {2222, {wxPalette, isOk, 0}},
- {2226, {wxDirDialog, new, 2}},
- {2227, {wxDirDialog, destruct, 0}},
- {2228, {wxDirDialog, getPath, 0}},
- {2229, {wxDirDialog, getMessage, 0}},
- {2230, {wxDirDialog, setMessage, 1}},
- {2231, {wxDirDialog, setPath, 1}},
- {2235, {wxFileDialog, new, 2}},
- {2236, {wxFileDialog, destruct, 0}},
- {2237, {wxFileDialog, getDirectory, 0}},
- {2238, {wxFileDialog, getFilename, 0}},
- {2239, {wxFileDialog, getFilenames, 1}},
- {2240, {wxFileDialog, getFilterIndex, 0}},
- {2241, {wxFileDialog, getMessage, 0}},
- {2242, {wxFileDialog, getPath, 0}},
- {2243, {wxFileDialog, getPaths, 1}},
- {2244, {wxFileDialog, getWildcard, 0}},
- {2245, {wxFileDialog, setDirectory, 1}},
- {2246, {wxFileDialog, setFilename, 1}},
- {2247, {wxFileDialog, setFilterIndex, 1}},
- {2248, {wxFileDialog, setMessage, 1}},
- {2249, {wxFileDialog, setPath, 1}},
- {2250, {wxFileDialog, setWildcard, 1}},
- {2251, {wxPickerBase, setInternalMargin, 1}},
- {2252, {wxPickerBase, getInternalMargin, 0}},
- {2253, {wxPickerBase, setTextCtrlProportion, 1}},
- {2254, {wxPickerBase, setPickerCtrlProportion, 1}},
- {2255, {wxPickerBase, getTextCtrlProportion, 0}},
- {2256, {wxPickerBase, getPickerCtrlProportion, 0}},
- {2257, {wxPickerBase, hasTextCtrl, 0}},
- {2258, {wxPickerBase, getTextCtrl, 0}},
- {2259, {wxPickerBase, isTextCtrlGrowable, 0}},
- {2260, {wxPickerBase, setPickerCtrlGrowable, 1}},
- {2261, {wxPickerBase, setTextCtrlGrowable, 1}},
- {2262, {wxPickerBase, isPickerCtrlGrowable, 0}},
- {2263, {wxFilePickerCtrl, new_0, 0}},
- {2264, {wxFilePickerCtrl, new_3, 3}},
- {2265, {wxFilePickerCtrl, create, 3}},
- {2266, {wxFilePickerCtrl, getPath, 0}},
- {2267, {wxFilePickerCtrl, setPath, 1}},
- {2268, {wxFilePickerCtrl, 'Destroy', undefined}},
- {2269, {wxDirPickerCtrl, new_0, 0}},
- {2270, {wxDirPickerCtrl, new_3, 3}},
- {2271, {wxDirPickerCtrl, create, 3}},
- {2272, {wxDirPickerCtrl, getPath, 0}},
- {2273, {wxDirPickerCtrl, setPath, 1}},
- {2274, {wxDirPickerCtrl, 'Destroy', undefined}},
- {2275, {wxColourPickerCtrl, new_0, 0}},
- {2276, {wxColourPickerCtrl, new_3, 3}},
- {2277, {wxColourPickerCtrl, create, 3}},
- {2278, {wxColourPickerCtrl, getColour, 0}},
- {2279, {wxColourPickerCtrl, setColour_1_1, 1}},
- {2280, {wxColourPickerCtrl, setColour_1_0, 1}},
- {2281, {wxColourPickerCtrl, 'Destroy', undefined}},
- {2282, {wxDatePickerCtrl, new_0, 0}},
- {2283, {wxDatePickerCtrl, new_3, 3}},
- {2284, {wxDatePickerCtrl, getRange, 2}},
- {2285, {wxDatePickerCtrl, getValue, 0}},
- {2286, {wxDatePickerCtrl, setRange, 2}},
- {2287, {wxDatePickerCtrl, setValue, 1}},
- {2288, {wxDatePickerCtrl, 'Destroy', undefined}},
- {2289, {wxFontPickerCtrl, new_0, 0}},
- {2290, {wxFontPickerCtrl, new_3, 3}},
- {2291, {wxFontPickerCtrl, create, 3}},
- {2292, {wxFontPickerCtrl, getSelectedFont, 0}},
- {2293, {wxFontPickerCtrl, setSelectedFont, 1}},
- {2294, {wxFontPickerCtrl, getMaxPointSize, 0}},
- {2295, {wxFontPickerCtrl, setMaxPointSize, 1}},
- {2296, {wxFontPickerCtrl, 'Destroy', undefined}},
- {2299, {wxFindReplaceDialog, new_0, 0}},
- {2300, {wxFindReplaceDialog, new_4, 4}},
- {2301, {wxFindReplaceDialog, destruct, 0}},
- {2302, {wxFindReplaceDialog, create, 4}},
- {2303, {wxFindReplaceDialog, getData, 0}},
- {2304, {wxFindReplaceData, new_0, 0}},
- {2305, {wxFindReplaceData, new_1, 1}},
- {2306, {wxFindReplaceData, getFindString, 0}},
- {2307, {wxFindReplaceData, getReplaceString, 0}},
- {2308, {wxFindReplaceData, getFlags, 0}},
- {2309, {wxFindReplaceData, setFlags, 1}},
- {2310, {wxFindReplaceData, setFindString, 1}},
- {2311, {wxFindReplaceData, setReplaceString, 1}},
- {2312, {wxFindReplaceData, 'Destroy', undefined}},
- {2313, {wxMultiChoiceDialog, new_0, 0}},
- {2315, {wxMultiChoiceDialog, new_5, 5}},
- {2316, {wxMultiChoiceDialog, getSelections, 0}},
- {2317, {wxMultiChoiceDialog, setSelections, 1}},
- {2318, {wxMultiChoiceDialog, 'Destroy', undefined}},
- {2319, {wxSingleChoiceDialog, new_0, 0}},
- {2321, {wxSingleChoiceDialog, new_5, 5}},
- {2322, {wxSingleChoiceDialog, getSelection, 0}},
- {2323, {wxSingleChoiceDialog, getStringSelection, 0}},
- {2324, {wxSingleChoiceDialog, setSelection, 1}},
- {2325, {wxSingleChoiceDialog, 'Destroy', undefined}},
- {2326, {wxTextEntryDialog, new, 3}},
- {2327, {wxTextEntryDialog, getValue, 0}},
- {2328, {wxTextEntryDialog, setValue, 1}},
- {2329, {wxTextEntryDialog, 'Destroy', undefined}},
- {2330, {wxPasswordEntryDialog, new, 3}},
- {2331, {wxPasswordEntryDialog, 'Destroy', undefined}},
- {2332, {wxFontData, new_0, 0}},
- {2333, {wxFontData, new_1, 1}},
- {2334, {wxFontData, destruct, 0}},
- {2335, {wxFontData, enableEffects, 1}},
- {2336, {wxFontData, getAllowSymbols, 0}},
- {2337, {wxFontData, getColour, 0}},
- {2338, {wxFontData, getChosenFont, 0}},
- {2339, {wxFontData, getEnableEffects, 0}},
- {2340, {wxFontData, getInitialFont, 0}},
- {2341, {wxFontData, getShowHelp, 0}},
- {2342, {wxFontData, setAllowSymbols, 1}},
- {2343, {wxFontData, setChosenFont, 1}},
- {2344, {wxFontData, setColour, 1}},
- {2345, {wxFontData, setInitialFont, 1}},
- {2346, {wxFontData, setRange, 2}},
- {2347, {wxFontData, setShowHelp, 1}},
- {2351, {wxFontDialog, new_0, 0}},
- {2353, {wxFontDialog, new_2, 2}},
- {2355, {wxFontDialog, create, 2}},
- {2356, {wxFontDialog, getFontData, 0}},
- {2358, {wxFontDialog, 'Destroy', undefined}},
- {2359, {wxProgressDialog, new, 3}},
- {2360, {wxProgressDialog, destruct, 0}},
- {2361, {wxProgressDialog, resume, 0}},
- {2362, {wxProgressDialog, update_2, 2}},
- {2363, {wxProgressDialog, update_0, 0}},
- {2364, {wxMessageDialog, new, 3}},
- {2365, {wxMessageDialog, destruct, 0}},
- {2366, {wxPageSetupDialog, new, 2}},
- {2367, {wxPageSetupDialog, destruct, 0}},
- {2368, {wxPageSetupDialog, getPageSetupData, 0}},
- {2369, {wxPageSetupDialog, showModal, 0}},
- {2370, {wxPageSetupDialogData, new_0, 0}},
- {2371, {wxPageSetupDialogData, new_1_0, 1}},
- {2372, {wxPageSetupDialogData, new_1_1, 1}},
- {2373, {wxPageSetupDialogData, destruct, 0}},
- {2374, {wxPageSetupDialogData, enableHelp, 1}},
- {2375, {wxPageSetupDialogData, enableMargins, 1}},
- {2376, {wxPageSetupDialogData, enableOrientation, 1}},
- {2377, {wxPageSetupDialogData, enablePaper, 1}},
- {2378, {wxPageSetupDialogData, enablePrinter, 1}},
- {2379, {wxPageSetupDialogData, getDefaultMinMargins, 0}},
- {2380, {wxPageSetupDialogData, getEnableMargins, 0}},
- {2381, {wxPageSetupDialogData, getEnableOrientation, 0}},
- {2382, {wxPageSetupDialogData, getEnablePaper, 0}},
- {2383, {wxPageSetupDialogData, getEnablePrinter, 0}},
- {2384, {wxPageSetupDialogData, getEnableHelp, 0}},
- {2385, {wxPageSetupDialogData, getDefaultInfo, 0}},
- {2386, {wxPageSetupDialogData, getMarginTopLeft, 0}},
- {2387, {wxPageSetupDialogData, getMarginBottomRight, 0}},
- {2388, {wxPageSetupDialogData, getMinMarginTopLeft, 0}},
- {2389, {wxPageSetupDialogData, getMinMarginBottomRight, 0}},
- {2390, {wxPageSetupDialogData, getPaperId, 0}},
- {2391, {wxPageSetupDialogData, getPaperSize, 0}},
- {2393, {wxPageSetupDialogData, getPrintData, 0}},
- {2394, {wxPageSetupDialogData, isOk, 0}},
- {2395, {wxPageSetupDialogData, setDefaultInfo, 1}},
- {2396, {wxPageSetupDialogData, setDefaultMinMargins, 1}},
- {2397, {wxPageSetupDialogData, setMarginTopLeft, 1}},
- {2398, {wxPageSetupDialogData, setMarginBottomRight, 1}},
- {2399, {wxPageSetupDialogData, setMinMarginTopLeft, 1}},
- {2400, {wxPageSetupDialogData, setMinMarginBottomRight, 1}},
- {2401, {wxPageSetupDialogData, setPaperId, 1}},
- {2402, {wxPageSetupDialogData, setPaperSize_1_1, 1}},
- {2403, {wxPageSetupDialogData, setPaperSize_1_0, 1}},
- {2404, {wxPageSetupDialogData, setPrintData, 1}},
- {2405, {wxPrintDialog, new_2_0, 2}},
- {2406, {wxPrintDialog, new_2_1, 2}},
- {2407, {wxPrintDialog, destruct, 0}},
- {2408, {wxPrintDialog, getPrintDialogData, 0}},
- {2409, {wxPrintDialog, getPrintDC, 0}},
- {2410, {wxPrintDialogData, new_0, 0}},
- {2411, {wxPrintDialogData, new_1_1, 1}},
- {2412, {wxPrintDialogData, new_1_0, 1}},
- {2413, {wxPrintDialogData, destruct, 0}},
- {2414, {wxPrintDialogData, enableHelp, 1}},
- {2415, {wxPrintDialogData, enablePageNumbers, 1}},
- {2416, {wxPrintDialogData, enablePrintToFile, 1}},
- {2417, {wxPrintDialogData, enableSelection, 1}},
- {2418, {wxPrintDialogData, getAllPages, 0}},
- {2419, {wxPrintDialogData, getCollate, 0}},
- {2420, {wxPrintDialogData, getFromPage, 0}},
- {2421, {wxPrintDialogData, getMaxPage, 0}},
- {2422, {wxPrintDialogData, getMinPage, 0}},
- {2423, {wxPrintDialogData, getNoCopies, 0}},
- {2424, {wxPrintDialogData, getPrintData, 0}},
- {2425, {wxPrintDialogData, getPrintToFile, 0}},
- {2426, {wxPrintDialogData, getSelection, 0}},
- {2427, {wxPrintDialogData, getToPage, 0}},
- {2428, {wxPrintDialogData, isOk, 0}},
- {2429, {wxPrintDialogData, setCollate, 1}},
- {2430, {wxPrintDialogData, setFromPage, 1}},
- {2431, {wxPrintDialogData, setMaxPage, 1}},
- {2432, {wxPrintDialogData, setMinPage, 1}},
- {2433, {wxPrintDialogData, setNoCopies, 1}},
- {2434, {wxPrintDialogData, setPrintData, 1}},
- {2435, {wxPrintDialogData, setPrintToFile, 1}},
- {2436, {wxPrintDialogData, setSelection, 1}},
- {2437, {wxPrintDialogData, setToPage, 1}},
- {2438, {wxPrintData, new_0, 0}},
- {2439, {wxPrintData, new_1, 1}},
- {2440, {wxPrintData, destruct, 0}},
- {2441, {wxPrintData, getCollate, 0}},
- {2442, {wxPrintData, getBin, 0}},
- {2443, {wxPrintData, getColour, 0}},
- {2444, {wxPrintData, getDuplex, 0}},
- {2445, {wxPrintData, getNoCopies, 0}},
- {2446, {wxPrintData, getOrientation, 0}},
- {2447, {wxPrintData, getPaperId, 0}},
- {2448, {wxPrintData, getPrinterName, 0}},
- {2449, {wxPrintData, getQuality, 0}},
- {2450, {wxPrintData, isOk, 0}},
- {2451, {wxPrintData, setBin, 1}},
- {2452, {wxPrintData, setCollate, 1}},
- {2453, {wxPrintData, setColour, 1}},
- {2454, {wxPrintData, setDuplex, 1}},
- {2455, {wxPrintData, setNoCopies, 1}},
- {2456, {wxPrintData, setOrientation, 1}},
- {2457, {wxPrintData, setPaperId, 1}},
- {2458, {wxPrintData, setPrinterName, 1}},
- {2459, {wxPrintData, setQuality, 1}},
- {2462, {wxPrintPreview, new_2, 2}},
- {2463, {wxPrintPreview, new_3, 3}},
- {2465, {wxPrintPreview, destruct, 0}},
- {2466, {wxPrintPreview, getCanvas, 0}},
- {2467, {wxPrintPreview, getCurrentPage, 0}},
- {2468, {wxPrintPreview, getFrame, 0}},
- {2469, {wxPrintPreview, getMaxPage, 0}},
- {2470, {wxPrintPreview, getMinPage, 0}},
- {2471, {wxPrintPreview, getPrintout, 0}},
- {2472, {wxPrintPreview, getPrintoutForPrinting, 0}},
- {2473, {wxPrintPreview, isOk, 0}},
- {2474, {wxPrintPreview, paintPage, 2}},
- {2475, {wxPrintPreview, print, 1}},
- {2476, {wxPrintPreview, renderPage, 1}},
- {2477, {wxPrintPreview, setCanvas, 1}},
- {2478, {wxPrintPreview, setCurrentPage, 1}},
- {2479, {wxPrintPreview, setFrame, 1}},
- {2480, {wxPrintPreview, setPrintout, 1}},
- {2481, {wxPrintPreview, setZoom, 1}},
- {2482, {wxPreviewFrame, new, 3}},
- {2483, {wxPreviewFrame, destruct, 0}},
- {2484, {wxPreviewFrame, createControlBar, 0}},
- {2485, {wxPreviewFrame, createCanvas, 0}},
- {2486, {wxPreviewFrame, initialize, 0}},
- {2487, {wxPreviewFrame, onCloseWindow, 1}},
- {2488, {wxPreviewControlBar, new, 4}},
- {2489, {wxPreviewControlBar, destruct, 0}},
- {2490, {wxPreviewControlBar, createButtons, 0}},
- {2491, {wxPreviewControlBar, getPrintPreview, 0}},
- {2492, {wxPreviewControlBar, getZoomControl, 0}},
- {2493, {wxPreviewControlBar, setZoomControl, 1}},
- {2495, {wxPrinter, new, 1}},
- {2496, {wxPrinter, createAbortWindow, 2}},
- {2497, {wxPrinter, getAbort, 0}},
- {2498, {wxPrinter, getLastError, 0}},
- {2499, {wxPrinter, getPrintDialogData, 0}},
- {2500, {wxPrinter, print, 3}},
- {2501, {wxPrinter, printDialog, 1}},
- {2502, {wxPrinter, reportError, 3}},
- {2503, {wxPrinter, setup, 1}},
- {2504, {wxPrinter, 'Destroy', undefined}},
- {2505, {wxXmlResource, new_1, 1}},
- {2506, {wxXmlResource, new_2, 2}},
- {2507, {wxXmlResource, destruct, 0}},
- {2508, {wxXmlResource, attachUnknownControl, 3}},
- {2509, {wxXmlResource, clearHandlers, 0}},
- {2510, {wxXmlResource, compareVersion, 4}},
- {2511, {wxXmlResource, get, 0}},
- {2512, {wxXmlResource, getFlags, 0}},
- {2513, {wxXmlResource, getVersion, 0}},
- {2514, {wxXmlResource, getXRCID, 2}},
- {2515, {wxXmlResource, initAllHandlers, 0}},
- {2516, {wxXmlResource, load, 1}},
- {2517, {wxXmlResource, loadBitmap, 1}},
- {2518, {wxXmlResource, loadDialog_2, 2}},
- {2519, {wxXmlResource, loadDialog_3, 3}},
- {2520, {wxXmlResource, loadFrame_2, 2}},
- {2521, {wxXmlResource, loadFrame_3, 3}},
- {2522, {wxXmlResource, loadIcon, 1}},
- {2523, {wxXmlResource, loadMenu, 1}},
- {2524, {wxXmlResource, loadMenuBar_2, 2}},
- {2525, {wxXmlResource, loadMenuBar_1, 1}},
- {2526, {wxXmlResource, loadPanel_2, 2}},
- {2527, {wxXmlResource, loadPanel_3, 3}},
- {2528, {wxXmlResource, loadToolBar, 2}},
- {2529, {wxXmlResource, set, 1}},
- {2530, {wxXmlResource, setFlags, 1}},
- {2531, {wxXmlResource, unload, 1}},
- {2532, {wxXmlResource, xrcctrl, 3}},
- {2533, {wxHtmlEasyPrinting, new, 1}},
- {2534, {wxHtmlEasyPrinting, destruct, 0}},
- {2535, {wxHtmlEasyPrinting, getPrintData, 0}},
- {2536, {wxHtmlEasyPrinting, getPageSetupData, 0}},
- {2537, {wxHtmlEasyPrinting, previewFile, 1}},
- {2538, {wxHtmlEasyPrinting, previewText, 2}},
- {2539, {wxHtmlEasyPrinting, printFile, 1}},
- {2540, {wxHtmlEasyPrinting, printText, 2}},
- {2541, {wxHtmlEasyPrinting, pageSetup, 0}},
- {2542, {wxHtmlEasyPrinting, setFonts, 3}},
- {2543, {wxHtmlEasyPrinting, setHeader, 2}},
- {2544, {wxHtmlEasyPrinting, setFooter, 2}},
- {2546, {wxGLCanvas, new_2, 2}},
- {2547, {wxGLCanvas, new_3_1, 3}},
- {2548, {wxGLCanvas, new_3_0, 3}},
- {2549, {wxGLCanvas, getContext, 0}},
- {2551, {wxGLCanvas, setCurrent, 0}},
- {2552, {wxGLCanvas, swapBuffers, 0}},
- {2553, {wxGLCanvas, 'Destroy', undefined}},
- {2554, {wxAuiManager, new, 1}},
- {2555, {wxAuiManager, destruct, 0}},
- {2556, {wxAuiManager, addPane_2_1, 2}},
- {2557, {wxAuiManager, addPane_3, 3}},
- {2558, {wxAuiManager, addPane_2_0, 2}},
- {2559, {wxAuiManager, detachPane, 1}},
- {2560, {wxAuiManager, getAllPanes, 0}},
- {2561, {wxAuiManager, getArtProvider, 0}},
- {2562, {wxAuiManager, getDockSizeConstraint, 2}},
- {2563, {wxAuiManager, getFlags, 0}},
- {2564, {wxAuiManager, getManagedWindow, 0}},
- {2565, {wxAuiManager, getManager, 1}},
- {2566, {wxAuiManager, getPane_1_1, 1}},
- {2567, {wxAuiManager, getPane_1_0, 1}},
- {2568, {wxAuiManager, hideHint, 0}},
- {2569, {wxAuiManager, insertPane, 3}},
- {2570, {wxAuiManager, loadPaneInfo, 2}},
- {2571, {wxAuiManager, loadPerspective, 2}},
- {2572, {wxAuiManager, savePaneInfo, 1}},
- {2573, {wxAuiManager, savePerspective, 0}},
- {2574, {wxAuiManager, setArtProvider, 1}},
- {2575, {wxAuiManager, setDockSizeConstraint, 2}},
- {2576, {wxAuiManager, setFlags, 1}},
- {2577, {wxAuiManager, setManagedWindow, 1}},
- {2578, {wxAuiManager, showHint, 1}},
- {2579, {wxAuiManager, unInit, 0}},
- {2580, {wxAuiManager, update, 0}},
- {2581, {wxAuiPaneInfo, new_0, 0}},
- {2582, {wxAuiPaneInfo, new_1, 1}},
- {2583, {wxAuiPaneInfo, destruct, 0}},
- {2584, {wxAuiPaneInfo, bestSize_1, 1}},
- {2585, {wxAuiPaneInfo, bestSize_2, 2}},
- {2586, {wxAuiPaneInfo, bottom, 0}},
- {2587, {wxAuiPaneInfo, bottomDockable, 1}},
- {2588, {wxAuiPaneInfo, caption, 1}},
- {2589, {wxAuiPaneInfo, captionVisible, 1}},
- {2590, {wxAuiPaneInfo, centre, 0}},
- {2591, {wxAuiPaneInfo, centrePane, 0}},
- {2592, {wxAuiPaneInfo, closeButton, 1}},
- {2593, {wxAuiPaneInfo, defaultPane, 0}},
- {2594, {wxAuiPaneInfo, destroyOnClose, 1}},
- {2595, {wxAuiPaneInfo, direction, 1}},
- {2596, {wxAuiPaneInfo, dock, 0}},
- {2597, {wxAuiPaneInfo, dockable, 1}},
- {2598, {wxAuiPaneInfo, fixed, 0}},
- {2599, {wxAuiPaneInfo, float, 0}},
- {2600, {wxAuiPaneInfo, floatable, 1}},
- {2601, {wxAuiPaneInfo, floatingPosition_1, 1}},
- {2602, {wxAuiPaneInfo, floatingPosition_2, 2}},
- {2603, {wxAuiPaneInfo, floatingSize_1, 1}},
- {2604, {wxAuiPaneInfo, floatingSize_2, 2}},
- {2605, {wxAuiPaneInfo, gripper, 1}},
- {2606, {wxAuiPaneInfo, gripperTop, 1}},
- {2607, {wxAuiPaneInfo, hasBorder, 0}},
- {2608, {wxAuiPaneInfo, hasCaption, 0}},
- {2609, {wxAuiPaneInfo, hasCloseButton, 0}},
- {2610, {wxAuiPaneInfo, hasFlag, 1}},
- {2611, {wxAuiPaneInfo, hasGripper, 0}},
- {2612, {wxAuiPaneInfo, hasGripperTop, 0}},
- {2613, {wxAuiPaneInfo, hasMaximizeButton, 0}},
- {2614, {wxAuiPaneInfo, hasMinimizeButton, 0}},
- {2615, {wxAuiPaneInfo, hasPinButton, 0}},
- {2616, {wxAuiPaneInfo, hide, 0}},
- {2617, {wxAuiPaneInfo, isBottomDockable, 0}},
- {2618, {wxAuiPaneInfo, isDocked, 0}},
- {2619, {wxAuiPaneInfo, isFixed, 0}},
- {2620, {wxAuiPaneInfo, isFloatable, 0}},
- {2621, {wxAuiPaneInfo, isFloating, 0}},
- {2622, {wxAuiPaneInfo, isLeftDockable, 0}},
- {2623, {wxAuiPaneInfo, isMovable, 0}},
- {2624, {wxAuiPaneInfo, isOk, 0}},
- {2625, {wxAuiPaneInfo, isResizable, 0}},
- {2626, {wxAuiPaneInfo, isRightDockable, 0}},
- {2627, {wxAuiPaneInfo, isShown, 0}},
- {2628, {wxAuiPaneInfo, isToolbar, 0}},
- {2629, {wxAuiPaneInfo, isTopDockable, 0}},
- {2630, {wxAuiPaneInfo, layer, 1}},
- {2631, {wxAuiPaneInfo, left, 0}},
- {2632, {wxAuiPaneInfo, leftDockable, 1}},
- {2633, {wxAuiPaneInfo, maxSize_1, 1}},
- {2634, {wxAuiPaneInfo, maxSize_2, 2}},
- {2635, {wxAuiPaneInfo, maximizeButton, 1}},
- {2636, {wxAuiPaneInfo, minSize_1, 1}},
- {2637, {wxAuiPaneInfo, minSize_2, 2}},
- {2638, {wxAuiPaneInfo, minimizeButton, 1}},
- {2639, {wxAuiPaneInfo, movable, 1}},
- {2640, {wxAuiPaneInfo, name, 1}},
- {2641, {wxAuiPaneInfo, paneBorder, 1}},
- {2642, {wxAuiPaneInfo, pinButton, 1}},
- {2643, {wxAuiPaneInfo, position, 1}},
- {2644, {wxAuiPaneInfo, resizable, 1}},
- {2645, {wxAuiPaneInfo, right, 0}},
- {2646, {wxAuiPaneInfo, rightDockable, 1}},
- {2647, {wxAuiPaneInfo, row, 1}},
- {2648, {wxAuiPaneInfo, safeSet, 1}},
- {2649, {wxAuiPaneInfo, setFlag, 2}},
- {2650, {wxAuiPaneInfo, show, 1}},
- {2651, {wxAuiPaneInfo, toolbarPane, 0}},
- {2652, {wxAuiPaneInfo, top, 0}},
- {2653, {wxAuiPaneInfo, topDockable, 1}},
- {2654, {wxAuiPaneInfo, window, 1}},
- {2655, {wxAuiPaneInfo, getWindow, 0}},
- {2656, {wxAuiPaneInfo, getFrame, 0}},
- {2657, {wxAuiPaneInfo, getDirection, 0}},
- {2658, {wxAuiPaneInfo, getLayer, 0}},
- {2659, {wxAuiPaneInfo, getRow, 0}},
- {2660, {wxAuiPaneInfo, getPosition, 0}},
- {2661, {wxAuiPaneInfo, getFloatingPosition, 0}},
- {2662, {wxAuiPaneInfo, getFloatingSize, 0}},
- {2663, {wxAuiNotebook, new_0, 0}},
- {2664, {wxAuiNotebook, new_2, 2}},
- {2665, {wxAuiNotebook, addPage, 3}},
- {2666, {wxAuiNotebook, create, 2}},
- {2667, {wxAuiNotebook, deletePage, 1}},
- {2668, {wxAuiNotebook, getArtProvider, 0}},
- {2669, {wxAuiNotebook, getPage, 1}},
- {2670, {wxAuiNotebook, getPageBitmap, 1}},
- {2671, {wxAuiNotebook, getPageCount, 0}},
- {2672, {wxAuiNotebook, getPageIndex, 1}},
- {2673, {wxAuiNotebook, getPageText, 1}},
- {2674, {wxAuiNotebook, getSelection, 0}},
- {2675, {wxAuiNotebook, insertPage, 4}},
- {2676, {wxAuiNotebook, removePage, 1}},
- {2677, {wxAuiNotebook, setArtProvider, 1}},
- {2678, {wxAuiNotebook, setFont, 1}},
- {2679, {wxAuiNotebook, setPageBitmap, 2}},
- {2680, {wxAuiNotebook, setPageText, 2}},
- {2681, {wxAuiNotebook, setSelection, 1}},
- {2682, {wxAuiNotebook, setTabCtrlHeight, 1}},
- {2683, {wxAuiNotebook, setUniformBitmapSize, 1}},
- {2684, {wxAuiNotebook, 'Destroy', undefined}},
- {2685, {wxAuiTabArt, setFlags, 1}},
- {2686, {wxAuiTabArt, setMeasuringFont, 1}},
- {2687, {wxAuiTabArt, setNormalFont, 1}},
- {2688, {wxAuiTabArt, setSelectedFont, 1}},
- {2689, {wxAuiTabArt, setColour, 1}},
- {2690, {wxAuiTabArt, setActiveColour, 1}},
- {2691, {wxAuiDockArt, getColour, 1}},
- {2692, {wxAuiDockArt, getFont, 1}},
- {2693, {wxAuiDockArt, getMetric, 1}},
- {2694, {wxAuiDockArt, setColour, 2}},
- {2695, {wxAuiDockArt, setFont, 2}},
- {2696, {wxAuiDockArt, setMetric, 2}},
- {2697, {wxAuiSimpleTabArt, new, 0}},
- {2698, {wxAuiSimpleTabArt, 'Destroy', undefined}},
- {2699, {wxMDIParentFrame, new_0, 0}},
- {2700, {wxMDIParentFrame, new_4, 4}},
- {2701, {wxMDIParentFrame, destruct, 0}},
- {2702, {wxMDIParentFrame, activateNext, 0}},
- {2703, {wxMDIParentFrame, activatePrevious, 0}},
- {2704, {wxMDIParentFrame, arrangeIcons, 0}},
- {2705, {wxMDIParentFrame, cascade, 0}},
- {2706, {wxMDIParentFrame, create, 4}},
- {2707, {wxMDIParentFrame, getActiveChild, 0}},
- {2708, {wxMDIParentFrame, getClientWindow, 0}},
- {2709, {wxMDIParentFrame, tile, 1}},
- {2710, {wxMDIChildFrame, new_0, 0}},
- {2711, {wxMDIChildFrame, new_4, 4}},
- {2712, {wxMDIChildFrame, destruct, 0}},
- {2713, {wxMDIChildFrame, activate, 0}},
- {2714, {wxMDIChildFrame, create, 4}},
- {2715, {wxMDIChildFrame, maximize, 1}},
- {2716, {wxMDIChildFrame, restore, 0}},
- {2717, {wxMDIClientWindow, new_0, 0}},
- {2718, {wxMDIClientWindow, new_2, 2}},
- {2719, {wxMDIClientWindow, destruct, 0}},
- {2720, {wxMDIClientWindow, createClient, 2}},
- {2721, {wxLayoutAlgorithm, new, 0}},
- {2722, {wxLayoutAlgorithm, layoutFrame, 2}},
- {2723, {wxLayoutAlgorithm, layoutMDIFrame, 2}},
- {2724, {wxLayoutAlgorithm, layoutWindow, 2}},
- {2725, {wxLayoutAlgorithm, 'Destroy', undefined}},
- {2726, {wxEvent, getId, 0}},
- {2727, {wxEvent, getSkipped, 0}},
- {2728, {wxEvent, getTimestamp, 0}},
- {2729, {wxEvent, isCommandEvent, 0}},
- {2730, {wxEvent, resumePropagation, 1}},
- {2731, {wxEvent, shouldPropagate, 0}},
- {2732, {wxEvent, skip, 1}},
- {2733, {wxEvent, stopPropagation, 0}},
- {2734, {wxCommandEvent, getClientData, 0}},
- {2735, {wxCommandEvent, getExtraLong, 0}},
- {2736, {wxCommandEvent, getInt, 0}},
- {2737, {wxCommandEvent, getSelection, 0}},
- {2738, {wxCommandEvent, getString, 0}},
- {2739, {wxCommandEvent, isChecked, 0}},
- {2740, {wxCommandEvent, isSelection, 0}},
- {2741, {wxCommandEvent, setInt, 1}},
- {2742, {wxCommandEvent, setString, 1}},
- {2743, {wxScrollEvent, getOrientation, 0}},
- {2744, {wxScrollEvent, getPosition, 0}},
- {2745, {wxScrollWinEvent, getOrientation, 0}},
- {2746, {wxScrollWinEvent, getPosition, 0}},
- {2747, {wxMouseEvent, altDown, 0}},
- {2748, {wxMouseEvent, button, 1}},
- {2749, {wxMouseEvent, buttonDClick, 1}},
- {2750, {wxMouseEvent, buttonDown, 1}},
- {2751, {wxMouseEvent, buttonUp, 1}},
- {2752, {wxMouseEvent, cmdDown, 0}},
- {2753, {wxMouseEvent, controlDown, 0}},
- {2754, {wxMouseEvent, dragging, 0}},
- {2755, {wxMouseEvent, entering, 0}},
- {2756, {wxMouseEvent, getButton, 0}},
- {2759, {wxMouseEvent, getPosition, 0}},
- {2760, {wxMouseEvent, getLogicalPosition, 1}},
- {2761, {wxMouseEvent, getLinesPerAction, 0}},
- {2762, {wxMouseEvent, getWheelRotation, 0}},
- {2763, {wxMouseEvent, getWheelDelta, 0}},
- {2764, {wxMouseEvent, getX, 0}},
- {2765, {wxMouseEvent, getY, 0}},
- {2766, {wxMouseEvent, isButton, 0}},
- {2767, {wxMouseEvent, isPageScroll, 0}},
- {2768, {wxMouseEvent, leaving, 0}},
- {2769, {wxMouseEvent, leftDClick, 0}},
- {2770, {wxMouseEvent, leftDown, 0}},
- {2771, {wxMouseEvent, leftIsDown, 0}},
- {2772, {wxMouseEvent, leftUp, 0}},
- {2773, {wxMouseEvent, metaDown, 0}},
- {2774, {wxMouseEvent, middleDClick, 0}},
- {2775, {wxMouseEvent, middleDown, 0}},
- {2776, {wxMouseEvent, middleIsDown, 0}},
- {2777, {wxMouseEvent, middleUp, 0}},
- {2778, {wxMouseEvent, moving, 0}},
- {2779, {wxMouseEvent, rightDClick, 0}},
- {2780, {wxMouseEvent, rightDown, 0}},
- {2781, {wxMouseEvent, rightIsDown, 0}},
- {2782, {wxMouseEvent, rightUp, 0}},
- {2783, {wxMouseEvent, shiftDown, 0}},
- {2784, {wxSetCursorEvent, getCursor, 0}},
- {2785, {wxSetCursorEvent, getX, 0}},
- {2786, {wxSetCursorEvent, getY, 0}},
- {2787, {wxSetCursorEvent, hasCursor, 0}},
- {2788, {wxSetCursorEvent, setCursor, 1}},
- {2789, {wxKeyEvent, altDown, 0}},
- {2790, {wxKeyEvent, cmdDown, 0}},
- {2791, {wxKeyEvent, controlDown, 0}},
- {2792, {wxKeyEvent, getKeyCode, 0}},
- {2793, {wxKeyEvent, getModifiers, 0}},
- {2796, {wxKeyEvent, getPosition, 0}},
- {2797, {wxKeyEvent, getRawKeyCode, 0}},
- {2798, {wxKeyEvent, getRawKeyFlags, 0}},
- {2799, {wxKeyEvent, getUnicodeKey, 0}},
- {2800, {wxKeyEvent, getX, 0}},
- {2801, {wxKeyEvent, getY, 0}},
- {2802, {wxKeyEvent, hasModifiers, 0}},
- {2803, {wxKeyEvent, metaDown, 0}},
- {2804, {wxKeyEvent, shiftDown, 0}},
- {2805, {wxSizeEvent, getSize, 0}},
- {2806, {wxMoveEvent, getPosition, 0}},
- {2807, {wxEraseEvent, getDC, 0}},
- {2808, {wxFocusEvent, getWindow, 0}},
- {2809, {wxChildFocusEvent, getWindow, 0}},
- {2810, {wxMenuEvent, getMenu, 0}},
- {2811, {wxMenuEvent, getMenuId, 0}},
- {2812, {wxMenuEvent, isPopup, 0}},
- {2813, {wxCloseEvent, canVeto, 0}},
- {2814, {wxCloseEvent, getLoggingOff, 0}},
- {2815, {wxCloseEvent, setCanVeto, 1}},
- {2816, {wxCloseEvent, setLoggingOff, 1}},
- {2817, {wxCloseEvent, veto, 1}},
- {2818, {wxShowEvent, setShow, 1}},
- {2819, {wxShowEvent, getShow, 0}},
- {2820, {wxIconizeEvent, iconized, 0}},
- {2821, {wxJoystickEvent, buttonDown, 1}},
- {2822, {wxJoystickEvent, buttonIsDown, 1}},
- {2823, {wxJoystickEvent, buttonUp, 1}},
- {2824, {wxJoystickEvent, getButtonChange, 0}},
- {2825, {wxJoystickEvent, getButtonState, 0}},
- {2826, {wxJoystickEvent, getJoystick, 0}},
- {2827, {wxJoystickEvent, getPosition, 0}},
- {2828, {wxJoystickEvent, getZPosition, 0}},
- {2829, {wxJoystickEvent, isButton, 0}},
- {2830, {wxJoystickEvent, isMove, 0}},
- {2831, {wxJoystickEvent, isZMove, 0}},
- {2832, {wxUpdateUIEvent, canUpdate, 1}},
- {2833, {wxUpdateUIEvent, check, 1}},
- {2834, {wxUpdateUIEvent, enable, 1}},
- {2835, {wxUpdateUIEvent, show, 1}},
- {2836, {wxUpdateUIEvent, getChecked, 0}},
- {2837, {wxUpdateUIEvent, getEnabled, 0}},
- {2838, {wxUpdateUIEvent, getShown, 0}},
- {2839, {wxUpdateUIEvent, getSetChecked, 0}},
- {2840, {wxUpdateUIEvent, getSetEnabled, 0}},
- {2841, {wxUpdateUIEvent, getSetShown, 0}},
- {2842, {wxUpdateUIEvent, getSetText, 0}},
- {2843, {wxUpdateUIEvent, getText, 0}},
- {2844, {wxUpdateUIEvent, getMode, 0}},
- {2845, {wxUpdateUIEvent, getUpdateInterval, 0}},
- {2846, {wxUpdateUIEvent, resetUpdateTime, 0}},
- {2847, {wxUpdateUIEvent, setMode, 1}},
- {2848, {wxUpdateUIEvent, setText, 1}},
- {2849, {wxUpdateUIEvent, setUpdateInterval, 1}},
- {2850, {wxMouseCaptureChangedEvent, getCapturedWindow, 0}},
- {2851, {wxPaletteChangedEvent, setChangedWindow, 1}},
- {2852, {wxPaletteChangedEvent, getChangedWindow, 0}},
- {2853, {wxQueryNewPaletteEvent, setPaletteRealized, 1}},
- {2854, {wxQueryNewPaletteEvent, getPaletteRealized, 0}},
- {2855, {wxNavigationKeyEvent, getDirection, 0}},
- {2856, {wxNavigationKeyEvent, setDirection, 1}},
- {2857, {wxNavigationKeyEvent, isWindowChange, 0}},
- {2858, {wxNavigationKeyEvent, setWindowChange, 1}},
- {2859, {wxNavigationKeyEvent, isFromTab, 0}},
- {2860, {wxNavigationKeyEvent, setFromTab, 1}},
- {2861, {wxNavigationKeyEvent, getCurrentFocus, 0}},
- {2862, {wxNavigationKeyEvent, setCurrentFocus, 1}},
- {2863, {wxHelpEvent, getOrigin, 0}},
- {2864, {wxHelpEvent, getPosition, 0}},
- {2865, {wxHelpEvent, setOrigin, 1}},
- {2866, {wxHelpEvent, setPosition, 1}},
- {2867, {wxContextMenuEvent, getPosition, 0}},
- {2868, {wxContextMenuEvent, setPosition, 1}},
- {2869, {wxIdleEvent, canSend, 1}},
- {2870, {wxIdleEvent, getMode, 0}},
- {2871, {wxIdleEvent, requestMore, 1}},
- {2872, {wxIdleEvent, moreRequested, 0}},
- {2873, {wxIdleEvent, setMode, 1}},
- {2874, {wxGridEvent, altDown, 0}},
- {2875, {wxGridEvent, controlDown, 0}},
- {2876, {wxGridEvent, getCol, 0}},
- {2877, {wxGridEvent, getPosition, 0}},
- {2878, {wxGridEvent, getRow, 0}},
- {2879, {wxGridEvent, metaDown, 0}},
- {2880, {wxGridEvent, selecting, 0}},
- {2881, {wxGridEvent, shiftDown, 0}},
- {2882, {wxNotifyEvent, allow, 0}},
- {2883, {wxNotifyEvent, isAllowed, 0}},
- {2884, {wxNotifyEvent, veto, 0}},
- {2885, {wxSashEvent, getEdge, 0}},
- {2886, {wxSashEvent, getDragRect, 0}},
- {2887, {wxSashEvent, getDragStatus, 0}},
- {2888, {wxListEvent, getCacheFrom, 0}},
- {2889, {wxListEvent, getCacheTo, 0}},
- {2890, {wxListEvent, getKeyCode, 0}},
- {2891, {wxListEvent, getIndex, 0}},
- {2892, {wxListEvent, getColumn, 0}},
- {2893, {wxListEvent, getPoint, 0}},
- {2894, {wxListEvent, getLabel, 0}},
- {2895, {wxListEvent, getText, 0}},
- {2896, {wxListEvent, getImage, 0}},
- {2897, {wxListEvent, getData, 0}},
- {2898, {wxListEvent, getMask, 0}},
- {2899, {wxListEvent, getItem, 0}},
- {2900, {wxListEvent, isEditCancelled, 0}},
- {2901, {wxDateEvent, getDate, 0}},
- {2902, {wxCalendarEvent, getWeekDay, 0}},
- {2903, {wxFileDirPickerEvent, getPath, 0}},
- {2904, {wxColourPickerEvent, getColour, 0}},
- {2905, {wxFontPickerEvent, getFont, 0}},
- {2906, {wxStyledTextEvent, getPosition, 0}},
- {2907, {wxStyledTextEvent, getKey, 0}},
- {2908, {wxStyledTextEvent, getModifiers, 0}},
- {2909, {wxStyledTextEvent, getModificationType, 0}},
- {2910, {wxStyledTextEvent, getText, 0}},
- {2911, {wxStyledTextEvent, getLength, 0}},
- {2912, {wxStyledTextEvent, getLinesAdded, 0}},
- {2913, {wxStyledTextEvent, getLine, 0}},
- {2914, {wxStyledTextEvent, getFoldLevelNow, 0}},
- {2915, {wxStyledTextEvent, getFoldLevelPrev, 0}},
- {2916, {wxStyledTextEvent, getMargin, 0}},
- {2917, {wxStyledTextEvent, getMessage, 0}},
- {2918, {wxStyledTextEvent, getWParam, 0}},
- {2919, {wxStyledTextEvent, getLParam, 0}},
- {2920, {wxStyledTextEvent, getListType, 0}},
- {2921, {wxStyledTextEvent, getX, 0}},
- {2922, {wxStyledTextEvent, getY, 0}},
- {2923, {wxStyledTextEvent, getDragText, 0}},
- {2924, {wxStyledTextEvent, getDragAllowMove, 0}},
- {2925, {wxStyledTextEvent, getDragResult, 0}},
- {2926, {wxStyledTextEvent, getShift, 0}},
- {2927, {wxStyledTextEvent, getControl, 0}},
- {2928, {wxStyledTextEvent, getAlt, 0}},
- {2929, {utils, getKeyState, 1}},
- {2930, {utils, getMousePosition, 2}},
- {2931, {utils, getMouseState, 0}},
- {2932, {utils, setDetectableAutoRepeat, 1}},
- {2933, {utils, bell, 0}},
- {2934, {utils, findMenuItemId, 3}},
- {2935, {utils, genericFindWindowAtPoint, 1}},
- {2936, {utils, findWindowAtPoint, 1}},
- {2937, {utils, beginBusyCursor, 1}},
- {2938, {utils, endBusyCursor, 0}},
- {2939, {utils, isBusy, 0}},
- {2940, {utils, shutdown, 1}},
- {2941, {utils, shell, 1}},
- {2942, {utils, launchDefaultBrowser, 2}},
- {2943, {utils, getEmailAddress, 0}},
- {2944, {utils, getUserId, 0}},
- {2945, {utils, getHomeDir, 0}},
- {2946, {utils, newId, 0}},
- {2947, {utils, registerId, 1}},
- {2948, {utils, getCurrentId, 0}},
- {2949, {utils, getOsDescription, 0}},
- {2950, {utils, isPlatformLittleEndian, 0}},
- {2951, {utils, isPlatform64Bit, 0}},
- {2952, {gdicmn, displaySize, 2}},
- {2953, {gdicmn, setCursor, 1}},
- {2954, {wxPrintout, new, 1}},
- {2955, {wxPrintout, destruct, 0}},
- {2956, {wxPrintout, getDC, 0}},
- {2957, {wxPrintout, getPageSizeMM, 2}},
- {2958, {wxPrintout, getPageSizePixels, 2}},
- {2959, {wxPrintout, getPaperRectPixels, 0}},
- {2960, {wxPrintout, getPPIPrinter, 2}},
- {2961, {wxPrintout, getPPIScreen, 2}},
- {2962, {wxPrintout, getTitle, 0}},
- {2963, {wxPrintout, isPreview, 0}},
- {2964, {wxPrintout, fitThisSizeToPaper, 1}},
- {2965, {wxPrintout, fitThisSizeToPage, 1}},
- {2966, {wxPrintout, fitThisSizeToPageMargins, 2}},
- {2967, {wxPrintout, mapScreenSizeToPaper, 0}},
- {2968, {wxPrintout, mapScreenSizeToPage, 0}},
- {2969, {wxPrintout, mapScreenSizeToPageMargins, 1}},
- {2970, {wxPrintout, mapScreenSizeToDevice, 0}},
- {2971, {wxPrintout, getLogicalPaperRect, 0}},
- {2972, {wxPrintout, getLogicalPageRect, 0}},
- {2973, {wxPrintout, getLogicalPageMarginsRect, 1}},
- {2974, {wxPrintout, setLogicalOrigin, 2}},
- {2975, {wxPrintout, offsetLogicalOrigin, 2}},
- {2976, {wxStyledTextCtrl, new_2, 2}},
- {2977, {wxStyledTextCtrl, new_0, 0}},
- {2978, {wxStyledTextCtrl, destruct, 0}},
- {2979, {wxStyledTextCtrl, create, 2}},
- {2980, {wxStyledTextCtrl, addText, 1}},
- {2981, {wxStyledTextCtrl, addStyledText, 1}},
- {2982, {wxStyledTextCtrl, insertText, 2}},
- {2983, {wxStyledTextCtrl, clearAll, 0}},
- {2984, {wxStyledTextCtrl, clearDocumentStyle, 0}},
- {2985, {wxStyledTextCtrl, getLength, 0}},
- {2986, {wxStyledTextCtrl, getCharAt, 1}},
- {2987, {wxStyledTextCtrl, getCurrentPos, 0}},
- {2988, {wxStyledTextCtrl, getAnchor, 0}},
- {2989, {wxStyledTextCtrl, getStyleAt, 1}},
- {2990, {wxStyledTextCtrl, redo, 0}},
- {2991, {wxStyledTextCtrl, setUndoCollection, 1}},
- {2992, {wxStyledTextCtrl, selectAll, 0}},
- {2993, {wxStyledTextCtrl, setSavePoint, 0}},
- {2994, {wxStyledTextCtrl, getStyledText, 2}},
- {2995, {wxStyledTextCtrl, canRedo, 0}},
- {2996, {wxStyledTextCtrl, markerLineFromHandle, 1}},
- {2997, {wxStyledTextCtrl, markerDeleteHandle, 1}},
- {2998, {wxStyledTextCtrl, getUndoCollection, 0}},
- {2999, {wxStyledTextCtrl, getViewWhiteSpace, 0}},
- {3000, {wxStyledTextCtrl, setViewWhiteSpace, 1}},
- {3001, {wxStyledTextCtrl, positionFromPoint, 1}},
- {3002, {wxStyledTextCtrl, positionFromPointClose, 2}},
- {3003, {wxStyledTextCtrl, gotoLine, 1}},
- {3004, {wxStyledTextCtrl, gotoPos, 1}},
- {3005, {wxStyledTextCtrl, setAnchor, 1}},
- {3006, {wxStyledTextCtrl, getCurLine, 1}},
- {3007, {wxStyledTextCtrl, getEndStyled, 0}},
- {3008, {wxStyledTextCtrl, convertEOLs, 1}},
- {3009, {wxStyledTextCtrl, getEOLMode, 0}},
- {3010, {wxStyledTextCtrl, setEOLMode, 1}},
- {3011, {wxStyledTextCtrl, startStyling, 2}},
- {3012, {wxStyledTextCtrl, setStyling, 2}},
- {3013, {wxStyledTextCtrl, getBufferedDraw, 0}},
- {3014, {wxStyledTextCtrl, setBufferedDraw, 1}},
- {3015, {wxStyledTextCtrl, setTabWidth, 1}},
- {3016, {wxStyledTextCtrl, getTabWidth, 0}},
- {3017, {wxStyledTextCtrl, setCodePage, 1}},
- {3018, {wxStyledTextCtrl, markerDefine, 3}},
- {3019, {wxStyledTextCtrl, markerSetForeground, 2}},
- {3020, {wxStyledTextCtrl, markerSetBackground, 2}},
- {3021, {wxStyledTextCtrl, markerAdd, 2}},
- {3022, {wxStyledTextCtrl, markerDelete, 2}},
- {3023, {wxStyledTextCtrl, markerDeleteAll, 1}},
- {3024, {wxStyledTextCtrl, markerGet, 1}},
- {3025, {wxStyledTextCtrl, markerNext, 2}},
- {3026, {wxStyledTextCtrl, markerPrevious, 2}},
- {3027, {wxStyledTextCtrl, markerDefineBitmap, 2}},
- {3028, {wxStyledTextCtrl, markerAddSet, 2}},
- {3029, {wxStyledTextCtrl, markerSetAlpha, 2}},
- {3030, {wxStyledTextCtrl, setMarginType, 2}},
- {3031, {wxStyledTextCtrl, getMarginType, 1}},
- {3032, {wxStyledTextCtrl, setMarginWidth, 2}},
- {3033, {wxStyledTextCtrl, getMarginWidth, 1}},
- {3034, {wxStyledTextCtrl, setMarginMask, 2}},
- {3035, {wxStyledTextCtrl, getMarginMask, 1}},
- {3036, {wxStyledTextCtrl, setMarginSensitive, 2}},
- {3037, {wxStyledTextCtrl, getMarginSensitive, 1}},
- {3038, {wxStyledTextCtrl, styleClearAll, 0}},
- {3039, {wxStyledTextCtrl, styleSetForeground, 2}},
- {3040, {wxStyledTextCtrl, styleSetBackground, 2}},
- {3041, {wxStyledTextCtrl, styleSetBold, 2}},
- {3042, {wxStyledTextCtrl, styleSetItalic, 2}},
- {3043, {wxStyledTextCtrl, styleSetSize, 2}},
- {3044, {wxStyledTextCtrl, styleSetFaceName, 2}},
- {3045, {wxStyledTextCtrl, styleSetEOLFilled, 2}},
- {3046, {wxStyledTextCtrl, styleResetDefault, 0}},
- {3047, {wxStyledTextCtrl, styleSetUnderline, 2}},
- {3048, {wxStyledTextCtrl, styleSetCase, 2}},
- {3049, {wxStyledTextCtrl, styleSetHotSpot, 2}},
- {3050, {wxStyledTextCtrl, setSelForeground, 2}},
- {3051, {wxStyledTextCtrl, setSelBackground, 2}},
- {3052, {wxStyledTextCtrl, getSelAlpha, 0}},
- {3053, {wxStyledTextCtrl, setSelAlpha, 1}},
- {3054, {wxStyledTextCtrl, setCaretForeground, 1}},
- {3055, {wxStyledTextCtrl, cmdKeyAssign, 3}},
- {3056, {wxStyledTextCtrl, cmdKeyClear, 2}},
- {3057, {wxStyledTextCtrl, cmdKeyClearAll, 0}},
- {3058, {wxStyledTextCtrl, setStyleBytes, 2}},
- {3059, {wxStyledTextCtrl, styleSetVisible, 2}},
- {3060, {wxStyledTextCtrl, getCaretPeriod, 0}},
- {3061, {wxStyledTextCtrl, setCaretPeriod, 1}},
- {3062, {wxStyledTextCtrl, setWordChars, 1}},
- {3063, {wxStyledTextCtrl, beginUndoAction, 0}},
- {3064, {wxStyledTextCtrl, endUndoAction, 0}},
- {3065, {wxStyledTextCtrl, indicatorSetStyle, 2}},
- {3066, {wxStyledTextCtrl, indicatorGetStyle, 1}},
- {3067, {wxStyledTextCtrl, indicatorSetForeground, 2}},
- {3068, {wxStyledTextCtrl, indicatorGetForeground, 1}},
- {3069, {wxStyledTextCtrl, setWhitespaceForeground, 2}},
- {3070, {wxStyledTextCtrl, setWhitespaceBackground, 2}},
- {3071, {wxStyledTextCtrl, getStyleBits, 0}},
- {3072, {wxStyledTextCtrl, setLineState, 2}},
- {3073, {wxStyledTextCtrl, getLineState, 1}},
- {3074, {wxStyledTextCtrl, getMaxLineState, 0}},
- {3075, {wxStyledTextCtrl, getCaretLineVisible, 0}},
- {3076, {wxStyledTextCtrl, setCaretLineVisible, 1}},
- {3077, {wxStyledTextCtrl, getCaretLineBackground, 0}},
- {3078, {wxStyledTextCtrl, setCaretLineBackground, 1}},
- {3079, {wxStyledTextCtrl, autoCompShow, 2}},
- {3080, {wxStyledTextCtrl, autoCompCancel, 0}},
- {3081, {wxStyledTextCtrl, autoCompActive, 0}},
- {3082, {wxStyledTextCtrl, autoCompPosStart, 0}},
- {3083, {wxStyledTextCtrl, autoCompComplete, 0}},
- {3084, {wxStyledTextCtrl, autoCompStops, 1}},
- {3085, {wxStyledTextCtrl, autoCompSetSeparator, 1}},
- {3086, {wxStyledTextCtrl, autoCompGetSeparator, 0}},
- {3087, {wxStyledTextCtrl, autoCompSelect, 1}},
- {3088, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}},
- {3089, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}},
- {3090, {wxStyledTextCtrl, autoCompSetFillUps, 1}},
- {3091, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}},
- {3092, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}},
- {3093, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}},
- {3094, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}},
- {3095, {wxStyledTextCtrl, userListShow, 2}},
- {3096, {wxStyledTextCtrl, autoCompSetAutoHide, 1}},
- {3097, {wxStyledTextCtrl, autoCompGetAutoHide, 0}},
- {3098, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}},
- {3099, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}},
- {3100, {wxStyledTextCtrl, registerImage, 2}},
- {3101, {wxStyledTextCtrl, clearRegisteredImages, 0}},
- {3102, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}},
- {3103, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}},
- {3104, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}},
- {3105, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}},
- {3106, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}},
- {3107, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}},
- {3108, {wxStyledTextCtrl, setIndent, 1}},
- {3109, {wxStyledTextCtrl, getIndent, 0}},
- {3110, {wxStyledTextCtrl, setUseTabs, 1}},
- {3111, {wxStyledTextCtrl, getUseTabs, 0}},
- {3112, {wxStyledTextCtrl, setLineIndentation, 2}},
- {3113, {wxStyledTextCtrl, getLineIndentation, 1}},
- {3114, {wxStyledTextCtrl, getLineIndentPosition, 1}},
- {3115, {wxStyledTextCtrl, getColumn, 1}},
- {3116, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}},
- {3117, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}},
- {3118, {wxStyledTextCtrl, setIndentationGuides, 1}},
- {3119, {wxStyledTextCtrl, getIndentationGuides, 0}},
- {3120, {wxStyledTextCtrl, setHighlightGuide, 1}},
- {3121, {wxStyledTextCtrl, getHighlightGuide, 0}},
- {3122, {wxStyledTextCtrl, getLineEndPosition, 1}},
- {3123, {wxStyledTextCtrl, getCodePage, 0}},
- {3124, {wxStyledTextCtrl, getCaretForeground, 0}},
- {3125, {wxStyledTextCtrl, getReadOnly, 0}},
- {3126, {wxStyledTextCtrl, setCurrentPos, 1}},
- {3127, {wxStyledTextCtrl, setSelectionStart, 1}},
- {3128, {wxStyledTextCtrl, getSelectionStart, 0}},
- {3129, {wxStyledTextCtrl, setSelectionEnd, 1}},
- {3130, {wxStyledTextCtrl, getSelectionEnd, 0}},
- {3131, {wxStyledTextCtrl, setPrintMagnification, 1}},
- {3132, {wxStyledTextCtrl, getPrintMagnification, 0}},
- {3133, {wxStyledTextCtrl, setPrintColourMode, 1}},
- {3134, {wxStyledTextCtrl, getPrintColourMode, 0}},
- {3135, {wxStyledTextCtrl, findText, 4}},
- {3136, {wxStyledTextCtrl, formatRange, 7}},
- {3137, {wxStyledTextCtrl, getFirstVisibleLine, 0}},
- {3138, {wxStyledTextCtrl, getLine, 1}},
- {3139, {wxStyledTextCtrl, getLineCount, 0}},
- {3140, {wxStyledTextCtrl, setMarginLeft, 1}},
- {3141, {wxStyledTextCtrl, getMarginLeft, 0}},
- {3142, {wxStyledTextCtrl, setMarginRight, 1}},
- {3143, {wxStyledTextCtrl, getMarginRight, 0}},
- {3144, {wxStyledTextCtrl, getModify, 0}},
- {3145, {wxStyledTextCtrl, setSelection, 2}},
- {3146, {wxStyledTextCtrl, getSelectedText, 0}},
- {3147, {wxStyledTextCtrl, getTextRange, 2}},
- {3148, {wxStyledTextCtrl, hideSelection, 1}},
- {3149, {wxStyledTextCtrl, lineFromPosition, 1}},
- {3150, {wxStyledTextCtrl, positionFromLine, 1}},
- {3151, {wxStyledTextCtrl, lineScroll, 2}},
- {3152, {wxStyledTextCtrl, ensureCaretVisible, 0}},
- {3153, {wxStyledTextCtrl, replaceSelection, 1}},
- {3154, {wxStyledTextCtrl, setReadOnly, 1}},
- {3155, {wxStyledTextCtrl, canPaste, 0}},
- {3156, {wxStyledTextCtrl, canUndo, 0}},
- {3157, {wxStyledTextCtrl, emptyUndoBuffer, 0}},
- {3158, {wxStyledTextCtrl, undo, 0}},
- {3159, {wxStyledTextCtrl, cut, 0}},
- {3160, {wxStyledTextCtrl, copy, 0}},
- {3161, {wxStyledTextCtrl, paste, 0}},
- {3162, {wxStyledTextCtrl, clear, 0}},
- {3163, {wxStyledTextCtrl, setText, 1}},
- {3164, {wxStyledTextCtrl, getText, 0}},
- {3165, {wxStyledTextCtrl, getTextLength, 0}},
- {3166, {wxStyledTextCtrl, getOvertype, 0}},
- {3167, {wxStyledTextCtrl, setCaretWidth, 1}},
- {3168, {wxStyledTextCtrl, getCaretWidth, 0}},
- {3169, {wxStyledTextCtrl, setTargetStart, 1}},
- {3170, {wxStyledTextCtrl, getTargetStart, 0}},
- {3171, {wxStyledTextCtrl, setTargetEnd, 1}},
- {3172, {wxStyledTextCtrl, getTargetEnd, 0}},
- {3173, {wxStyledTextCtrl, replaceTarget, 1}},
- {3174, {wxStyledTextCtrl, searchInTarget, 1}},
- {3175, {wxStyledTextCtrl, setSearchFlags, 1}},
- {3176, {wxStyledTextCtrl, getSearchFlags, 0}},
- {3177, {wxStyledTextCtrl, callTipShow, 2}},
- {3178, {wxStyledTextCtrl, callTipCancel, 0}},
- {3179, {wxStyledTextCtrl, callTipActive, 0}},
- {3180, {wxStyledTextCtrl, callTipPosAtStart, 0}},
- {3181, {wxStyledTextCtrl, callTipSetHighlight, 2}},
- {3182, {wxStyledTextCtrl, callTipSetBackground, 1}},
- {3183, {wxStyledTextCtrl, callTipSetForeground, 1}},
- {3184, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}},
- {3185, {wxStyledTextCtrl, callTipUseStyle, 1}},
- {3186, {wxStyledTextCtrl, visibleFromDocLine, 1}},
- {3187, {wxStyledTextCtrl, docLineFromVisible, 1}},
- {3188, {wxStyledTextCtrl, wrapCount, 1}},
- {3189, {wxStyledTextCtrl, setFoldLevel, 2}},
- {3190, {wxStyledTextCtrl, getFoldLevel, 1}},
- {3191, {wxStyledTextCtrl, getLastChild, 2}},
- {3192, {wxStyledTextCtrl, getFoldParent, 1}},
- {3193, {wxStyledTextCtrl, showLines, 2}},
- {3194, {wxStyledTextCtrl, hideLines, 2}},
- {3195, {wxStyledTextCtrl, getLineVisible, 1}},
- {3196, {wxStyledTextCtrl, setFoldExpanded, 2}},
- {3197, {wxStyledTextCtrl, getFoldExpanded, 1}},
- {3198, {wxStyledTextCtrl, toggleFold, 1}},
- {3199, {wxStyledTextCtrl, ensureVisible, 1}},
- {3200, {wxStyledTextCtrl, setFoldFlags, 1}},
- {3201, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}},
- {3202, {wxStyledTextCtrl, setTabIndents, 1}},
- {3203, {wxStyledTextCtrl, getTabIndents, 0}},
- {3204, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}},
- {3205, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}},
- {3206, {wxStyledTextCtrl, setMouseDwellTime, 1}},
- {3207, {wxStyledTextCtrl, getMouseDwellTime, 0}},
- {3208, {wxStyledTextCtrl, wordStartPosition, 2}},
- {3209, {wxStyledTextCtrl, wordEndPosition, 2}},
- {3210, {wxStyledTextCtrl, setWrapMode, 1}},
- {3211, {wxStyledTextCtrl, getWrapMode, 0}},
- {3212, {wxStyledTextCtrl, setWrapVisualFlags, 1}},
- {3213, {wxStyledTextCtrl, getWrapVisualFlags, 0}},
- {3214, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}},
- {3215, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}},
- {3216, {wxStyledTextCtrl, setWrapStartIndent, 1}},
- {3217, {wxStyledTextCtrl, getWrapStartIndent, 0}},
- {3218, {wxStyledTextCtrl, setLayoutCache, 1}},
- {3219, {wxStyledTextCtrl, getLayoutCache, 0}},
- {3220, {wxStyledTextCtrl, setScrollWidth, 1}},
- {3221, {wxStyledTextCtrl, getScrollWidth, 0}},
- {3222, {wxStyledTextCtrl, textWidth, 2}},
- {3223, {wxStyledTextCtrl, getEndAtLastLine, 0}},
- {3224, {wxStyledTextCtrl, textHeight, 1}},
- {3225, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}},
- {3226, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}},
- {3227, {wxStyledTextCtrl, appendText, 1}},
- {3228, {wxStyledTextCtrl, getTwoPhaseDraw, 0}},
- {3229, {wxStyledTextCtrl, setTwoPhaseDraw, 1}},
- {3230, {wxStyledTextCtrl, targetFromSelection, 0}},
- {3231, {wxStyledTextCtrl, linesJoin, 0}},
- {3232, {wxStyledTextCtrl, linesSplit, 1}},
- {3233, {wxStyledTextCtrl, setFoldMarginColour, 2}},
- {3234, {wxStyledTextCtrl, setFoldMarginHiColour, 2}},
- {3235, {wxStyledTextCtrl, lineDown, 0}},
- {3236, {wxStyledTextCtrl, lineDownExtend, 0}},
- {3237, {wxStyledTextCtrl, lineUp, 0}},
- {3238, {wxStyledTextCtrl, lineUpExtend, 0}},
- {3239, {wxStyledTextCtrl, charLeft, 0}},
- {3240, {wxStyledTextCtrl, charLeftExtend, 0}},
- {3241, {wxStyledTextCtrl, charRight, 0}},
- {3242, {wxStyledTextCtrl, charRightExtend, 0}},
- {3243, {wxStyledTextCtrl, wordLeft, 0}},
- {3244, {wxStyledTextCtrl, wordLeftExtend, 0}},
- {3245, {wxStyledTextCtrl, wordRight, 0}},
- {3246, {wxStyledTextCtrl, wordRightExtend, 0}},
- {3247, {wxStyledTextCtrl, home, 0}},
- {3248, {wxStyledTextCtrl, homeExtend, 0}},
- {3249, {wxStyledTextCtrl, lineEnd, 0}},
- {3250, {wxStyledTextCtrl, lineEndExtend, 0}},
- {3251, {wxStyledTextCtrl, documentStart, 0}},
- {3252, {wxStyledTextCtrl, documentStartExtend, 0}},
- {3253, {wxStyledTextCtrl, documentEnd, 0}},
- {3254, {wxStyledTextCtrl, documentEndExtend, 0}},
- {3255, {wxStyledTextCtrl, pageUp, 0}},
- {3256, {wxStyledTextCtrl, pageUpExtend, 0}},
- {3257, {wxStyledTextCtrl, pageDown, 0}},
- {3258, {wxStyledTextCtrl, pageDownExtend, 0}},
- {3259, {wxStyledTextCtrl, editToggleOvertype, 0}},
- {3260, {wxStyledTextCtrl, cancel, 0}},
- {3261, {wxStyledTextCtrl, deleteBack, 0}},
- {3262, {wxStyledTextCtrl, tab, 0}},
- {3263, {wxStyledTextCtrl, backTab, 0}},
- {3264, {wxStyledTextCtrl, newLine, 0}},
- {3265, {wxStyledTextCtrl, formFeed, 0}},
- {3266, {wxStyledTextCtrl, vCHome, 0}},
- {3267, {wxStyledTextCtrl, vCHomeExtend, 0}},
- {3268, {wxStyledTextCtrl, zoomIn, 0}},
- {3269, {wxStyledTextCtrl, zoomOut, 0}},
- {3270, {wxStyledTextCtrl, delWordLeft, 0}},
- {3271, {wxStyledTextCtrl, delWordRight, 0}},
- {3272, {wxStyledTextCtrl, lineCut, 0}},
- {3273, {wxStyledTextCtrl, lineDelete, 0}},
- {3274, {wxStyledTextCtrl, lineTranspose, 0}},
- {3275, {wxStyledTextCtrl, lineDuplicate, 0}},
- {3276, {wxStyledTextCtrl, lowerCase, 0}},
- {3277, {wxStyledTextCtrl, upperCase, 0}},
- {3278, {wxStyledTextCtrl, lineScrollDown, 0}},
- {3279, {wxStyledTextCtrl, lineScrollUp, 0}},
- {3280, {wxStyledTextCtrl, deleteBackNotLine, 0}},
- {3281, {wxStyledTextCtrl, homeDisplay, 0}},
- {3282, {wxStyledTextCtrl, homeDisplayExtend, 0}},
- {3283, {wxStyledTextCtrl, lineEndDisplay, 0}},
- {3284, {wxStyledTextCtrl, lineEndDisplayExtend, 0}},
- {3285, {wxStyledTextCtrl, homeWrapExtend, 0}},
- {3286, {wxStyledTextCtrl, lineEndWrap, 0}},
- {3287, {wxStyledTextCtrl, lineEndWrapExtend, 0}},
- {3288, {wxStyledTextCtrl, vCHomeWrap, 0}},
- {3289, {wxStyledTextCtrl, vCHomeWrapExtend, 0}},
- {3290, {wxStyledTextCtrl, lineCopy, 0}},
- {3291, {wxStyledTextCtrl, moveCaretInsideView, 0}},
- {3292, {wxStyledTextCtrl, lineLength, 1}},
- {3293, {wxStyledTextCtrl, braceHighlight, 2}},
- {3294, {wxStyledTextCtrl, braceBadLight, 1}},
- {3295, {wxStyledTextCtrl, braceMatch, 1}},
- {3296, {wxStyledTextCtrl, getViewEOL, 0}},
- {3297, {wxStyledTextCtrl, setViewEOL, 1}},
- {3298, {wxStyledTextCtrl, setModEventMask, 1}},
- {3299, {wxStyledTextCtrl, getEdgeColumn, 0}},
- {3300, {wxStyledTextCtrl, setEdgeColumn, 1}},
- {3301, {wxStyledTextCtrl, setEdgeMode, 1}},
- {3302, {wxStyledTextCtrl, getEdgeMode, 0}},
- {3303, {wxStyledTextCtrl, getEdgeColour, 0}},
- {3304, {wxStyledTextCtrl, setEdgeColour, 1}},
- {3305, {wxStyledTextCtrl, searchAnchor, 0}},
- {3306, {wxStyledTextCtrl, searchNext, 2}},
- {3307, {wxStyledTextCtrl, searchPrev, 2}},
- {3308, {wxStyledTextCtrl, linesOnScreen, 0}},
- {3309, {wxStyledTextCtrl, usePopUp, 1}},
- {3310, {wxStyledTextCtrl, selectionIsRectangle, 0}},
- {3311, {wxStyledTextCtrl, setZoom, 1}},
- {3312, {wxStyledTextCtrl, getZoom, 0}},
- {3313, {wxStyledTextCtrl, getModEventMask, 0}},
- {3314, {wxStyledTextCtrl, setSTCFocus, 1}},
- {3315, {wxStyledTextCtrl, getSTCFocus, 0}},
- {3316, {wxStyledTextCtrl, setStatus, 1}},
- {3317, {wxStyledTextCtrl, getStatus, 0}},
- {3318, {wxStyledTextCtrl, setMouseDownCaptures, 1}},
- {3319, {wxStyledTextCtrl, getMouseDownCaptures, 0}},
- {3320, {wxStyledTextCtrl, setSTCCursor, 1}},
- {3321, {wxStyledTextCtrl, getSTCCursor, 0}},
- {3322, {wxStyledTextCtrl, setControlCharSymbol, 1}},
- {3323, {wxStyledTextCtrl, getControlCharSymbol, 0}},
- {3324, {wxStyledTextCtrl, wordPartLeft, 0}},
- {3325, {wxStyledTextCtrl, wordPartLeftExtend, 0}},
- {3326, {wxStyledTextCtrl, wordPartRight, 0}},
- {3327, {wxStyledTextCtrl, wordPartRightExtend, 0}},
- {3328, {wxStyledTextCtrl, setVisiblePolicy, 2}},
- {3329, {wxStyledTextCtrl, delLineLeft, 0}},
- {3330, {wxStyledTextCtrl, delLineRight, 0}},
- {3331, {wxStyledTextCtrl, getXOffset, 0}},
- {3332, {wxStyledTextCtrl, chooseCaretX, 0}},
- {3333, {wxStyledTextCtrl, setXCaretPolicy, 2}},
- {3334, {wxStyledTextCtrl, setYCaretPolicy, 2}},
- {3335, {wxStyledTextCtrl, getPrintWrapMode, 0}},
- {3336, {wxStyledTextCtrl, setHotspotActiveForeground, 2}},
- {3337, {wxStyledTextCtrl, setHotspotActiveBackground, 2}},
- {3338, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}},
- {3339, {wxStyledTextCtrl, setHotspotSingleLine, 1}},
- {3340, {wxStyledTextCtrl, paraDownExtend, 0}},
- {3341, {wxStyledTextCtrl, paraUp, 0}},
- {3342, {wxStyledTextCtrl, paraUpExtend, 0}},
- {3343, {wxStyledTextCtrl, positionBefore, 1}},
- {3344, {wxStyledTextCtrl, positionAfter, 1}},
- {3345, {wxStyledTextCtrl, copyRange, 2}},
- {3346, {wxStyledTextCtrl, copyText, 2}},
- {3347, {wxStyledTextCtrl, setSelectionMode, 1}},
- {3348, {wxStyledTextCtrl, getSelectionMode, 0}},
- {3349, {wxStyledTextCtrl, lineDownRectExtend, 0}},
- {3350, {wxStyledTextCtrl, lineUpRectExtend, 0}},
- {3351, {wxStyledTextCtrl, charLeftRectExtend, 0}},
- {3352, {wxStyledTextCtrl, charRightRectExtend, 0}},
- {3353, {wxStyledTextCtrl, homeRectExtend, 0}},
- {3354, {wxStyledTextCtrl, vCHomeRectExtend, 0}},
- {3355, {wxStyledTextCtrl, lineEndRectExtend, 0}},
- {3356, {wxStyledTextCtrl, pageUpRectExtend, 0}},
- {3357, {wxStyledTextCtrl, pageDownRectExtend, 0}},
- {3358, {wxStyledTextCtrl, stutteredPageUp, 0}},
- {3359, {wxStyledTextCtrl, stutteredPageUpExtend, 0}},
- {3360, {wxStyledTextCtrl, stutteredPageDown, 0}},
- {3361, {wxStyledTextCtrl, stutteredPageDownExtend, 0}},
- {3362, {wxStyledTextCtrl, wordLeftEnd, 0}},
- {3363, {wxStyledTextCtrl, wordLeftEndExtend, 0}},
- {3364, {wxStyledTextCtrl, wordRightEnd, 0}},
- {3365, {wxStyledTextCtrl, wordRightEndExtend, 0}},
- {3366, {wxStyledTextCtrl, setWhitespaceChars, 1}},
- {3367, {wxStyledTextCtrl, setCharsDefault, 0}},
- {3368, {wxStyledTextCtrl, autoCompGetCurrent, 0}},
- {3369, {wxStyledTextCtrl, allocate, 1}},
- {3370, {wxStyledTextCtrl, findColumn, 2}},
- {3371, {wxStyledTextCtrl, getCaretSticky, 0}},
- {3372, {wxStyledTextCtrl, setCaretSticky, 1}},
- {3373, {wxStyledTextCtrl, toggleCaretSticky, 0}},
- {3374, {wxStyledTextCtrl, setPasteConvertEndings, 1}},
- {3375, {wxStyledTextCtrl, getPasteConvertEndings, 0}},
- {3376, {wxStyledTextCtrl, selectionDuplicate, 0}},
- {3377, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}},
- {3378, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}},
- {3379, {wxStyledTextCtrl, startRecord, 0}},
- {3380, {wxStyledTextCtrl, stopRecord, 0}},
- {3381, {wxStyledTextCtrl, setLexer, 1}},
- {3382, {wxStyledTextCtrl, getLexer, 0}},
- {3383, {wxStyledTextCtrl, colourise, 2}},
- {3384, {wxStyledTextCtrl, setProperty, 2}},
- {3385, {wxStyledTextCtrl, setKeyWords, 2}},
- {3386, {wxStyledTextCtrl, setLexerLanguage, 1}},
- {3387, {wxStyledTextCtrl, getProperty, 1}},
- {3388, {wxStyledTextCtrl, getStyleBitsNeeded, 0}},
- {3389, {wxStyledTextCtrl, getCurrentLine, 0}},
- {3390, {wxStyledTextCtrl, styleSetSpec, 2}},
- {3391, {wxStyledTextCtrl, styleSetFont, 2}},
- {3392, {wxStyledTextCtrl, styleSetFontAttr, 7}},
- {3393, {wxStyledTextCtrl, styleSetCharacterSet, 2}},
- {3394, {wxStyledTextCtrl, styleSetFontEncoding, 2}},
- {3395, {wxStyledTextCtrl, cmdKeyExecute, 1}},
- {3396, {wxStyledTextCtrl, setMargins, 2}},
- {3397, {wxStyledTextCtrl, getSelection, 2}},
- {3398, {wxStyledTextCtrl, pointFromPosition, 1}},
- {3399, {wxStyledTextCtrl, scrollToLine, 1}},
- {3400, {wxStyledTextCtrl, scrollToColumn, 1}},
- {3401, {wxStyledTextCtrl, setVScrollBar, 1}},
- {3402, {wxStyledTextCtrl, setHScrollBar, 1}},
- {3403, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
- {3404, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
- {3405, {wxStyledTextCtrl, saveFile, 1}},
- {3406, {wxStyledTextCtrl, loadFile, 1}},
- {3407, {wxStyledTextCtrl, doDragOver, 3}},
- {3408, {wxStyledTextCtrl, doDropText, 3}},
- {3409, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
- {3410, {wxStyledTextCtrl, addTextRaw, 1}},
- {3411, {wxStyledTextCtrl, insertTextRaw, 2}},
- {3412, {wxStyledTextCtrl, getCurLineRaw, 1}},
- {3413, {wxStyledTextCtrl, getLineRaw, 1}},
- {3414, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
- {3415, {wxStyledTextCtrl, getTextRangeRaw, 2}},
- {3416, {wxStyledTextCtrl, setTextRaw, 1}},
- {3417, {wxStyledTextCtrl, getTextRaw, 0}},
- {3418, {wxStyledTextCtrl, appendTextRaw, 1}},
- {3419, {wxArtProvider, getBitmap, 2}},
- {3420, {wxArtProvider, getIcon, 2}},
- {3421, {wxTreeEvent, getKeyCode, 0}},
- {3422, {wxTreeEvent, getItem, 0}},
- {3423, {wxTreeEvent, getKeyEvent, 0}},
- {3424, {wxTreeEvent, getLabel, 0}},
- {3425, {wxTreeEvent, getOldItem, 0}},
- {3426, {wxTreeEvent, getPoint, 0}},
- {3427, {wxTreeEvent, isEditCancelled, 0}},
- {3428, {wxTreeEvent, setToolTip, 1}},
- {3429, {wxNotebookEvent, getOldSelection, 0}},
- {3430, {wxNotebookEvent, getSelection, 0}},
- {3431, {wxNotebookEvent, setOldSelection, 1}},
- {3432, {wxNotebookEvent, setSelection, 1}},
- {3433, {wxFileDataObject, new, 0}},
- {3434, {wxFileDataObject, addFile, 1}},
- {3435, {wxFileDataObject, getFilenames, 0}},
- {3436, {wxFileDataObject, 'Destroy', undefined}},
- {3437, {wxTextDataObject, new, 1}},
- {3438, {wxTextDataObject, getTextLength, 0}},
- {3439, {wxTextDataObject, getText, 0}},
- {3440, {wxTextDataObject, setText, 1}},
- {3441, {wxTextDataObject, 'Destroy', undefined}},
- {3442, {wxBitmapDataObject, new_1_1, 1}},
- {3443, {wxBitmapDataObject, new_1_0, 1}},
- {3444, {wxBitmapDataObject, getBitmap, 0}},
- {3445, {wxBitmapDataObject, setBitmap, 1}},
- {3446, {wxBitmapDataObject, 'Destroy', undefined}},
- {3448, {wxClipboard, new, 0}},
- {3449, {wxClipboard, destruct, 0}},
- {3450, {wxClipboard, addData, 1}},
- {3451, {wxClipboard, clear, 0}},
- {3452, {wxClipboard, close, 0}},
- {3453, {wxClipboard, flush, 0}},
- {3454, {wxClipboard, getData, 1}},
- {3455, {wxClipboard, isOpened, 0}},
- {3456, {wxClipboard, open, 0}},
- {3457, {wxClipboard, setData, 1}},
- {3459, {wxClipboard, usePrimarySelection, 1}},
- {3460, {wxClipboard, isSupported, 1}},
- {3461, {wxClipboard, get, 0}},
- {3462, {wxSpinEvent, getPosition, 0}},
- {3463, {wxSpinEvent, setPosition, 1}},
- {3464, {wxSplitterWindow, new_0, 0}},
- {3465, {wxSplitterWindow, new_2, 2}},
- {3466, {wxSplitterWindow, destruct, 0}},
- {3467, {wxSplitterWindow, create, 2}},
- {3468, {wxSplitterWindow, getMinimumPaneSize, 0}},
- {3469, {wxSplitterWindow, getSashGravity, 0}},
- {3470, {wxSplitterWindow, getSashPosition, 0}},
- {3471, {wxSplitterWindow, getSplitMode, 0}},
- {3472, {wxSplitterWindow, getWindow1, 0}},
- {3473, {wxSplitterWindow, getWindow2, 0}},
- {3474, {wxSplitterWindow, initialize, 1}},
- {3475, {wxSplitterWindow, isSplit, 0}},
- {3476, {wxSplitterWindow, replaceWindow, 2}},
- {3477, {wxSplitterWindow, setSashGravity, 1}},
- {3478, {wxSplitterWindow, setSashPosition, 2}},
- {3479, {wxSplitterWindow, setSashSize, 1}},
- {3480, {wxSplitterWindow, setMinimumPaneSize, 1}},
- {3481, {wxSplitterWindow, setSplitMode, 1}},
- {3482, {wxSplitterWindow, splitHorizontally, 3}},
- {3483, {wxSplitterWindow, splitVertically, 3}},
- {3484, {wxSplitterWindow, unsplit, 1}},
- {3485, {wxSplitterWindow, updateSize, 0}},
- {3486, {wxSplitterEvent, getSashPosition, 0}},
- {3487, {wxSplitterEvent, getX, 0}},
- {3488, {wxSplitterEvent, getY, 0}},
- {3489, {wxSplitterEvent, getWindowBeingRemoved, 0}},
- {3490, {wxSplitterEvent, setSashPosition, 1}},
- {3491, {wxHtmlWindow, new_0, 0}},
- {3492, {wxHtmlWindow, new_2, 2}},
- {3493, {wxHtmlWindow, appendToPage, 1}},
- {3494, {wxHtmlWindow, getOpenedAnchor, 0}},
- {3495, {wxHtmlWindow, getOpenedPage, 0}},
- {3496, {wxHtmlWindow, getOpenedPageTitle, 0}},
- {3497, {wxHtmlWindow, getRelatedFrame, 0}},
- {3498, {wxHtmlWindow, historyBack, 0}},
- {3499, {wxHtmlWindow, historyCanBack, 0}},
- {3500, {wxHtmlWindow, historyCanForward, 0}},
- {3501, {wxHtmlWindow, historyClear, 0}},
- {3502, {wxHtmlWindow, historyForward, 0}},
- {3503, {wxHtmlWindow, loadFile, 1}},
- {3504, {wxHtmlWindow, loadPage, 1}},
- {3505, {wxHtmlWindow, selectAll, 0}},
- {3506, {wxHtmlWindow, selectionToText, 0}},
- {3507, {wxHtmlWindow, selectLine, 1}},
- {3508, {wxHtmlWindow, selectWord, 1}},
- {3509, {wxHtmlWindow, setBorders, 1}},
- {3510, {wxHtmlWindow, setFonts, 3}},
- {3511, {wxHtmlWindow, setPage, 1}},
- {3512, {wxHtmlWindow, setRelatedFrame, 2}},
- {3513, {wxHtmlWindow, setRelatedStatusBar, 1}},
- {3514, {wxHtmlWindow, toText, 0}},
- {3515, {wxHtmlWindow, 'Destroy', undefined}},
- {3516, {wxHtmlLinkEvent, getLinkInfo, 0}},
- {3517, {wxSystemSettings, getColour, 1}},
- {3518, {wxSystemSettings, getFont, 1}},
- {3519, {wxSystemSettings, getMetric, 2}},
- {3520, {wxSystemSettings, getScreenType, 0}},
- {3521, {wxSystemOptions, getOption, 1}},
- {3522, {wxSystemOptions, getOptionInt, 1}},
- {3523, {wxSystemOptions, hasOption, 1}},
- {3524, {wxSystemOptions, isFalse, 1}},
- {3525, {wxSystemOptions, setOption_2_1, 2}},
- {3526, {wxSystemOptions, setOption_2_0, 2}},
- {3527, {wxAuiNotebookEvent, setSelection, 1}},
- {3528, {wxAuiNotebookEvent, getSelection, 0}},
- {3529, {wxAuiNotebookEvent, setOldSelection, 1}},
- {3530, {wxAuiNotebookEvent, getOldSelection, 0}},
- {3531, {wxAuiNotebookEvent, setDragSource, 1}},
- {3532, {wxAuiNotebookEvent, getDragSource, 0}},
- {3533, {wxAuiManagerEvent, setManager, 1}},
- {3534, {wxAuiManagerEvent, getManager, 0}},
- {3535, {wxAuiManagerEvent, setPane, 1}},
- {3536, {wxAuiManagerEvent, getPane, 0}},
- {3537, {wxAuiManagerEvent, setButton, 1}},
- {3538, {wxAuiManagerEvent, getButton, 0}},
- {3539, {wxAuiManagerEvent, setDC, 1}},
- {3540, {wxAuiManagerEvent, getDC, 0}},
- {3541, {wxAuiManagerEvent, veto, 1}},
- {3542, {wxAuiManagerEvent, getVeto, 0}},
- {3543, {wxAuiManagerEvent, setCanVeto, 1}},
- {3544, {wxAuiManagerEvent, canVeto, 0}},
- {3545, {wxLogNull, new, 0}},
- {3546, {wxLogNull, 'Destroy', undefined}},
- {3547, {wxTaskBarIcon, new, 0}},
- {3548, {wxTaskBarIcon, destruct, 0}},
- {3549, {wxTaskBarIcon, popupMenu, 1}},
- {3550, {wxTaskBarIcon, removeIcon, 0}},
- {3551, {wxTaskBarIcon, setIcon, 2}},
- {3552, {wxLocale, new_0, 0}},
- {3554, {wxLocale, new_2, 2}},
- {3555, {wxLocale, destruct, 0}},
- {3557, {wxLocale, init, 1}},
- {3558, {wxLocale, addCatalog_1, 1}},
- {3559, {wxLocale, addCatalog_3, 3}},
- {3560, {wxLocale, addCatalogLookupPathPrefix, 1}},
- {3561, {wxLocale, getCanonicalName, 0}},
- {3562, {wxLocale, getLanguage, 0}},
- {3563, {wxLocale, getLanguageName, 1}},
- {3564, {wxLocale, getLocale, 0}},
- {3565, {wxLocale, getName, 0}},
- {3566, {wxLocale, getString_2, 2}},
- {3567, {wxLocale, getString_4, 4}},
- {3568, {wxLocale, getHeaderValue, 2}},
- {3569, {wxLocale, getSysName, 0}},
- {3570, {wxLocale, getSystemEncoding, 0}},
- {3571, {wxLocale, getSystemEncodingName, 0}},
- {3572, {wxLocale, getSystemLanguage, 0}},
- {3573, {wxLocale, isLoaded, 1}},
- {3574, {wxLocale, isOk, 0}},
- {3575, {wxActivateEvent, getActive, 0}},
- {3577, {wxPopupWindow, new_2, 2}},
- {3578, {wxPopupWindow, new_0, 0}},
- {3580, {wxPopupWindow, destruct, 0}},
- {3581, {wxPopupWindow, create, 2}},
- {3582, {wxPopupWindow, position, 2}},
- {3583, {wxPopupTransientWindow, new_0, 0}},
- {3584, {wxPopupTransientWindow, new_2, 2}},
- {3585, {wxPopupTransientWindow, destruct, 0}},
- {3586, {wxPopupTransientWindow, popup, 1}},
- {3587, {wxPopupTransientWindow, dismiss, 0}},
- {3588, {wxOverlay, new, 0}},
- {3589, {wxOverlay, destruct, 0}},
- {3590, {wxOverlay, reset, 0}},
- {3591, {wxDCOverlay, new_6, 6}},
- {3592, {wxDCOverlay, new_2, 2}},
- {3593, {wxDCOverlay, destruct, 0}},
- {3594, {wxDCOverlay, clear, 0}},
+ {126, {wxWindow, dragAcceptFiles, 1}},
+ {127, {wxWindow, enable, 1}},
+ {128, {wxWindow, findFocus, 0}},
+ {129, {wxWindow, findWindow_1_0, 1}},
+ {130, {wxWindow, findWindow_1_1, 1}},
+ {131, {wxWindow, findWindowById, 2}},
+ {132, {wxWindow, findWindowByName, 2}},
+ {133, {wxWindow, findWindowByLabel, 2}},
+ {134, {wxWindow, fit, 0}},
+ {135, {wxWindow, fitInside, 0}},
+ {136, {wxWindow, freeze, 0}},
+ {137, {wxWindow, getAcceleratorTable, 0}},
+ {138, {wxWindow, getBackgroundColour, 0}},
+ {139, {wxWindow, getBackgroundStyle, 0}},
+ {140, {wxWindow, getBestSize, 0}},
+ {142, {wxWindow, getCaret, 0}},
+ {143, {wxWindow, getCapture, 0}},
+ {144, {wxWindow, getCharHeight, 0}},
+ {145, {wxWindow, getCharWidth, 0}},
+ {146, {wxWindow, getChildren, 0}},
+ {149, {wxWindow, getClientSize, 0}},
+ {150, {wxWindow, getContainingSizer, 0}},
+ {151, {wxWindow, getCursor, 0}},
+ {152, {wxWindow, getDropTarget, 0}},
+ {153, {wxWindow, getEventHandler, 0}},
+ {154, {wxWindow, getExtraStyle, 0}},
+ {155, {wxWindow, getFont, 0}},
+ {156, {wxWindow, getForegroundColour, 0}},
+ {157, {wxWindow, getGrandParent, 0}},
+ {158, {wxWindow, getHandle, 0}},
+ {159, {wxWindow, getHelpText, 0}},
+ {160, {wxWindow, getId, 0}},
+ {161, {wxWindow, getLabel, 0}},
+ {162, {wxWindow, getMaxSize, 0}},
+ {163, {wxWindow, getMinSize, 0}},
+ {164, {wxWindow, getName, 0}},
+ {165, {wxWindow, getParent, 0}},
+ {167, {wxWindow, getPosition, 0}},
+ {168, {wxWindow, getRect, 0}},
+ {170, {wxWindow, getScreenPosition, 0}},
+ {171, {wxWindow, getScreenRect, 0}},
+ {172, {wxWindow, getScrollPos, 1}},
+ {173, {wxWindow, getScrollRange, 1}},
+ {174, {wxWindow, getScrollThumb, 1}},
+ {176, {wxWindow, getSize, 0}},
+ {177, {wxWindow, getSizer, 0}},
+ {178, {wxWindow, getTextExtent, 4}},
+ {179, {wxWindow, getToolTip, 0}},
+ {180, {wxWindow, getUpdateRegion, 0}},
+ {182, {wxWindow, getVirtualSize, 0}},
+ {184, {wxWindow, getWindowStyleFlag, 0}},
+ {185, {wxWindow, getWindowVariant, 0}},
+ {186, {wxWindow, hasCapture, 0}},
+ {187, {wxWindow, hasScrollbar, 1}},
+ {188, {wxWindow, hasTransparentBackground, 0}},
+ {189, {wxWindow, hide, 0}},
+ {190, {wxWindow, inheritAttributes, 0}},
+ {191, {wxWindow, initDialog, 0}},
+ {192, {wxWindow, invalidateBestSize, 0}},
+ {193, {wxWindow, isEnabled, 0}},
+ {194, {wxWindow, isExposed_2, 2}},
+ {195, {wxWindow, isExposed_4, 4}},
+ {196, {wxWindow, isExposed_1_0, 1}},
+ {197, {wxWindow, isExposed_1_1, 1}},
+ {198, {wxWindow, isRetained, 0}},
+ {199, {wxWindow, isShown, 0}},
+ {200, {wxWindow, isTopLevel, 0}},
+ {201, {wxWindow, layout, 0}},
+ {202, {wxWindow, lineDown, 0}},
+ {203, {wxWindow, lineUp, 0}},
+ {204, {wxWindow, lower, 0}},
+ {205, {wxWindow, makeModal, 1}},
+ {206, {wxWindow, move_3, 3}},
+ {207, {wxWindow, move_2, 2}},
+ {208, {wxWindow, moveAfterInTabOrder, 1}},
+ {209, {wxWindow, moveBeforeInTabOrder, 1}},
+ {210, {wxWindow, navigate, 1}},
+ {211, {wxWindow, pageDown, 0}},
+ {212, {wxWindow, pageUp, 0}},
+ {213, {wxWindow, popEventHandler, 1}},
+ {214, {wxWindow, popupMenu_2, 2}},
+ {215, {wxWindow, popupMenu_3, 3}},
+ {216, {wxWindow, raise, 0}},
+ {217, {wxWindow, refresh, 1}},
+ {218, {wxWindow, refreshRect, 2}},
+ {219, {wxWindow, releaseMouse, 0}},
+ {220, {wxWindow, removeChild, 1}},
+ {221, {wxWindow, reparent, 1}},
+ {222, {wxWindow, screenToClient_2, 2}},
+ {223, {wxWindow, screenToClient_1, 1}},
+ {225, {wxWindow, scrollLines, 1}},
+ {227, {wxWindow, scrollPages, 1}},
+ {228, {wxWindow, scrollWindow, 3}},
+ {229, {wxWindow, setAcceleratorTable, 1}},
+ {230, {wxWindow, setAutoLayout, 1}},
+ {231, {wxWindow, setBackgroundColour, 1}},
+ {232, {wxWindow, setBackgroundStyle, 1}},
+ {233, {wxWindow, setCaret, 1}},
+ {234, {wxWindow, setClientSize_2, 2}},
+ {235, {wxWindow, setClientSize_1_0, 1}},
+ {236, {wxWindow, setClientSize_1_1, 1}},
+ {237, {wxWindow, setContainingSizer, 1}},
+ {238, {wxWindow, setCursor, 1}},
+ {239, {wxWindow, setMaxSize, 1}},
+ {240, {wxWindow, setMinSize, 1}},
+ {241, {wxWindow, setOwnBackgroundColour, 1}},
+ {242, {wxWindow, setOwnFont, 1}},
+ {243, {wxWindow, setOwnForegroundColour, 1}},
+ {244, {wxWindow, setDropTarget, 1}},
+ {245, {wxWindow, setExtraStyle, 1}},
+ {246, {wxWindow, setFocus, 0}},
+ {247, {wxWindow, setFocusFromKbd, 0}},
+ {248, {wxWindow, setFont, 1}},
+ {249, {wxWindow, setForegroundColour, 1}},
+ {250, {wxWindow, setHelpText, 1}},
+ {251, {wxWindow, setId, 1}},
+ {253, {wxWindow, setLabel, 1}},
+ {254, {wxWindow, setName, 1}},
+ {255, {wxWindow, setPalette, 1}},
+ {256, {wxWindow, setScrollbar, 5}},
+ {257, {wxWindow, setScrollPos, 3}},
+ {258, {wxWindow, setSize_5, 5}},
+ {259, {wxWindow, setSize_2_0, 2}},
+ {260, {wxWindow, setSize_1, 1}},
+ {261, {wxWindow, setSize_2_1, 2}},
+ {262, {wxWindow, setSizeHints_3, 3}},
+ {263, {wxWindow, setSizeHints_2, 2}},
+ {264, {wxWindow, setSizer, 2}},
+ {265, {wxWindow, setSizerAndFit, 2}},
+ {266, {wxWindow, setThemeEnabled, 1}},
+ {267, {wxWindow, setToolTip_1_0, 1}},
+ {268, {wxWindow, setToolTip_1_1, 1}},
+ {269, {wxWindow, setVirtualSize_1, 1}},
+ {270, {wxWindow, setVirtualSize_2, 2}},
+ {271, {wxWindow, setVirtualSizeHints_3, 3}},
+ {272, {wxWindow, setVirtualSizeHints_2, 2}},
+ {273, {wxWindow, setWindowStyle, 1}},
+ {274, {wxWindow, setWindowStyleFlag, 1}},
+ {275, {wxWindow, setWindowVariant, 1}},
+ {276, {wxWindow, shouldInheritColours, 0}},
+ {277, {wxWindow, show, 1}},
+ {278, {wxWindow, thaw, 0}},
+ {279, {wxWindow, transferDataFromWindow, 0}},
+ {280, {wxWindow, transferDataToWindow, 0}},
+ {281, {wxWindow, update, 0}},
+ {282, {wxWindow, updateWindowUI, 1}},
+ {283, {wxWindow, validate, 0}},
+ {284, {wxWindow, warpPointer, 2}},
+ {285, {wxWindow, setTransparent, 1}},
+ {286, {wxWindow, canSetTransparent, 0}},
+ {287, {wxWindow, isDoubleBuffered, 0}},
+ {288, {wxWindow, setDoubleBuffered, 1}},
+ {289, {wxWindow, getContentScaleFactor, 0}},
+ {290, {wxTopLevelWindow, getIcon, 0}},
+ {291, {wxTopLevelWindow, getIcons, 0}},
+ {292, {wxTopLevelWindow, getTitle, 0}},
+ {293, {wxTopLevelWindow, isActive, 0}},
+ {294, {wxTopLevelWindow, iconize, 1}},
+ {295, {wxTopLevelWindow, isFullScreen, 0}},
+ {296, {wxTopLevelWindow, isIconized, 0}},
+ {297, {wxTopLevelWindow, isMaximized, 0}},
+ {298, {wxTopLevelWindow, maximize, 1}},
+ {299, {wxTopLevelWindow, requestUserAttention, 1}},
+ {300, {wxTopLevelWindow, setIcon, 1}},
+ {301, {wxTopLevelWindow, setIcons, 1}},
+ {302, {wxTopLevelWindow, centerOnScreen, 1}},
+ {303, {wxTopLevelWindow, centreOnScreen, 1}},
+ {305, {wxTopLevelWindow, setShape, 1}},
+ {306, {wxTopLevelWindow, setTitle, 1}},
+ {307, {wxTopLevelWindow, showFullScreen, 2}},
+ {309, {wxFrame, new_4, 4}},
+ {310, {wxFrame, new_0, 0}},
+ {312, {wxFrame, destruct, 0}},
+ {313, {wxFrame, create, 4}},
+ {314, {wxFrame, createStatusBar, 1}},
+ {315, {wxFrame, createToolBar, 1}},
+ {316, {wxFrame, getClientAreaOrigin, 0}},
+ {317, {wxFrame, getMenuBar, 0}},
+ {318, {wxFrame, getStatusBar, 0}},
+ {319, {wxFrame, getStatusBarPane, 0}},
+ {320, {wxFrame, getToolBar, 0}},
+ {321, {wxFrame, processCommand, 1}},
+ {322, {wxFrame, sendSizeEvent, 0}},
+ {323, {wxFrame, setMenuBar, 1}},
+ {324, {wxFrame, setStatusBar, 1}},
+ {325, {wxFrame, setStatusBarPane, 1}},
+ {326, {wxFrame, setStatusText, 2}},
+ {327, {wxFrame, setStatusWidths, 2}},
+ {328, {wxFrame, setToolBar, 1}},
+ {329, {wxMiniFrame, new_0, 0}},
+ {330, {wxMiniFrame, new_4, 4}},
+ {331, {wxMiniFrame, create, 4}},
+ {332, {wxMiniFrame, 'Destroy', undefined}},
+ {333, {wxSplashScreen, new_0, 0}},
+ {334, {wxSplashScreen, new_6, 6}},
+ {335, {wxSplashScreen, destruct, 0}},
+ {336, {wxSplashScreen, getSplashStyle, 0}},
+ {337, {wxSplashScreen, getTimeout, 0}},
+ {338, {wxPanel, new_0, 0}},
+ {339, {wxPanel, new_6, 6}},
+ {340, {wxPanel, new_2, 2}},
+ {341, {wxPanel, destruct, 0}},
+ {342, {wxPanel, initDialog, 0}},
+ {343, {wxPanel, setFocusIgnoringChildren, 0}},
+ {344, {wxScrolledWindow, new_0, 0}},
+ {345, {wxScrolledWindow, new_2, 2}},
+ {346, {wxScrolledWindow, destruct, 0}},
+ {347, {wxScrolledWindow, calcScrolledPosition_4, 4}},
+ {348, {wxScrolledWindow, calcScrolledPosition_1, 1}},
+ {349, {wxScrolledWindow, calcUnscrolledPosition_4, 4}},
+ {350, {wxScrolledWindow, calcUnscrolledPosition_1, 1}},
+ {351, {wxScrolledWindow, enableScrolling, 2}},
+ {352, {wxScrolledWindow, getScrollPixelsPerUnit, 2}},
+ {353, {wxScrolledWindow, getViewStart, 2}},
+ {354, {wxScrolledWindow, doPrepareDC, 1}},
+ {355, {wxScrolledWindow, prepareDC, 1}},
+ {356, {wxScrolledWindow, scroll, 2}},
+ {357, {wxScrolledWindow, setScrollbars, 5}},
+ {358, {wxScrolledWindow, setScrollRate, 2}},
+ {359, {wxScrolledWindow, setTargetWindow, 1}},
+ {360, {wxSashWindow, new_0, 0}},
+ {361, {wxSashWindow, new_2, 2}},
+ {362, {wxSashWindow, destruct, 0}},
+ {363, {wxSashWindow, getSashVisible, 1}},
+ {364, {wxSashWindow, getMaximumSizeX, 0}},
+ {365, {wxSashWindow, getMaximumSizeY, 0}},
+ {366, {wxSashWindow, getMinimumSizeX, 0}},
+ {367, {wxSashWindow, getMinimumSizeY, 0}},
+ {368, {wxSashWindow, setMaximumSizeX, 1}},
+ {369, {wxSashWindow, setMaximumSizeY, 1}},
+ {370, {wxSashWindow, setMinimumSizeX, 1}},
+ {371, {wxSashWindow, setMinimumSizeY, 1}},
+ {372, {wxSashWindow, setSashVisible, 2}},
+ {373, {wxSashLayoutWindow, new_0, 0}},
+ {374, {wxSashLayoutWindow, new_2, 2}},
+ {375, {wxSashLayoutWindow, create, 2}},
+ {376, {wxSashLayoutWindow, getAlignment, 0}},
+ {377, {wxSashLayoutWindow, getOrientation, 0}},
+ {378, {wxSashLayoutWindow, setAlignment, 1}},
+ {379, {wxSashLayoutWindow, setDefaultSize, 1}},
+ {380, {wxSashLayoutWindow, setOrientation, 1}},
+ {381, {wxSashLayoutWindow, 'Destroy', undefined}},
+ {382, {wxGrid, new_0, 0}},
+ {383, {wxGrid, new_3, 3}},
+ {384, {wxGrid, new_4, 4}},
+ {385, {wxGrid, destruct, 0}},
+ {386, {wxGrid, appendCols, 1}},
+ {387, {wxGrid, appendRows, 1}},
+ {388, {wxGrid, autoSize, 0}},
+ {389, {wxGrid, autoSizeColumn, 2}},
+ {390, {wxGrid, autoSizeColumns, 1}},
+ {391, {wxGrid, autoSizeRow, 2}},
+ {392, {wxGrid, autoSizeRows, 1}},
+ {393, {wxGrid, beginBatch, 0}},
+ {394, {wxGrid, blockToDeviceRect, 2}},
+ {395, {wxGrid, canDragColSize, 0}},
+ {396, {wxGrid, canDragRowSize, 0}},
+ {397, {wxGrid, canDragGridSize, 0}},
+ {398, {wxGrid, canEnableCellControl, 0}},
+ {399, {wxGrid, cellToRect_2, 2}},
+ {400, {wxGrid, cellToRect_1, 1}},
+ {401, {wxGrid, clearGrid, 0}},
+ {402, {wxGrid, clearSelection, 0}},
+ {403, {wxGrid, createGrid, 3}},
+ {404, {wxGrid, deleteCols, 1}},
+ {405, {wxGrid, deleteRows, 1}},
+ {406, {wxGrid, disableCellEditControl, 0}},
+ {407, {wxGrid, disableDragColSize, 0}},
+ {408, {wxGrid, disableDragGridSize, 0}},
+ {409, {wxGrid, disableDragRowSize, 0}},
+ {410, {wxGrid, enableCellEditControl, 1}},
+ {411, {wxGrid, enableDragColSize, 1}},
+ {412, {wxGrid, enableDragGridSize, 1}},
+ {413, {wxGrid, enableDragRowSize, 1}},
+ {414, {wxGrid, enableEditing, 1}},
+ {415, {wxGrid, enableGridLines, 1}},
+ {416, {wxGrid, endBatch, 0}},
+ {417, {wxGrid, fit, 0}},
+ {418, {wxGrid, forceRefresh, 0}},
+ {419, {wxGrid, getBatchCount, 0}},
+ {420, {wxGrid, getCellAlignment, 4}},
+ {421, {wxGrid, getCellBackgroundColour, 2}},
+ {422, {wxGrid, getCellEditor, 2}},
+ {423, {wxGrid, getCellFont, 2}},
+ {424, {wxGrid, getCellRenderer, 2}},
+ {425, {wxGrid, getCellTextColour, 2}},
+ {426, {wxGrid, getCellValue_2, 2}},
+ {427, {wxGrid, getCellValue_1, 1}},
+ {428, {wxGrid, getColLabelAlignment, 2}},
+ {429, {wxGrid, getColLabelSize, 0}},
+ {430, {wxGrid, getColLabelValue, 1}},
+ {431, {wxGrid, getColMinimalAcceptableWidth, 0}},
+ {432, {wxGrid, getDefaultCellAlignment, 2}},
+ {433, {wxGrid, getDefaultCellBackgroundColour, 0}},
+ {434, {wxGrid, getDefaultCellFont, 0}},
+ {435, {wxGrid, getDefaultCellTextColour, 0}},
+ {436, {wxGrid, getDefaultColLabelSize, 0}},
+ {437, {wxGrid, getDefaultColSize, 0}},
+ {438, {wxGrid, getDefaultEditor, 0}},
+ {439, {wxGrid, getDefaultEditorForCell_2, 2}},
+ {440, {wxGrid, getDefaultEditorForCell_1, 1}},
+ {441, {wxGrid, getDefaultEditorForType, 1}},
+ {442, {wxGrid, getDefaultRenderer, 0}},
+ {443, {wxGrid, getDefaultRendererForCell, 2}},
+ {444, {wxGrid, getDefaultRendererForType, 1}},
+ {445, {wxGrid, getDefaultRowLabelSize, 0}},
+ {446, {wxGrid, getDefaultRowSize, 0}},
+ {447, {wxGrid, getGridCursorCol, 0}},
+ {448, {wxGrid, getGridCursorRow, 0}},
+ {449, {wxGrid, getGridLineColour, 0}},
+ {450, {wxGrid, gridLinesEnabled, 0}},
+ {451, {wxGrid, getLabelBackgroundColour, 0}},
+ {452, {wxGrid, getLabelFont, 0}},
+ {453, {wxGrid, getLabelTextColour, 0}},
+ {454, {wxGrid, getNumberCols, 0}},
+ {455, {wxGrid, getNumberRows, 0}},
+ {456, {wxGrid, getOrCreateCellAttr, 2}},
+ {457, {wxGrid, getRowMinimalAcceptableHeight, 0}},
+ {458, {wxGrid, getRowLabelAlignment, 2}},
+ {459, {wxGrid, getRowLabelSize, 0}},
+ {460, {wxGrid, getRowLabelValue, 1}},
+ {461, {wxGrid, getRowSize, 1}},
+ {462, {wxGrid, getScrollLineX, 0}},
+ {463, {wxGrid, getScrollLineY, 0}},
+ {464, {wxGrid, getSelectedCells, 0}},
+ {465, {wxGrid, getSelectedCols, 0}},
+ {466, {wxGrid, getSelectedRows, 0}},
+ {467, {wxGrid, getSelectionBackground, 0}},
+ {468, {wxGrid, getSelectionBlockTopLeft, 0}},
+ {469, {wxGrid, getSelectionBlockBottomRight, 0}},
+ {470, {wxGrid, getSelectionForeground, 0}},
+ {471, {wxGrid, getViewWidth, 0}},
+ {472, {wxGrid, getGridWindow, 0}},
+ {473, {wxGrid, getGridRowLabelWindow, 0}},
+ {474, {wxGrid, getGridColLabelWindow, 0}},
+ {475, {wxGrid, getGridCornerLabelWindow, 0}},
+ {476, {wxGrid, hideCellEditControl, 0}},
+ {477, {wxGrid, insertCols, 1}},
+ {478, {wxGrid, insertRows, 1}},
+ {479, {wxGrid, isCellEditControlEnabled, 0}},
+ {480, {wxGrid, isCurrentCellReadOnly, 0}},
+ {481, {wxGrid, isEditable, 0}},
+ {482, {wxGrid, isInSelection_2, 2}},
+ {483, {wxGrid, isInSelection_1, 1}},
+ {484, {wxGrid, isReadOnly, 2}},
+ {485, {wxGrid, isSelection, 0}},
+ {486, {wxGrid, isVisible_3, 3}},
+ {487, {wxGrid, isVisible_2, 2}},
+ {488, {wxGrid, makeCellVisible_2, 2}},
+ {489, {wxGrid, makeCellVisible_1, 1}},
+ {490, {wxGrid, moveCursorDown, 1}},
+ {491, {wxGrid, moveCursorLeft, 1}},
+ {492, {wxGrid, moveCursorRight, 1}},
+ {493, {wxGrid, moveCursorUp, 1}},
+ {494, {wxGrid, moveCursorDownBlock, 1}},
+ {495, {wxGrid, moveCursorLeftBlock, 1}},
+ {496, {wxGrid, moveCursorRightBlock, 1}},
+ {497, {wxGrid, moveCursorUpBlock, 1}},
+ {498, {wxGrid, movePageDown, 0}},
+ {499, {wxGrid, movePageUp, 0}},
+ {500, {wxGrid, registerDataType, 3}},
+ {501, {wxGrid, saveEditControlValue, 0}},
+ {502, {wxGrid, selectAll, 0}},
+ {503, {wxGrid, selectBlock_5, 5}},
+ {504, {wxGrid, selectBlock_3, 3}},
+ {505, {wxGrid, selectCol, 2}},
+ {506, {wxGrid, selectRow, 2}},
+ {507, {wxGrid, setCellAlignment_4, 4}},
+ {508, {wxGrid, setCellAlignment_3, 3}},
+ {509, {wxGrid, setCellAlignment_1, 1}},
+ {510, {wxGrid, setCellBackgroundColour_3_0, 3}},
+ {511, {wxGrid, setCellBackgroundColour_1, 1}},
+ {512, {wxGrid, setCellBackgroundColour_3_1, 3}},
+ {513, {wxGrid, setCellEditor, 3}},
+ {514, {wxGrid, setCellFont, 3}},
+ {515, {wxGrid, setCellRenderer, 3}},
+ {516, {wxGrid, setCellTextColour_3_0, 3}},
+ {517, {wxGrid, setCellTextColour_3_1, 3}},
+ {518, {wxGrid, setCellTextColour_1, 1}},
+ {519, {wxGrid, setCellValue_3_0, 3}},
+ {520, {wxGrid, setCellValue_2, 2}},
+ {521, {wxGrid, setCellValue_3_1, 3}},
+ {522, {wxGrid, setColAttr, 2}},
+ {523, {wxGrid, setColFormatBool, 1}},
+ {524, {wxGrid, setColFormatNumber, 1}},
+ {525, {wxGrid, setColFormatFloat, 2}},
+ {526, {wxGrid, setColFormatCustom, 2}},
+ {527, {wxGrid, setColLabelAlignment, 2}},
+ {528, {wxGrid, setColLabelSize, 1}},
+ {529, {wxGrid, setColLabelValue, 2}},
+ {530, {wxGrid, setColMinimalWidth, 2}},
+ {531, {wxGrid, setColMinimalAcceptableWidth, 1}},
+ {532, {wxGrid, setColSize, 2}},
+ {533, {wxGrid, setDefaultCellAlignment, 2}},
+ {534, {wxGrid, setDefaultCellBackgroundColour, 1}},
+ {535, {wxGrid, setDefaultCellFont, 1}},
+ {536, {wxGrid, setDefaultCellTextColour, 1}},
+ {537, {wxGrid, setDefaultEditor, 1}},
+ {538, {wxGrid, setDefaultRenderer, 1}},
+ {539, {wxGrid, setDefaultColSize, 2}},
+ {540, {wxGrid, setDefaultRowSize, 2}},
+ {541, {wxGrid, setGridCursor, 2}},
+ {542, {wxGrid, setGridLineColour, 1}},
+ {543, {wxGrid, setLabelBackgroundColour, 1}},
+ {544, {wxGrid, setLabelFont, 1}},
+ {545, {wxGrid, setLabelTextColour, 1}},
+ {546, {wxGrid, setMargins, 2}},
+ {547, {wxGrid, setReadOnly, 3}},
+ {548, {wxGrid, setRowAttr, 2}},
+ {549, {wxGrid, setRowLabelAlignment, 2}},
+ {550, {wxGrid, setRowLabelSize, 1}},
+ {551, {wxGrid, setRowLabelValue, 2}},
+ {552, {wxGrid, setRowMinimalHeight, 2}},
+ {553, {wxGrid, setRowMinimalAcceptableHeight, 1}},
+ {554, {wxGrid, setRowSize, 2}},
+ {555, {wxGrid, setScrollLineX, 1}},
+ {556, {wxGrid, setScrollLineY, 1}},
+ {557, {wxGrid, setSelectionBackground, 1}},
+ {558, {wxGrid, setSelectionForeground, 1}},
+ {559, {wxGrid, setSelectionMode, 1}},
+ {560, {wxGrid, showCellEditControl, 0}},
+ {561, {wxGrid, xToCol, 2}},
+ {562, {wxGrid, xToEdgeOfCol, 1}},
+ {563, {wxGrid, yToEdgeOfRow, 1}},
+ {564, {wxGrid, yToRow, 1}},
+ {565, {wxGridCellRenderer, draw, 7}},
+ {566, {wxGridCellRenderer, getBestSize, 5}},
+ {567, {wxGridCellEditor, create, 3}},
+ {568, {wxGridCellEditor, isCreated, 0}},
+ {569, {wxGridCellEditor, setSize, 1}},
+ {570, {wxGridCellEditor, show, 2}},
+ {571, {wxGridCellEditor, paintBackground, 2}},
+ {572, {wxGridCellEditor, beginEdit, 3}},
+ {573, {wxGridCellEditor, endEdit, 3}},
+ {574, {wxGridCellEditor, reset, 0}},
+ {575, {wxGridCellEditor, startingKey, 1}},
+ {576, {wxGridCellEditor, startingClick, 0}},
+ {577, {wxGridCellEditor, handleReturn, 1}},
+ {578, {wxGridCellBoolRenderer, new, 0}},
+ {579, {wxGridCellBoolRenderer, 'Destroy', undefined}},
+ {580, {wxGridCellBoolEditor, new, 0}},
+ {581, {wxGridCellBoolEditor, isTrueValue, 1}},
+ {582, {wxGridCellBoolEditor, useStringValues, 1}},
+ {583, {wxGridCellBoolEditor, 'Destroy', undefined}},
+ {584, {wxGridCellFloatRenderer, new, 1}},
+ {585, {wxGridCellFloatRenderer, getPrecision, 0}},
+ {586, {wxGridCellFloatRenderer, getWidth, 0}},
+ {587, {wxGridCellFloatRenderer, setParameters, 1}},
+ {588, {wxGridCellFloatRenderer, setPrecision, 1}},
+ {589, {wxGridCellFloatRenderer, setWidth, 1}},
+ {590, {wxGridCellFloatRenderer, 'Destroy', undefined}},
+ {591, {wxGridCellFloatEditor, new, 1}},
+ {592, {wxGridCellFloatEditor, setParameters, 1}},
+ {593, {wxGridCellFloatEditor, 'Destroy', undefined}},
+ {594, {wxGridCellStringRenderer, new, 0}},
+ {595, {wxGridCellStringRenderer, 'Destroy', undefined}},
+ {596, {wxGridCellTextEditor, new, 0}},
+ {597, {wxGridCellTextEditor, setParameters, 1}},
+ {598, {wxGridCellTextEditor, 'Destroy', undefined}},
+ {600, {wxGridCellChoiceEditor, new, 2}},
+ {601, {wxGridCellChoiceEditor, setParameters, 1}},
+ {602, {wxGridCellChoiceEditor, 'Destroy', undefined}},
+ {603, {wxGridCellNumberRenderer, new, 0}},
+ {604, {wxGridCellNumberRenderer, 'Destroy', undefined}},
+ {605, {wxGridCellNumberEditor, new, 1}},
+ {606, {wxGridCellNumberEditor, getValue, 0}},
+ {607, {wxGridCellNumberEditor, setParameters, 1}},
+ {608, {wxGridCellNumberEditor, 'Destroy', undefined}},
+ {609, {wxGridCellAttr, setTextColour, 1}},
+ {610, {wxGridCellAttr, setBackgroundColour, 1}},
+ {611, {wxGridCellAttr, setFont, 1}},
+ {612, {wxGridCellAttr, setAlignment, 2}},
+ {613, {wxGridCellAttr, setReadOnly, 1}},
+ {614, {wxGridCellAttr, setRenderer, 1}},
+ {615, {wxGridCellAttr, setEditor, 1}},
+ {616, {wxGridCellAttr, hasTextColour, 0}},
+ {617, {wxGridCellAttr, hasBackgroundColour, 0}},
+ {618, {wxGridCellAttr, hasFont, 0}},
+ {619, {wxGridCellAttr, hasAlignment, 0}},
+ {620, {wxGridCellAttr, hasRenderer, 0}},
+ {621, {wxGridCellAttr, hasEditor, 0}},
+ {622, {wxGridCellAttr, getTextColour, 0}},
+ {623, {wxGridCellAttr, getBackgroundColour, 0}},
+ {624, {wxGridCellAttr, getFont, 0}},
+ {625, {wxGridCellAttr, getAlignment, 2}},
+ {626, {wxGridCellAttr, getRenderer, 3}},
+ {627, {wxGridCellAttr, getEditor, 3}},
+ {628, {wxGridCellAttr, isReadOnly, 0}},
+ {629, {wxGridCellAttr, setDefAttr, 1}},
+ {630, {wxDC, blit, 5}},
+ {631, {wxDC, calcBoundingBox, 2}},
+ {632, {wxDC, clear, 0}},
+ {633, {wxDC, computeScaleAndOrigin, 0}},
+ {634, {wxDC, crossHair, 1}},
+ {635, {wxDC, destroyClippingRegion, 0}},
+ {636, {wxDC, deviceToLogicalX, 1}},
+ {637, {wxDC, deviceToLogicalXRel, 1}},
+ {638, {wxDC, deviceToLogicalY, 1}},
+ {639, {wxDC, deviceToLogicalYRel, 1}},
+ {640, {wxDC, drawArc, 3}},
+ {641, {wxDC, drawBitmap, 3}},
+ {642, {wxDC, drawCheckMark, 1}},
+ {643, {wxDC, drawCircle, 2}},
+ {645, {wxDC, drawEllipse_2, 2}},
+ {646, {wxDC, drawEllipse_1, 1}},
+ {647, {wxDC, drawEllipticArc, 4}},
+ {648, {wxDC, drawIcon, 2}},
+ {649, {wxDC, drawLabel, 3}},
+ {650, {wxDC, drawLine, 2}},
+ {651, {wxDC, drawLines, 3}},
+ {653, {wxDC, drawPolygon, 3}},
+ {655, {wxDC, drawPoint, 1}},
+ {657, {wxDC, drawRectangle_2, 2}},
+ {658, {wxDC, drawRectangle_1, 1}},
+ {659, {wxDC, drawRotatedText, 3}},
+ {661, {wxDC, drawRoundedRectangle_3, 3}},
+ {662, {wxDC, drawRoundedRectangle_2, 2}},
+ {663, {wxDC, drawText, 2}},
+ {664, {wxDC, endDoc, 0}},
+ {665, {wxDC, endPage, 0}},
+ {666, {wxDC, floodFill, 3}},
+ {667, {wxDC, getBackground, 0}},
+ {668, {wxDC, getBackgroundMode, 0}},
+ {669, {wxDC, getBrush, 0}},
+ {670, {wxDC, getCharHeight, 0}},
+ {671, {wxDC, getCharWidth, 0}},
+ {672, {wxDC, getClippingBox, 4}},
+ {674, {wxDC, getFont, 0}},
+ {675, {wxDC, getLayoutDirection, 0}},
+ {676, {wxDC, getLogicalFunction, 0}},
+ {677, {wxDC, getMapMode, 0}},
+ {678, {wxDC, getMultiLineTextExtent_4, 4}},
+ {679, {wxDC, getMultiLineTextExtent_1, 1}},
+ {680, {wxDC, getPartialTextExtents, 2}},
+ {681, {wxDC, getPen, 0}},
+ {682, {wxDC, getPixel, 2}},
+ {683, {wxDC, getPPI, 0}},
+ {685, {wxDC, getSize, 0}},
+ {687, {wxDC, getSizeMM, 0}},
+ {688, {wxDC, getTextBackground, 0}},
+ {689, {wxDC, getTextExtent_4, 4}},
+ {690, {wxDC, getTextExtent_1, 1}},
+ {692, {wxDC, getTextForeground, 0}},
+ {693, {wxDC, getUserScale, 2}},
+ {694, {wxDC, gradientFillConcentric_3, 3}},
+ {695, {wxDC, gradientFillConcentric_4, 4}},
+ {696, {wxDC, gradientFillLinear, 4}},
+ {697, {wxDC, logicalToDeviceX, 1}},
+ {698, {wxDC, logicalToDeviceXRel, 1}},
+ {699, {wxDC, logicalToDeviceY, 1}},
+ {700, {wxDC, logicalToDeviceYRel, 1}},
+ {701, {wxDC, maxX, 0}},
+ {702, {wxDC, maxY, 0}},
+ {703, {wxDC, minX, 0}},
+ {704, {wxDC, minY, 0}},
+ {705, {wxDC, isOk, 0}},
+ {706, {wxDC, resetBoundingBox, 0}},
+ {707, {wxDC, setAxisOrientation, 2}},
+ {708, {wxDC, setBackground, 1}},
+ {709, {wxDC, setBackgroundMode, 1}},
+ {710, {wxDC, setBrush, 1}},
+ {712, {wxDC, setClippingRegion_2, 2}},
+ {713, {wxDC, setClippingRegion_1_1, 1}},
+ {714, {wxDC, setClippingRegion_1_0, 1}},
+ {715, {wxDC, setDeviceOrigin, 2}},
+ {716, {wxDC, setFont, 1}},
+ {717, {wxDC, setLayoutDirection, 1}},
+ {718, {wxDC, setLogicalFunction, 1}},
+ {719, {wxDC, setMapMode, 1}},
+ {720, {wxDC, setPalette, 1}},
+ {721, {wxDC, setPen, 1}},
+ {722, {wxDC, setTextBackground, 1}},
+ {723, {wxDC, setTextForeground, 1}},
+ {724, {wxDC, setUserScale, 2}},
+ {725, {wxDC, startDoc, 1}},
+ {726, {wxDC, startPage, 0}},
+ {727, {wxMirrorDC, new, 2}},
+ {728, {wxMirrorDC, 'Destroy', undefined}},
+ {729, {wxScreenDC, new, 0}},
+ {730, {wxScreenDC, destruct, 0}},
+ {731, {wxPostScriptDC, new_0, 0}},
+ {732, {wxPostScriptDC, new_1, 1}},
+ {733, {wxPostScriptDC, destruct, 0}},
+ {734, {wxPostScriptDC, setResolution, 1}},
+ {735, {wxPostScriptDC, getResolution, 0}},
+ {736, {wxWindowDC, new_0, 0}},
+ {737, {wxWindowDC, new_1, 1}},
+ {738, {wxWindowDC, destruct, 0}},
+ {739, {wxClientDC, new_0, 0}},
+ {740, {wxClientDC, new_1, 1}},
+ {741, {wxClientDC, 'Destroy', undefined}},
+ {742, {wxPaintDC, new_0, 0}},
+ {743, {wxPaintDC, new_1, 1}},
+ {744, {wxPaintDC, 'Destroy', undefined}},
+ {746, {wxMemoryDC, new_1_0, 1}},
+ {747, {wxMemoryDC, new_1_1, 1}},
+ {748, {wxMemoryDC, new_0, 0}},
+ {750, {wxMemoryDC, destruct, 0}},
+ {751, {wxMemoryDC, selectObject, 1}},
+ {752, {wxMemoryDC, selectObjectAsSource, 1}},
+ {753, {wxBufferedDC, new_0, 0}},
+ {754, {wxBufferedDC, new_2, 2}},
+ {755, {wxBufferedDC, new_3, 3}},
+ {756, {wxBufferedDC, destruct, 0}},
+ {757, {wxBufferedDC, init_2, 2}},
+ {758, {wxBufferedDC, init_3, 3}},
+ {759, {wxBufferedPaintDC, new_3, 3}},
+ {760, {wxBufferedPaintDC, new_2, 2}},
+ {761, {wxBufferedPaintDC, destruct, 0}},
+ {762, {wxGraphicsObject, destruct, 0}},
+ {763, {wxGraphicsObject, getRenderer, 0}},
+ {764, {wxGraphicsObject, isNull, 0}},
+ {765, {wxGraphicsContext, destruct, 0}},
+ {766, {wxGraphicsContext, create_1_1, 1}},
+ {767, {wxGraphicsContext, create_1_0, 1}},
+ {768, {wxGraphicsContext, create_0, 0}},
+ {769, {wxGraphicsContext, createPen, 1}},
+ {770, {wxGraphicsContext, createBrush, 1}},
+ {771, {wxGraphicsContext, createRadialGradientBrush, 7}},
+ {772, {wxGraphicsContext, createLinearGradientBrush, 6}},
+ {773, {wxGraphicsContext, createFont, 2}},
+ {774, {wxGraphicsContext, createMatrix, 1}},
+ {775, {wxGraphicsContext, createPath, 0}},
+ {776, {wxGraphicsContext, clip_1, 1}},
+ {777, {wxGraphicsContext, clip_4, 4}},
+ {778, {wxGraphicsContext, resetClip, 0}},
+ {779, {wxGraphicsContext, drawBitmap, 5}},
+ {780, {wxGraphicsContext, drawEllipse, 4}},
+ {781, {wxGraphicsContext, drawIcon, 5}},
+ {782, {wxGraphicsContext, drawLines, 3}},
+ {783, {wxGraphicsContext, drawPath, 2}},
+ {784, {wxGraphicsContext, drawRectangle, 4}},
+ {785, {wxGraphicsContext, drawRoundedRectangle, 5}},
+ {786, {wxGraphicsContext, drawText_3, 3}},
+ {787, {wxGraphicsContext, drawText_4_0, 4}},
+ {788, {wxGraphicsContext, drawText_4_1, 4}},
+ {789, {wxGraphicsContext, drawText_5, 5}},
+ {790, {wxGraphicsContext, fillPath, 2}},
+ {791, {wxGraphicsContext, strokePath, 1}},
+ {792, {wxGraphicsContext, getPartialTextExtents, 2}},
+ {793, {wxGraphicsContext, getTextExtent, 5}},
+ {794, {wxGraphicsContext, rotate, 1}},
+ {795, {wxGraphicsContext, scale, 2}},
+ {796, {wxGraphicsContext, translate, 2}},
+ {797, {wxGraphicsContext, getTransform, 0}},
+ {798, {wxGraphicsContext, setTransform, 1}},
+ {799, {wxGraphicsContext, concatTransform, 1}},
+ {800, {wxGraphicsContext, setBrush_1_1, 1}},
+ {801, {wxGraphicsContext, setBrush_1_0, 1}},
+ {802, {wxGraphicsContext, setFont_1, 1}},
+ {803, {wxGraphicsContext, setFont_2, 2}},
+ {804, {wxGraphicsContext, setPen_1_0, 1}},
+ {805, {wxGraphicsContext, setPen_1_1, 1}},
+ {806, {wxGraphicsContext, strokeLine, 4}},
+ {807, {wxGraphicsContext, strokeLines, 2}},
+ {809, {wxGraphicsMatrix, concat, 1}},
+ {811, {wxGraphicsMatrix, get, 1}},
+ {812, {wxGraphicsMatrix, invert, 0}},
+ {813, {wxGraphicsMatrix, isEqual, 1}},
+ {815, {wxGraphicsMatrix, isIdentity, 0}},
+ {816, {wxGraphicsMatrix, rotate, 1}},
+ {817, {wxGraphicsMatrix, scale, 2}},
+ {818, {wxGraphicsMatrix, translate, 2}},
+ {819, {wxGraphicsMatrix, set, 1}},
+ {820, {wxGraphicsMatrix, transformPoint, 2}},
+ {821, {wxGraphicsMatrix, transformDistance, 2}},
+ {822, {wxGraphicsPath, moveToPoint_2, 2}},
+ {823, {wxGraphicsPath, moveToPoint_1, 1}},
+ {824, {wxGraphicsPath, addArc_6, 6}},
+ {825, {wxGraphicsPath, addArc_5, 5}},
+ {826, {wxGraphicsPath, addArcToPoint, 5}},
+ {827, {wxGraphicsPath, addCircle, 3}},
+ {828, {wxGraphicsPath, addCurveToPoint_6, 6}},
+ {829, {wxGraphicsPath, addCurveToPoint_3, 3}},
+ {830, {wxGraphicsPath, addEllipse, 4}},
+ {831, {wxGraphicsPath, addLineToPoint_2, 2}},
+ {832, {wxGraphicsPath, addLineToPoint_1, 1}},
+ {833, {wxGraphicsPath, addPath, 1}},
+ {834, {wxGraphicsPath, addQuadCurveToPoint, 4}},
+ {835, {wxGraphicsPath, addRectangle, 4}},
+ {836, {wxGraphicsPath, addRoundedRectangle, 5}},
+ {837, {wxGraphicsPath, closeSubpath, 0}},
+ {838, {wxGraphicsPath, contains_3, 3}},
+ {839, {wxGraphicsPath, contains_2, 2}},
+ {841, {wxGraphicsPath, getBox, 0}},
+ {843, {wxGraphicsPath, getCurrentPoint, 0}},
+ {844, {wxGraphicsPath, transform, 1}},
+ {845, {wxGraphicsRenderer, getDefaultRenderer, 0}},
+ {846, {wxGraphicsRenderer, createContext_1_1, 1}},
+ {847, {wxGraphicsRenderer, createContext_1_0, 1}},
+ {848, {wxGraphicsRenderer, createPen, 1}},
+ {849, {wxGraphicsRenderer, createBrush, 1}},
+ {850, {wxGraphicsRenderer, createLinearGradientBrush, 6}},
+ {851, {wxGraphicsRenderer, createRadialGradientBrush, 7}},
+ {852, {wxGraphicsRenderer, createFont, 2}},
+ {853, {wxGraphicsRenderer, createMatrix, 1}},
+ {854, {wxGraphicsRenderer, createPath, 0}},
+ {856, {wxMenuBar, new_1, 1}},
+ {858, {wxMenuBar, new_0, 0}},
+ {860, {wxMenuBar, destruct, 0}},
+ {861, {wxMenuBar, append, 2}},
+ {862, {wxMenuBar, check, 2}},
+ {863, {wxMenuBar, enable_2, 2}},
+ {864, {wxMenuBar, enable_1, 1}},
+ {865, {wxMenuBar, enableTop, 2}},
+ {866, {wxMenuBar, findMenu, 1}},
+ {867, {wxMenuBar, findMenuItem, 2}},
+ {868, {wxMenuBar, findItem, 2}},
+ {869, {wxMenuBar, getHelpString, 1}},
+ {870, {wxMenuBar, getLabel_1, 1}},
+ {871, {wxMenuBar, getLabel_0, 0}},
+ {872, {wxMenuBar, getLabelTop, 1}},
+ {873, {wxMenuBar, getMenu, 1}},
+ {874, {wxMenuBar, getMenuCount, 0}},
+ {875, {wxMenuBar, insert, 3}},
+ {876, {wxMenuBar, isChecked, 1}},
+ {877, {wxMenuBar, isEnabled_1, 1}},
+ {878, {wxMenuBar, isEnabled_0, 0}},
+ {879, {wxMenuBar, remove, 1}},
+ {880, {wxMenuBar, replace, 3}},
+ {881, {wxMenuBar, setHelpString, 2}},
+ {882, {wxMenuBar, setLabel_2, 2}},
+ {883, {wxMenuBar, setLabel_1, 1}},
+ {884, {wxMenuBar, setLabelTop, 2}},
+ {885, {wxControl, getLabel, 0}},
+ {886, {wxControl, setLabel, 1}},
+ {887, {wxControlWithItems, append_1, 1}},
+ {888, {wxControlWithItems, append_2, 2}},
+ {889, {wxControlWithItems, appendStrings_1, 1}},
+ {890, {wxControlWithItems, clear, 0}},
+ {891, {wxControlWithItems, delete, 1}},
+ {892, {wxControlWithItems, findString, 2}},
+ {893, {wxControlWithItems, getClientData, 1}},
+ {894, {wxControlWithItems, setClientData, 2}},
+ {895, {wxControlWithItems, getCount, 0}},
+ {896, {wxControlWithItems, getSelection, 0}},
+ {897, {wxControlWithItems, getString, 1}},
+ {898, {wxControlWithItems, getStringSelection, 0}},
+ {899, {wxControlWithItems, insert_2, 2}},
+ {900, {wxControlWithItems, insert_3, 3}},
+ {901, {wxControlWithItems, isEmpty, 0}},
+ {902, {wxControlWithItems, select, 1}},
+ {903, {wxControlWithItems, setSelection, 1}},
+ {904, {wxControlWithItems, setString, 2}},
+ {905, {wxControlWithItems, setStringSelection, 1}},
+ {908, {wxMenu, new_2, 2}},
+ {909, {wxMenu, new_1, 1}},
+ {911, {wxMenu, destruct, 0}},
+ {912, {wxMenu, append_3, 3}},
+ {913, {wxMenu, append_1, 1}},
+ {914, {wxMenu, append_4_0, 4}},
+ {915, {wxMenu, append_4_1, 4}},
+ {916, {wxMenu, appendCheckItem, 3}},
+ {917, {wxMenu, appendRadioItem, 3}},
+ {918, {wxMenu, appendSeparator, 0}},
+ {919, {wxMenu, break, 0}},
+ {920, {wxMenu, check, 2}},
+ {921, {wxMenu, delete_1_0, 1}},
+ {922, {wxMenu, delete_1_1, 1}},
+ {923, {wxMenu, destroy_1_0, 1}},
+ {924, {wxMenu, destroy_1_1, 1}},
+ {925, {wxMenu, enable, 2}},
+ {926, {wxMenu, findItem_1, 1}},
+ {927, {wxMenu, findItem_2, 2}},
+ {928, {wxMenu, findItemByPosition, 1}},
+ {929, {wxMenu, getHelpString, 1}},
+ {930, {wxMenu, getLabel, 1}},
+ {931, {wxMenu, getMenuItemCount, 0}},
+ {932, {wxMenu, getMenuItems, 0}},
+ {934, {wxMenu, getTitle, 0}},
+ {935, {wxMenu, insert_2, 2}},
+ {936, {wxMenu, insert_3, 3}},
+ {937, {wxMenu, insert_5_1, 5}},
+ {938, {wxMenu, insert_5_0, 5}},
+ {939, {wxMenu, insertCheckItem, 4}},
+ {940, {wxMenu, insertRadioItem, 4}},
+ {941, {wxMenu, insertSeparator, 1}},
+ {942, {wxMenu, isChecked, 1}},
+ {943, {wxMenu, isEnabled, 1}},
+ {944, {wxMenu, prepend_1, 1}},
+ {945, {wxMenu, prepend_2, 2}},
+ {946, {wxMenu, prepend_4_1, 4}},
+ {947, {wxMenu, prepend_4_0, 4}},
+ {948, {wxMenu, prependCheckItem, 3}},
+ {949, {wxMenu, prependRadioItem, 3}},
+ {950, {wxMenu, prependSeparator, 0}},
+ {951, {wxMenu, remove_1_0, 1}},
+ {952, {wxMenu, remove_1_1, 1}},
+ {953, {wxMenu, setHelpString, 2}},
+ {954, {wxMenu, setLabel, 2}},
+ {955, {wxMenu, setTitle, 1}},
+ {956, {wxMenuItem, new, 1}},
+ {958, {wxMenuItem, destruct, 0}},
+ {959, {wxMenuItem, check, 1}},
+ {960, {wxMenuItem, enable, 1}},
+ {961, {wxMenuItem, getBitmap, 0}},
+ {962, {wxMenuItem, getHelp, 0}},
+ {963, {wxMenuItem, getId, 0}},
+ {964, {wxMenuItem, getKind, 0}},
+ {965, {wxMenuItem, getLabel, 0}},
+ {966, {wxMenuItem, getLabelFromText, 1}},
+ {967, {wxMenuItem, getMenu, 0}},
+ {968, {wxMenuItem, getText, 0}},
+ {969, {wxMenuItem, getSubMenu, 0}},
+ {970, {wxMenuItem, isCheckable, 0}},
+ {971, {wxMenuItem, isChecked, 0}},
+ {972, {wxMenuItem, isEnabled, 0}},
+ {973, {wxMenuItem, isSeparator, 0}},
+ {974, {wxMenuItem, isSubMenu, 0}},
+ {975, {wxMenuItem, setBitmap, 1}},
+ {976, {wxMenuItem, setHelp, 1}},
+ {977, {wxMenuItem, setMenu, 1}},
+ {978, {wxMenuItem, setSubMenu, 1}},
+ {979, {wxMenuItem, setText, 1}},
+ {980, {wxToolBar, addControl, 1}},
+ {981, {wxToolBar, addSeparator, 0}},
+ {982, {wxToolBar, addTool_5, 5}},
+ {983, {wxToolBar, addTool_4_0, 4}},
+ {984, {wxToolBar, addTool_1, 1}},
+ {985, {wxToolBar, addTool_4_1, 4}},
+ {986, {wxToolBar, addTool_3, 3}},
+ {987, {wxToolBar, addTool_6, 6}},
+ {988, {wxToolBar, addCheckTool, 4}},
+ {989, {wxToolBar, addRadioTool, 4}},
+ {990, {wxToolBar, addStretchableSpace, 0}},
+ {991, {wxToolBar, insertStretchableSpace, 1}},
+ {992, {wxToolBar, deleteTool, 1}},
+ {993, {wxToolBar, deleteToolByPos, 1}},
+ {994, {wxToolBar, enableTool, 2}},
+ {995, {wxToolBar, findById, 1}},
+ {996, {wxToolBar, findControl, 1}},
+ {997, {wxToolBar, findToolForPosition, 2}},
+ {998, {wxToolBar, getToolSize, 0}},
+ {999, {wxToolBar, getToolBitmapSize, 0}},
+ {1000, {wxToolBar, getMargins, 0}},
+ {1001, {wxToolBar, getToolEnabled, 1}},
+ {1002, {wxToolBar, getToolLongHelp, 1}},
+ {1003, {wxToolBar, getToolPacking, 0}},
+ {1004, {wxToolBar, getToolPos, 1}},
+ {1005, {wxToolBar, getToolSeparation, 0}},
+ {1006, {wxToolBar, getToolShortHelp, 1}},
+ {1007, {wxToolBar, getToolState, 1}},
+ {1008, {wxToolBar, insertControl, 2}},
+ {1009, {wxToolBar, insertSeparator, 1}},
+ {1010, {wxToolBar, insertTool_5, 5}},
+ {1011, {wxToolBar, insertTool_2, 2}},
+ {1012, {wxToolBar, insertTool_4, 4}},
+ {1013, {wxToolBar, realize, 0}},
+ {1014, {wxToolBar, removeTool, 1}},
+ {1015, {wxToolBar, setMargins, 2}},
+ {1016, {wxToolBar, setToolBitmapSize, 1}},
+ {1017, {wxToolBar, setToolLongHelp, 2}},
+ {1018, {wxToolBar, setToolPacking, 1}},
+ {1019, {wxToolBar, setToolShortHelp, 2}},
+ {1020, {wxToolBar, setToolSeparation, 1}},
+ {1021, {wxToolBar, toggleTool, 2}},
+ {1023, {wxStatusBar, new_0, 0}},
+ {1024, {wxStatusBar, new_2, 2}},
+ {1026, {wxStatusBar, destruct, 0}},
+ {1027, {wxStatusBar, create, 2}},
+ {1028, {wxStatusBar, getFieldRect, 2}},
+ {1029, {wxStatusBar, getFieldsCount, 0}},
+ {1030, {wxStatusBar, getStatusText, 1}},
+ {1031, {wxStatusBar, popStatusText, 1}},
+ {1032, {wxStatusBar, pushStatusText, 2}},
+ {1033, {wxStatusBar, setFieldsCount, 2}},
+ {1034, {wxStatusBar, setMinHeight, 1}},
+ {1035, {wxStatusBar, setStatusText, 2}},
+ {1036, {wxStatusBar, setStatusWidths, 2}},
+ {1037, {wxStatusBar, setStatusStyles, 2}},
+ {1038, {wxBitmap, new_0, 0}},
+ {1039, {wxBitmap, new_3, 3}},
+ {1040, {wxBitmap, new_4, 4}},
+ {1041, {wxBitmap, new_2_0, 2}},
+ {1042, {wxBitmap, new_2_1, 2}},
+ {1043, {wxBitmap, destruct, 0}},
+ {1044, {wxBitmap, convertToImage, 0}},
+ {1045, {wxBitmap, copyFromIcon, 1}},
+ {1046, {wxBitmap, create, 3}},
+ {1047, {wxBitmap, getDepth, 0}},
+ {1048, {wxBitmap, getHeight, 0}},
+ {1049, {wxBitmap, getPalette, 0}},
+ {1050, {wxBitmap, getMask, 0}},
+ {1051, {wxBitmap, getWidth, 0}},
+ {1052, {wxBitmap, getSubBitmap, 1}},
+ {1053, {wxBitmap, loadFile, 2}},
+ {1054, {wxBitmap, ok, 0}},
+ {1055, {wxBitmap, saveFile, 3}},
+ {1056, {wxBitmap, setDepth, 1}},
+ {1057, {wxBitmap, setHeight, 1}},
+ {1058, {wxBitmap, setMask, 1}},
+ {1059, {wxBitmap, setPalette, 1}},
+ {1060, {wxBitmap, setWidth, 1}},
+ {1061, {wxIcon, new_0, 0}},
+ {1062, {wxIcon, new_2, 2}},
+ {1063, {wxIcon, new_1, 1}},
+ {1064, {wxIcon, copyFromBitmap, 1}},
+ {1065, {wxIcon, 'Destroy', undefined}},
+ {1066, {wxIconBundle, new_0, 0}},
+ {1067, {wxIconBundle, new_2, 2}},
+ {1068, {wxIconBundle, new_1_0, 1}},
+ {1069, {wxIconBundle, new_1_1, 1}},
+ {1070, {wxIconBundle, destruct, 0}},
+ {1071, {wxIconBundle, addIcon_2, 2}},
+ {1072, {wxIconBundle, addIcon_1, 1}},
+ {1073, {wxIconBundle, getIcon_1_1, 1}},
+ {1074, {wxIconBundle, getIcon_1_0, 1}},
+ {1075, {wxCursor, new_0, 0}},
+ {1076, {wxCursor, new_1_0, 1}},
+ {1077, {wxCursor, new_1_1, 1}},
+ {1078, {wxCursor, new_4, 4}},
+ {1079, {wxCursor, destruct, 0}},
+ {1080, {wxCursor, ok, 0}},
+ {1081, {wxMask, new_0, 0}},
+ {1082, {wxMask, new_2_1, 2}},
+ {1083, {wxMask, new_2_0, 2}},
+ {1084, {wxMask, new_1, 1}},
+ {1085, {wxMask, destruct, 0}},
+ {1086, {wxMask, create_2_1, 2}},
+ {1087, {wxMask, create_2_0, 2}},
+ {1088, {wxMask, create_1, 1}},
+ {1089, {wxImage, new_0, 0}},
+ {1090, {wxImage, new_3_0, 3}},
+ {1091, {wxImage, new_4, 4}},
+ {1092, {wxImage, new_5, 5}},
+ {1093, {wxImage, new_2, 2}},
+ {1094, {wxImage, new_3_1, 3}},
+ {1095, {wxImage, blur, 1}},
+ {1096, {wxImage, blurHorizontal, 1}},
+ {1097, {wxImage, blurVertical, 1}},
+ {1098, {wxImage, convertAlphaToMask, 1}},
+ {1099, {wxImage, convertToGreyscale, 1}},
+ {1100, {wxImage, convertToMono, 3}},
+ {1101, {wxImage, copy, 0}},
+ {1102, {wxImage, create_3, 3}},
+ {1103, {wxImage, create_4, 4}},
+ {1104, {wxImage, create_5, 5}},
+ {1105, {wxImage, 'Destroy', 0}},
+ {1106, {wxImage, findFirstUnusedColour, 4}},
+ {1107, {wxImage, getImageExtWildcard, 0}},
+ {1108, {wxImage, getAlpha_2, 2}},
+ {1109, {wxImage, getAlpha_0, 0}},
+ {1110, {wxImage, getBlue, 2}},
+ {1111, {wxImage, getData, 0}},
+ {1112, {wxImage, getGreen, 2}},
+ {1113, {wxImage, getImageCount, 2}},
+ {1114, {wxImage, getHeight, 0}},
+ {1115, {wxImage, getMaskBlue, 0}},
+ {1116, {wxImage, getMaskGreen, 0}},
+ {1117, {wxImage, getMaskRed, 0}},
+ {1118, {wxImage, getOrFindMaskColour, 3}},
+ {1119, {wxImage, getPalette, 0}},
+ {1120, {wxImage, getRed, 2}},
+ {1121, {wxImage, getSubImage, 1}},
+ {1122, {wxImage, getWidth, 0}},
+ {1123, {wxImage, hasAlpha, 0}},
+ {1124, {wxImage, hasMask, 0}},
+ {1125, {wxImage, getOption, 1}},
+ {1126, {wxImage, getOptionInt, 1}},
+ {1127, {wxImage, hasOption, 1}},
+ {1128, {wxImage, initAlpha, 0}},
+ {1129, {wxImage, initStandardHandlers, 0}},
+ {1130, {wxImage, isTransparent, 3}},
+ {1131, {wxImage, loadFile_2, 2}},
+ {1132, {wxImage, loadFile_3, 3}},
+ {1133, {wxImage, ok, 0}},
+ {1134, {wxImage, removeHandler, 1}},
+ {1135, {wxImage, mirror, 1}},
+ {1136, {wxImage, replace, 6}},
+ {1137, {wxImage, rescale, 3}},
+ {1138, {wxImage, resize, 3}},
+ {1139, {wxImage, rotate, 3}},
+ {1140, {wxImage, rotateHue, 1}},
+ {1141, {wxImage, rotate90, 1}},
+ {1142, {wxImage, saveFile_1, 1}},
+ {1143, {wxImage, saveFile_2_0, 2}},
+ {1144, {wxImage, saveFile_2_1, 2}},
+ {1145, {wxImage, scale, 3}},
+ {1146, {wxImage, size, 3}},
+ {1147, {wxImage, setAlpha_3, 3}},
+ {1148, {wxImage, setAlpha_2, 2}},
+ {1149, {wxImage, setData_2, 2}},
+ {1150, {wxImage, setData_4, 4}},
+ {1151, {wxImage, setMask, 1}},
+ {1152, {wxImage, setMaskColour, 3}},
+ {1153, {wxImage, setMaskFromImage, 4}},
+ {1154, {wxImage, setOption_2_1, 2}},
+ {1155, {wxImage, setOption_2_0, 2}},
+ {1156, {wxImage, setPalette, 1}},
+ {1157, {wxImage, setRGB_5, 5}},
+ {1158, {wxImage, setRGB_4, 4}},
+ {1159, {wxImage, 'Destroy', undefined}},
+ {1160, {wxBrush, new_0, 0}},
+ {1161, {wxBrush, new_2, 2}},
+ {1162, {wxBrush, new_1, 1}},
+ {1164, {wxBrush, destruct, 0}},
+ {1165, {wxBrush, getColour, 0}},
+ {1166, {wxBrush, getStipple, 0}},
+ {1167, {wxBrush, getStyle, 0}},
+ {1168, {wxBrush, isHatch, 0}},
+ {1169, {wxBrush, isOk, 0}},
+ {1170, {wxBrush, setColour_1, 1}},
+ {1171, {wxBrush, setColour_3, 3}},
+ {1172, {wxBrush, setStipple, 1}},
+ {1173, {wxBrush, setStyle, 1}},
+ {1174, {wxPen, new_0, 0}},
+ {1175, {wxPen, new_2, 2}},
+ {1176, {wxPen, destruct, 0}},
+ {1177, {wxPen, getCap, 0}},
+ {1178, {wxPen, getColour, 0}},
+ {1179, {wxPen, getJoin, 0}},
+ {1180, {wxPen, getStyle, 0}},
+ {1181, {wxPen, getWidth, 0}},
+ {1182, {wxPen, isOk, 0}},
+ {1183, {wxPen, setCap, 1}},
+ {1184, {wxPen, setColour_1, 1}},
+ {1185, {wxPen, setColour_3, 3}},
+ {1186, {wxPen, setJoin, 1}},
+ {1187, {wxPen, setStyle, 1}},
+ {1188, {wxPen, setWidth, 1}},
+ {1189, {wxRegion, new_0, 0}},
+ {1190, {wxRegion, new_4, 4}},
+ {1191, {wxRegion, new_2, 2}},
+ {1192, {wxRegion, new_1_1, 1}},
+ {1194, {wxRegion, new_1_0, 1}},
+ {1196, {wxRegion, destruct, 0}},
+ {1197, {wxRegion, clear, 0}},
+ {1198, {wxRegion, contains_2, 2}},
+ {1199, {wxRegion, contains_1_0, 1}},
+ {1200, {wxRegion, contains_4, 4}},
+ {1201, {wxRegion, contains_1_1, 1}},
+ {1202, {wxRegion, convertToBitmap, 0}},
+ {1203, {wxRegion, getBox, 0}},
+ {1204, {wxRegion, intersect_4, 4}},
+ {1205, {wxRegion, intersect_1_1, 1}},
+ {1206, {wxRegion, intersect_1_0, 1}},
+ {1207, {wxRegion, isEmpty, 0}},
+ {1208, {wxRegion, subtract_4, 4}},
+ {1209, {wxRegion, subtract_1_1, 1}},
+ {1210, {wxRegion, subtract_1_0, 1}},
+ {1211, {wxRegion, offset_2, 2}},
+ {1212, {wxRegion, offset_1, 1}},
+ {1213, {wxRegion, union_4, 4}},
+ {1214, {wxRegion, union_1_2, 1}},
+ {1215, {wxRegion, union_1_1, 1}},
+ {1216, {wxRegion, union_1_0, 1}},
+ {1217, {wxRegion, union_3, 3}},
+ {1218, {wxRegion, xor_4, 4}},
+ {1219, {wxRegion, xor_1_1, 1}},
+ {1220, {wxRegion, xor_1_0, 1}},
+ {1221, {wxAcceleratorTable, new_0, 0}},
+ {1222, {wxAcceleratorTable, new_2, 2}},
+ {1223, {wxAcceleratorTable, destruct, 0}},
+ {1224, {wxAcceleratorTable, ok, 0}},
+ {1225, {wxAcceleratorEntry, new_1_0, 1}},
+ {1226, {wxAcceleratorEntry, new_1_1, 1}},
+ {1227, {wxAcceleratorEntry, getCommand, 0}},
+ {1228, {wxAcceleratorEntry, getFlags, 0}},
+ {1229, {wxAcceleratorEntry, getKeyCode, 0}},
+ {1230, {wxAcceleratorEntry, set, 4}},
+ {1231, {wxAcceleratorEntry, 'Destroy', undefined}},
+ {1236, {wxCaret, new_3, 3}},
+ {1237, {wxCaret, new_2, 2}},
+ {1239, {wxCaret, destruct, 0}},
+ {1240, {wxCaret, create_3, 3}},
+ {1241, {wxCaret, create_2, 2}},
+ {1242, {wxCaret, getBlinkTime, 0}},
+ {1244, {wxCaret, getPosition, 0}},
+ {1246, {wxCaret, getSize, 0}},
+ {1247, {wxCaret, getWindow, 0}},
+ {1248, {wxCaret, hide, 0}},
+ {1249, {wxCaret, isOk, 0}},
+ {1250, {wxCaret, isVisible, 0}},
+ {1251, {wxCaret, move_2, 2}},
+ {1252, {wxCaret, move_1, 1}},
+ {1253, {wxCaret, setBlinkTime, 1}},
+ {1254, {wxCaret, setSize_2, 2}},
+ {1255, {wxCaret, setSize_1, 1}},
+ {1256, {wxCaret, show, 1}},
+ {1257, {wxSizer, add_2_1, 2}},
+ {1258, {wxSizer, add_2_0, 2}},
+ {1259, {wxSizer, add_3, 3}},
+ {1260, {wxSizer, add_2_3, 2}},
+ {1261, {wxSizer, add_2_2, 2}},
+ {1262, {wxSizer, addSpacer, 1}},
+ {1263, {wxSizer, addStretchSpacer, 1}},
+ {1264, {wxSizer, calcMin, 0}},
+ {1265, {wxSizer, clear, 1}},
+ {1266, {wxSizer, detach_1_2, 1}},
+ {1267, {wxSizer, detach_1_1, 1}},
+ {1268, {wxSizer, detach_1_0, 1}},
+ {1269, {wxSizer, fit, 1}},
+ {1270, {wxSizer, fitInside, 1}},
+ {1271, {wxSizer, getChildren, 0}},
+ {1272, {wxSizer, getItem_2_1, 2}},
+ {1273, {wxSizer, getItem_2_0, 2}},
+ {1274, {wxSizer, getItem_1, 1}},
+ {1275, {wxSizer, getSize, 0}},
+ {1276, {wxSizer, getPosition, 0}},
+ {1277, {wxSizer, getMinSize, 0}},
+ {1278, {wxSizer, hide_2_0, 2}},
+ {1279, {wxSizer, hide_2_1, 2}},
+ {1280, {wxSizer, hide_1, 1}},
+ {1281, {wxSizer, insert_3_1, 3}},
+ {1282, {wxSizer, insert_3_0, 3}},
+ {1283, {wxSizer, insert_4, 4}},
+ {1284, {wxSizer, insert_3_3, 3}},
+ {1285, {wxSizer, insert_3_2, 3}},
+ {1286, {wxSizer, insert_2, 2}},
+ {1287, {wxSizer, insertSpacer, 2}},
+ {1288, {wxSizer, insertStretchSpacer, 2}},
+ {1289, {wxSizer, isShown_1_2, 1}},
+ {1290, {wxSizer, isShown_1_1, 1}},
+ {1291, {wxSizer, isShown_1_0, 1}},
+ {1292, {wxSizer, layout, 0}},
+ {1293, {wxSizer, prepend_2_1, 2}},
+ {1294, {wxSizer, prepend_2_0, 2}},
+ {1295, {wxSizer, prepend_3, 3}},
+ {1296, {wxSizer, prepend_2_3, 2}},
+ {1297, {wxSizer, prepend_2_2, 2}},
+ {1298, {wxSizer, prepend_1, 1}},
+ {1299, {wxSizer, prependSpacer, 1}},
+ {1300, {wxSizer, prependStretchSpacer, 1}},
+ {1301, {wxSizer, recalcSizes, 0}},
+ {1302, {wxSizer, remove_1_1, 1}},
+ {1303, {wxSizer, remove_1_0, 1}},
+ {1304, {wxSizer, replace_3_1, 3}},
+ {1305, {wxSizer, replace_3_0, 3}},
+ {1306, {wxSizer, replace_2, 2}},
+ {1307, {wxSizer, setDimension, 4}},
+ {1308, {wxSizer, setMinSize_2, 2}},
+ {1309, {wxSizer, setMinSize_1, 1}},
+ {1310, {wxSizer, setItemMinSize_3_2, 3}},
+ {1311, {wxSizer, setItemMinSize_2_2, 2}},
+ {1312, {wxSizer, setItemMinSize_3_1, 3}},
+ {1313, {wxSizer, setItemMinSize_2_1, 2}},
+ {1314, {wxSizer, setItemMinSize_3_0, 3}},
+ {1315, {wxSizer, setItemMinSize_2_0, 2}},
+ {1316, {wxSizer, setSizeHints, 1}},
+ {1317, {wxSizer, setVirtualSizeHints, 1}},
+ {1318, {wxSizer, show_2_2, 2}},
+ {1319, {wxSizer, show_2_1, 2}},
+ {1320, {wxSizer, show_2_0, 2}},
+ {1321, {wxSizer, show_1, 1}},
+ {1322, {wxSizerFlags, new, 1}},
+ {1323, {wxSizerFlags, align, 1}},
+ {1324, {wxSizerFlags, border_2, 2}},
+ {1325, {wxSizerFlags, border_1, 1}},
+ {1326, {wxSizerFlags, center, 0}},
+ {1327, {wxSizerFlags, centre, 0}},
+ {1328, {wxSizerFlags, expand, 0}},
+ {1329, {wxSizerFlags, left, 0}},
+ {1330, {wxSizerFlags, proportion, 1}},
+ {1331, {wxSizerFlags, right, 0}},
+ {1332, {wxSizerFlags, 'Destroy', undefined}},
+ {1333, {wxSizerItem, new_5_1, 5}},
+ {1334, {wxSizerItem, new_2_1, 2}},
+ {1335, {wxSizerItem, new_5_0, 5}},
+ {1336, {wxSizerItem, new_2_0, 2}},
+ {1337, {wxSizerItem, new_6, 6}},
+ {1338, {wxSizerItem, new_3, 3}},
+ {1339, {wxSizerItem, new_0, 0}},
+ {1340, {wxSizerItem, destruct, 0}},
+ {1341, {wxSizerItem, calcMin, 0}},
+ {1342, {wxSizerItem, deleteWindows, 0}},
+ {1343, {wxSizerItem, detachSizer, 0}},
+ {1344, {wxSizerItem, getBorder, 0}},
+ {1345, {wxSizerItem, getFlag, 0}},
+ {1346, {wxSizerItem, getMinSize, 0}},
+ {1347, {wxSizerItem, getPosition, 0}},
+ {1348, {wxSizerItem, getProportion, 0}},
+ {1349, {wxSizerItem, getRatio, 0}},
+ {1350, {wxSizerItem, getRect, 0}},
+ {1351, {wxSizerItem, getSize, 0}},
+ {1352, {wxSizerItem, getSizer, 0}},
+ {1353, {wxSizerItem, getSpacer, 0}},
+ {1354, {wxSizerItem, getUserData, 0}},
+ {1355, {wxSizerItem, getWindow, 0}},
+ {1356, {wxSizerItem, isSizer, 0}},
+ {1357, {wxSizerItem, isShown, 0}},
+ {1358, {wxSizerItem, isSpacer, 0}},
+ {1359, {wxSizerItem, isWindow, 0}},
+ {1360, {wxSizerItem, setBorder, 1}},
+ {1361, {wxSizerItem, setDimension, 2}},
+ {1362, {wxSizerItem, setFlag, 1}},
+ {1363, {wxSizerItem, setInitSize, 2}},
+ {1364, {wxSizerItem, setMinSize_1, 1}},
+ {1365, {wxSizerItem, setMinSize_2, 2}},
+ {1366, {wxSizerItem, setProportion, 1}},
+ {1367, {wxSizerItem, setRatio_2, 2}},
+ {1368, {wxSizerItem, setRatio_1_1, 1}},
+ {1369, {wxSizerItem, setRatio_1_0, 1}},
+ {1370, {wxSizerItem, setSizer, 1}},
+ {1371, {wxSizerItem, setSpacer_1, 1}},
+ {1372, {wxSizerItem, setSpacer_2, 2}},
+ {1373, {wxSizerItem, setWindow, 1}},
+ {1374, {wxSizerItem, show, 1}},
+ {1375, {wxBoxSizer, new, 1}},
+ {1376, {wxBoxSizer, getOrientation, 0}},
+ {1377, {wxBoxSizer, 'Destroy', undefined}},
+ {1378, {wxStaticBoxSizer, new_2, 2}},
+ {1379, {wxStaticBoxSizer, new_3, 3}},
+ {1380, {wxStaticBoxSizer, getStaticBox, 0}},
+ {1381, {wxStaticBoxSizer, 'Destroy', undefined}},
+ {1382, {wxGridSizer, new_4, 4}},
+ {1383, {wxGridSizer, new_2, 2}},
+ {1384, {wxGridSizer, getCols, 0}},
+ {1385, {wxGridSizer, getHGap, 0}},
+ {1386, {wxGridSizer, getRows, 0}},
+ {1387, {wxGridSizer, getVGap, 0}},
+ {1388, {wxGridSizer, setCols, 1}},
+ {1389, {wxGridSizer, setHGap, 1}},
+ {1390, {wxGridSizer, setRows, 1}},
+ {1391, {wxGridSizer, setVGap, 1}},
+ {1392, {wxGridSizer, 'Destroy', undefined}},
+ {1393, {wxFlexGridSizer, new_4, 4}},
+ {1394, {wxFlexGridSizer, new_2, 2}},
+ {1395, {wxFlexGridSizer, addGrowableCol, 2}},
+ {1396, {wxFlexGridSizer, addGrowableRow, 2}},
+ {1397, {wxFlexGridSizer, getFlexibleDirection, 0}},
+ {1398, {wxFlexGridSizer, getNonFlexibleGrowMode, 0}},
+ {1399, {wxFlexGridSizer, removeGrowableCol, 1}},
+ {1400, {wxFlexGridSizer, removeGrowableRow, 1}},
+ {1401, {wxFlexGridSizer, setFlexibleDirection, 1}},
+ {1402, {wxFlexGridSizer, setNonFlexibleGrowMode, 1}},
+ {1403, {wxFlexGridSizer, 'Destroy', undefined}},
+ {1404, {wxGridBagSizer, new, 1}},
+ {1405, {wxGridBagSizer, add_3_2, 3}},
+ {1406, {wxGridBagSizer, add_3_1, 3}},
+ {1407, {wxGridBagSizer, add_4, 4}},
+ {1408, {wxGridBagSizer, add_1_0, 1}},
+ {1409, {wxGridBagSizer, add_2_1, 2}},
+ {1410, {wxGridBagSizer, add_2_0, 2}},
+ {1411, {wxGridBagSizer, add_3_0, 3}},
+ {1412, {wxGridBagSizer, add_1_1, 1}},
+ {1413, {wxGridBagSizer, calcMin, 0}},
+ {1414, {wxGridBagSizer, checkForIntersection_2, 2}},
+ {1415, {wxGridBagSizer, checkForIntersection_3, 3}},
+ {1416, {wxGridBagSizer, findItem_1_1, 1}},
+ {1417, {wxGridBagSizer, findItem_1_0, 1}},
+ {1418, {wxGridBagSizer, findItemAtPoint, 1}},
+ {1419, {wxGridBagSizer, findItemAtPosition, 1}},
+ {1420, {wxGridBagSizer, findItemWithData, 1}},
+ {1421, {wxGridBagSizer, getCellSize, 2}},
+ {1422, {wxGridBagSizer, getEmptyCellSize, 0}},
+ {1423, {wxGridBagSizer, getItemPosition_1_2, 1}},
+ {1424, {wxGridBagSizer, getItemPosition_1_1, 1}},
+ {1425, {wxGridBagSizer, getItemPosition_1_0, 1}},
+ {1426, {wxGridBagSizer, getItemSpan_1_2, 1}},
+ {1427, {wxGridBagSizer, getItemSpan_1_1, 1}},
+ {1428, {wxGridBagSizer, getItemSpan_1_0, 1}},
+ {1429, {wxGridBagSizer, setEmptyCellSize, 1}},
+ {1430, {wxGridBagSizer, setItemPosition_2_2, 2}},
+ {1431, {wxGridBagSizer, setItemPosition_2_1, 2}},
+ {1432, {wxGridBagSizer, setItemPosition_2_0, 2}},
+ {1433, {wxGridBagSizer, setItemSpan_2_2, 2}},
+ {1434, {wxGridBagSizer, setItemSpan_2_1, 2}},
+ {1435, {wxGridBagSizer, setItemSpan_2_0, 2}},
+ {1436, {wxGridBagSizer, 'Destroy', undefined}},
+ {1437, {wxStdDialogButtonSizer, new, 0}},
+ {1438, {wxStdDialogButtonSizer, addButton, 1}},
+ {1439, {wxStdDialogButtonSizer, realize, 0}},
+ {1440, {wxStdDialogButtonSizer, setAffirmativeButton, 1}},
+ {1441, {wxStdDialogButtonSizer, setCancelButton, 1}},
+ {1442, {wxStdDialogButtonSizer, setNegativeButton, 1}},
+ {1443, {wxStdDialogButtonSizer, 'Destroy', undefined}},
+ {1444, {wxFont, new_0, 0}},
+ {1445, {wxFont, new_1, 1}},
+ {1446, {wxFont, new_5, 5}},
+ {1448, {wxFont, destruct, 0}},
+ {1449, {wxFont, isFixedWidth, 0}},
+ {1450, {wxFont, getDefaultEncoding, 0}},
+ {1451, {wxFont, getFaceName, 0}},
+ {1452, {wxFont, getFamily, 0}},
+ {1453, {wxFont, getNativeFontInfoDesc, 0}},
+ {1454, {wxFont, getNativeFontInfoUserDesc, 0}},
+ {1455, {wxFont, getPointSize, 0}},
+ {1456, {wxFont, getStyle, 0}},
+ {1457, {wxFont, getUnderlined, 0}},
+ {1458, {wxFont, getWeight, 0}},
+ {1459, {wxFont, ok, 0}},
+ {1460, {wxFont, setDefaultEncoding, 1}},
+ {1461, {wxFont, setFaceName, 1}},
+ {1462, {wxFont, setFamily, 1}},
+ {1463, {wxFont, setPointSize, 1}},
+ {1464, {wxFont, setStyle, 1}},
+ {1465, {wxFont, setUnderlined, 1}},
+ {1466, {wxFont, setWeight, 1}},
+ {1467, {wxToolTip, enable, 1}},
+ {1468, {wxToolTip, setDelay, 1}},
+ {1469, {wxToolTip, new, 1}},
+ {1470, {wxToolTip, setTip, 1}},
+ {1471, {wxToolTip, getTip, 0}},
+ {1472, {wxToolTip, getWindow, 0}},
+ {1473, {wxToolTip, 'Destroy', undefined}},
+ {1475, {wxButton, new_3, 3}},
+ {1476, {wxButton, new_0, 0}},
+ {1477, {wxButton, destruct, 0}},
+ {1478, {wxButton, create, 3}},
+ {1479, {wxButton, getDefaultSize, 0}},
+ {1480, {wxButton, setDefault, 0}},
+ {1481, {wxButton, setLabel, 1}},
+ {1483, {wxBitmapButton, new_4, 4}},
+ {1484, {wxBitmapButton, new_0, 0}},
+ {1485, {wxBitmapButton, create, 4}},
+ {1486, {wxBitmapButton, getBitmapDisabled, 0}},
+ {1488, {wxBitmapButton, getBitmapFocus, 0}},
+ {1490, {wxBitmapButton, getBitmapLabel, 0}},
+ {1492, {wxBitmapButton, getBitmapSelected, 0}},
+ {1494, {wxBitmapButton, setBitmapDisabled, 1}},
+ {1495, {wxBitmapButton, setBitmapFocus, 1}},
+ {1496, {wxBitmapButton, setBitmapLabel, 1}},
+ {1497, {wxBitmapButton, setBitmapSelected, 1}},
+ {1498, {wxBitmapButton, 'Destroy', undefined}},
+ {1499, {wxToggleButton, new_0, 0}},
+ {1500, {wxToggleButton, new_4, 4}},
+ {1501, {wxToggleButton, create, 4}},
+ {1502, {wxToggleButton, getValue, 0}},
+ {1503, {wxToggleButton, setValue, 1}},
+ {1504, {wxToggleButton, 'Destroy', undefined}},
+ {1505, {wxCalendarCtrl, new_0, 0}},
+ {1506, {wxCalendarCtrl, new_3, 3}},
+ {1507, {wxCalendarCtrl, create, 3}},
+ {1508, {wxCalendarCtrl, destruct, 0}},
+ {1509, {wxCalendarCtrl, setDate, 1}},
+ {1510, {wxCalendarCtrl, getDate, 0}},
+ {1511, {wxCalendarCtrl, enableYearChange, 1}},
+ {1512, {wxCalendarCtrl, enableMonthChange, 1}},
+ {1513, {wxCalendarCtrl, enableHolidayDisplay, 1}},
+ {1514, {wxCalendarCtrl, setHeaderColours, 2}},
+ {1515, {wxCalendarCtrl, getHeaderColourFg, 0}},
+ {1516, {wxCalendarCtrl, getHeaderColourBg, 0}},
+ {1517, {wxCalendarCtrl, setHighlightColours, 2}},
+ {1518, {wxCalendarCtrl, getHighlightColourFg, 0}},
+ {1519, {wxCalendarCtrl, getHighlightColourBg, 0}},
+ {1520, {wxCalendarCtrl, setHolidayColours, 2}},
+ {1521, {wxCalendarCtrl, getHolidayColourFg, 0}},
+ {1522, {wxCalendarCtrl, getHolidayColourBg, 0}},
+ {1523, {wxCalendarCtrl, getAttr, 1}},
+ {1524, {wxCalendarCtrl, setAttr, 2}},
+ {1525, {wxCalendarCtrl, setHoliday, 1}},
+ {1526, {wxCalendarCtrl, resetAttr, 1}},
+ {1527, {wxCalendarCtrl, hitTest, 2}},
+ {1528, {wxCalendarDateAttr, new_0, 0}},
+ {1529, {wxCalendarDateAttr, new_2_1, 2}},
+ {1530, {wxCalendarDateAttr, new_2_0, 2}},
+ {1531, {wxCalendarDateAttr, setTextColour, 1}},
+ {1532, {wxCalendarDateAttr, setBackgroundColour, 1}},
+ {1533, {wxCalendarDateAttr, setBorderColour, 1}},
+ {1534, {wxCalendarDateAttr, setFont, 1}},
+ {1535, {wxCalendarDateAttr, setBorder, 1}},
+ {1536, {wxCalendarDateAttr, setHoliday, 1}},
+ {1537, {wxCalendarDateAttr, hasTextColour, 0}},
+ {1538, {wxCalendarDateAttr, hasBackgroundColour, 0}},
+ {1539, {wxCalendarDateAttr, hasBorderColour, 0}},
+ {1540, {wxCalendarDateAttr, hasFont, 0}},
+ {1541, {wxCalendarDateAttr, hasBorder, 0}},
+ {1542, {wxCalendarDateAttr, isHoliday, 0}},
+ {1543, {wxCalendarDateAttr, getTextColour, 0}},
+ {1544, {wxCalendarDateAttr, getBackgroundColour, 0}},
+ {1545, {wxCalendarDateAttr, getBorderColour, 0}},
+ {1546, {wxCalendarDateAttr, getFont, 0}},
+ {1547, {wxCalendarDateAttr, getBorder, 0}},
+ {1548, {wxCalendarDateAttr, 'Destroy', undefined}},
+ {1550, {wxCheckBox, new_4, 4}},
+ {1551, {wxCheckBox, new_0, 0}},
+ {1552, {wxCheckBox, create, 4}},
+ {1553, {wxCheckBox, getValue, 0}},
+ {1554, {wxCheckBox, get3StateValue, 0}},
+ {1555, {wxCheckBox, is3rdStateAllowedForUser, 0}},
+ {1556, {wxCheckBox, is3State, 0}},
+ {1557, {wxCheckBox, isChecked, 0}},
+ {1558, {wxCheckBox, setValue, 1}},
+ {1559, {wxCheckBox, set3StateValue, 1}},
+ {1560, {wxCheckBox, 'Destroy', undefined}},
+ {1561, {wxCheckListBox, new_0, 0}},
+ {1563, {wxCheckListBox, new_3, 3}},
+ {1564, {wxCheckListBox, check, 2}},
+ {1565, {wxCheckListBox, isChecked, 1}},
+ {1566, {wxCheckListBox, 'Destroy', undefined}},
+ {1569, {wxChoice, new_3, 3}},
+ {1570, {wxChoice, new_0, 0}},
+ {1572, {wxChoice, destruct, 0}},
+ {1574, {wxChoice, create, 6}},
+ {1575, {wxChoice, delete, 1}},
+ {1576, {wxChoice, getColumns, 0}},
+ {1577, {wxChoice, setColumns, 1}},
+ {1578, {wxComboBox, new_0, 0}},
+ {1580, {wxComboBox, new_3, 3}},
+ {1581, {wxComboBox, destruct, 0}},
+ {1583, {wxComboBox, create, 7}},
+ {1584, {wxComboBox, canCopy, 0}},
+ {1585, {wxComboBox, canCut, 0}},
+ {1586, {wxComboBox, canPaste, 0}},
+ {1587, {wxComboBox, canRedo, 0}},
+ {1588, {wxComboBox, canUndo, 0}},
+ {1589, {wxComboBox, copy, 0}},
+ {1590, {wxComboBox, cut, 0}},
+ {1591, {wxComboBox, getInsertionPoint, 0}},
+ {1592, {wxComboBox, getLastPosition, 0}},
+ {1593, {wxComboBox, getValue, 0}},
+ {1594, {wxComboBox, paste, 0}},
+ {1595, {wxComboBox, redo, 0}},
+ {1596, {wxComboBox, replace, 3}},
+ {1597, {wxComboBox, remove, 2}},
+ {1598, {wxComboBox, setInsertionPoint, 1}},
+ {1599, {wxComboBox, setInsertionPointEnd, 0}},
+ {1600, {wxComboBox, setSelection_1, 1}},
+ {1601, {wxComboBox, setSelection_2, 2}},
+ {1602, {wxComboBox, setValue, 1}},
+ {1603, {wxComboBox, undo, 0}},
+ {1604, {wxGauge, new_0, 0}},
+ {1605, {wxGauge, new_4, 4}},
+ {1606, {wxGauge, create, 4}},
+ {1607, {wxGauge, getRange, 0}},
+ {1608, {wxGauge, getValue, 0}},
+ {1609, {wxGauge, isVertical, 0}},
+ {1610, {wxGauge, setRange, 1}},
+ {1611, {wxGauge, setValue, 1}},
+ {1612, {wxGauge, pulse, 0}},
+ {1613, {wxGauge, 'Destroy', undefined}},
+ {1614, {wxGenericDirCtrl, new_0, 0}},
+ {1615, {wxGenericDirCtrl, new_2, 2}},
+ {1616, {wxGenericDirCtrl, destruct, 0}},
+ {1617, {wxGenericDirCtrl, create, 2}},
+ {1618, {wxGenericDirCtrl, init, 0}},
+ {1619, {wxGenericDirCtrl, collapseTree, 0}},
+ {1620, {wxGenericDirCtrl, expandPath, 1}},
+ {1621, {wxGenericDirCtrl, getDefaultPath, 0}},
+ {1622, {wxGenericDirCtrl, getPath, 0}},
+ {1623, {wxGenericDirCtrl, getFilePath, 0}},
+ {1624, {wxGenericDirCtrl, getFilter, 0}},
+ {1625, {wxGenericDirCtrl, getFilterIndex, 0}},
+ {1626, {wxGenericDirCtrl, getRootId, 0}},
+ {1627, {wxGenericDirCtrl, getTreeCtrl, 0}},
+ {1628, {wxGenericDirCtrl, reCreateTree, 0}},
+ {1629, {wxGenericDirCtrl, setDefaultPath, 1}},
+ {1630, {wxGenericDirCtrl, setFilter, 1}},
+ {1631, {wxGenericDirCtrl, setFilterIndex, 1}},
+ {1632, {wxGenericDirCtrl, setPath, 1}},
+ {1634, {wxStaticBox, new_4, 4}},
+ {1635, {wxStaticBox, new_0, 0}},
+ {1636, {wxStaticBox, create, 4}},
+ {1637, {wxStaticBox, 'Destroy', undefined}},
+ {1639, {wxStaticLine, new_2, 2}},
+ {1640, {wxStaticLine, new_0, 0}},
+ {1641, {wxStaticLine, create, 2}},
+ {1642, {wxStaticLine, isVertical, 0}},
+ {1643, {wxStaticLine, getDefaultSize, 0}},
+ {1644, {wxStaticLine, 'Destroy', undefined}},
+ {1647, {wxListBox, new_3, 3}},
+ {1648, {wxListBox, new_0, 0}},
+ {1650, {wxListBox, destruct, 0}},
+ {1652, {wxListBox, create, 6}},
+ {1653, {wxListBox, deselect, 1}},
+ {1654, {wxListBox, getSelections, 1}},
+ {1655, {wxListBox, insertItems, 2}},
+ {1656, {wxListBox, isSelected, 1}},
+ {1657, {wxListBox, set, 1}},
+ {1658, {wxListBox, hitTest, 1}},
+ {1659, {wxListBox, setFirstItem_1_0, 1}},
+ {1660, {wxListBox, setFirstItem_1_1, 1}},
+ {1661, {wxListCtrl, new_0, 0}},
+ {1662, {wxListCtrl, new_2, 2}},
+ {1663, {wxListCtrl, arrange, 1}},
+ {1664, {wxListCtrl, assignImageList, 2}},
+ {1665, {wxListCtrl, clearAll, 0}},
+ {1666, {wxListCtrl, create, 2}},
+ {1667, {wxListCtrl, deleteAllItems, 0}},
+ {1668, {wxListCtrl, deleteColumn, 1}},
+ {1669, {wxListCtrl, deleteItem, 1}},
+ {1670, {wxListCtrl, editLabel, 1}},
+ {1671, {wxListCtrl, ensureVisible, 1}},
+ {1672, {wxListCtrl, findItem_3_0, 3}},
+ {1673, {wxListCtrl, findItem_3_1, 3}},
+ {1674, {wxListCtrl, getColumn, 2}},
+ {1675, {wxListCtrl, getColumnCount, 0}},
+ {1676, {wxListCtrl, getColumnWidth, 1}},
+ {1677, {wxListCtrl, getCountPerPage, 0}},
+ {1678, {wxListCtrl, getEditControl, 0}},
+ {1679, {wxListCtrl, getImageList, 1}},
+ {1680, {wxListCtrl, getItem, 1}},
+ {1681, {wxListCtrl, getItemBackgroundColour, 1}},
+ {1682, {wxListCtrl, getItemCount, 0}},
+ {1683, {wxListCtrl, getItemData, 1}},
+ {1684, {wxListCtrl, getItemFont, 1}},
+ {1685, {wxListCtrl, getItemPosition, 2}},
+ {1686, {wxListCtrl, getItemRect, 3}},
+ {1687, {wxListCtrl, getItemSpacing, 0}},
+ {1688, {wxListCtrl, getItemState, 2}},
+ {1689, {wxListCtrl, getItemText, 1}},
+ {1690, {wxListCtrl, getItemTextColour, 1}},
+ {1691, {wxListCtrl, getNextItem, 2}},
+ {1692, {wxListCtrl, getSelectedItemCount, 0}},
+ {1693, {wxListCtrl, getTextColour, 0}},
+ {1694, {wxListCtrl, getTopItem, 0}},
+ {1695, {wxListCtrl, getViewRect, 0}},
+ {1696, {wxListCtrl, hitTest, 3}},
+ {1697, {wxListCtrl, insertColumn_2, 2}},
+ {1698, {wxListCtrl, insertColumn_3, 3}},
+ {1699, {wxListCtrl, insertItem_1, 1}},
+ {1700, {wxListCtrl, insertItem_2_1, 2}},
+ {1701, {wxListCtrl, insertItem_2_0, 2}},
+ {1702, {wxListCtrl, insertItem_3, 3}},
+ {1703, {wxListCtrl, refreshItem, 1}},
+ {1704, {wxListCtrl, refreshItems, 2}},
+ {1705, {wxListCtrl, scrollList, 2}},
+ {1706, {wxListCtrl, setBackgroundColour, 1}},
+ {1707, {wxListCtrl, setColumn, 2}},
+ {1708, {wxListCtrl, setColumnWidth, 2}},
+ {1709, {wxListCtrl, setImageList, 2}},
+ {1710, {wxListCtrl, setItem_1, 1}},
+ {1711, {wxListCtrl, setItem_4, 4}},
+ {1712, {wxListCtrl, setItemBackgroundColour, 2}},
+ {1713, {wxListCtrl, setItemCount, 1}},
+ {1714, {wxListCtrl, setItemData, 2}},
+ {1715, {wxListCtrl, setItemFont, 2}},
+ {1716, {wxListCtrl, setItemImage, 3}},
+ {1717, {wxListCtrl, setItemColumnImage, 3}},
+ {1718, {wxListCtrl, setItemPosition, 2}},
+ {1719, {wxListCtrl, setItemState, 3}},
+ {1720, {wxListCtrl, setItemText, 2}},
+ {1721, {wxListCtrl, setItemTextColour, 2}},
+ {1722, {wxListCtrl, setSingleStyle, 2}},
+ {1723, {wxListCtrl, setTextColour, 1}},
+ {1724, {wxListCtrl, setWindowStyleFlag, 1}},
+ {1725, {wxListCtrl, sortItems, 2}},
+ {1726, {wxListCtrl, 'Destroy', undefined}},
+ {1727, {wxListView, clearColumnImage, 1}},
+ {1728, {wxListView, focus, 1}},
+ {1729, {wxListView, getFirstSelected, 0}},
+ {1730, {wxListView, getFocusedItem, 0}},
+ {1731, {wxListView, getNextSelected, 1}},
+ {1732, {wxListView, isSelected, 1}},
+ {1733, {wxListView, select, 2}},
+ {1734, {wxListView, setColumnImage, 2}},
+ {1735, {wxListItem, new_0, 0}},
+ {1736, {wxListItem, new_1, 1}},
+ {1737, {wxListItem, destruct, 0}},
+ {1738, {wxListItem, clear, 0}},
+ {1739, {wxListItem, getAlign, 0}},
+ {1740, {wxListItem, getBackgroundColour, 0}},
+ {1741, {wxListItem, getColumn, 0}},
+ {1742, {wxListItem, getFont, 0}},
+ {1743, {wxListItem, getId, 0}},
+ {1744, {wxListItem, getImage, 0}},
+ {1745, {wxListItem, getMask, 0}},
+ {1746, {wxListItem, getState, 0}},
+ {1747, {wxListItem, getText, 0}},
+ {1748, {wxListItem, getTextColour, 0}},
+ {1749, {wxListItem, getWidth, 0}},
+ {1750, {wxListItem, setAlign, 1}},
+ {1751, {wxListItem, setBackgroundColour, 1}},
+ {1752, {wxListItem, setColumn, 1}},
+ {1753, {wxListItem, setFont, 1}},
+ {1754, {wxListItem, setId, 1}},
+ {1755, {wxListItem, setImage, 1}},
+ {1756, {wxListItem, setMask, 1}},
+ {1757, {wxListItem, setState, 1}},
+ {1758, {wxListItem, setStateMask, 1}},
+ {1759, {wxListItem, setText, 1}},
+ {1760, {wxListItem, setTextColour, 1}},
+ {1761, {wxListItem, setWidth, 1}},
+ {1762, {wxListItemAttr, new_0, 0}},
+ {1763, {wxListItemAttr, new_3, 3}},
+ {1764, {wxListItemAttr, getBackgroundColour, 0}},
+ {1765, {wxListItemAttr, getFont, 0}},
+ {1766, {wxListItemAttr, getTextColour, 0}},
+ {1767, {wxListItemAttr, hasBackgroundColour, 0}},
+ {1768, {wxListItemAttr, hasFont, 0}},
+ {1769, {wxListItemAttr, hasTextColour, 0}},
+ {1770, {wxListItemAttr, setBackgroundColour, 1}},
+ {1771, {wxListItemAttr, setFont, 1}},
+ {1772, {wxListItemAttr, setTextColour, 1}},
+ {1773, {wxListItemAttr, 'Destroy', undefined}},
+ {1774, {wxImageList, new_0, 0}},
+ {1775, {wxImageList, new_3, 3}},
+ {1776, {wxImageList, add_1, 1}},
+ {1777, {wxImageList, add_2_0, 2}},
+ {1778, {wxImageList, add_2_1, 2}},
+ {1779, {wxImageList, create, 3}},
+ {1781, {wxImageList, draw, 5}},
+ {1782, {wxImageList, getBitmap, 1}},
+ {1783, {wxImageList, getIcon, 1}},
+ {1784, {wxImageList, getImageCount, 0}},
+ {1785, {wxImageList, getSize, 3}},
+ {1786, {wxImageList, remove, 1}},
+ {1787, {wxImageList, removeAll, 0}},
+ {1788, {wxImageList, replace_2, 2}},
+ {1789, {wxImageList, replace_3, 3}},
+ {1790, {wxImageList, 'Destroy', undefined}},
+ {1791, {wxTextAttr, new_0, 0}},
+ {1792, {wxTextAttr, new_2, 2}},
+ {1793, {wxTextAttr, getAlignment, 0}},
+ {1794, {wxTextAttr, getBackgroundColour, 0}},
+ {1795, {wxTextAttr, getFont, 0}},
+ {1796, {wxTextAttr, getLeftIndent, 0}},
+ {1797, {wxTextAttr, getLeftSubIndent, 0}},
+ {1798, {wxTextAttr, getRightIndent, 0}},
+ {1799, {wxTextAttr, getTabs, 0}},
+ {1800, {wxTextAttr, getTextColour, 0}},
+ {1801, {wxTextAttr, hasBackgroundColour, 0}},
+ {1802, {wxTextAttr, hasFont, 0}},
+ {1803, {wxTextAttr, hasTextColour, 0}},
+ {1804, {wxTextAttr, getFlags, 0}},
+ {1805, {wxTextAttr, isDefault, 0}},
+ {1806, {wxTextAttr, setAlignment, 1}},
+ {1807, {wxTextAttr, setBackgroundColour, 1}},
+ {1808, {wxTextAttr, setFlags, 1}},
+ {1809, {wxTextAttr, setFont, 2}},
+ {1810, {wxTextAttr, setLeftIndent, 2}},
+ {1811, {wxTextAttr, setRightIndent, 1}},
+ {1812, {wxTextAttr, setTabs, 1}},
+ {1813, {wxTextAttr, setTextColour, 1}},
+ {1814, {wxTextAttr, 'Destroy', undefined}},
+ {1816, {wxTextCtrl, new_3, 3}},
+ {1817, {wxTextCtrl, new_0, 0}},
+ {1819, {wxTextCtrl, destruct, 0}},
+ {1820, {wxTextCtrl, appendText, 1}},
+ {1821, {wxTextCtrl, canCopy, 0}},
+ {1822, {wxTextCtrl, canCut, 0}},
+ {1823, {wxTextCtrl, canPaste, 0}},
+ {1824, {wxTextCtrl, canRedo, 0}},
+ {1825, {wxTextCtrl, canUndo, 0}},
+ {1826, {wxTextCtrl, clear, 0}},
+ {1827, {wxTextCtrl, copy, 0}},
+ {1828, {wxTextCtrl, create, 3}},
+ {1829, {wxTextCtrl, cut, 0}},
+ {1830, {wxTextCtrl, discardEdits, 0}},
+ {1831, {wxTextCtrl, changeValue, 1}},
+ {1832, {wxTextCtrl, emulateKeyPress, 1}},
+ {1833, {wxTextCtrl, getDefaultStyle, 0}},
+ {1834, {wxTextCtrl, getInsertionPoint, 0}},
+ {1835, {wxTextCtrl, getLastPosition, 0}},
+ {1836, {wxTextCtrl, getLineLength, 1}},
+ {1837, {wxTextCtrl, getLineText, 1}},
+ {1838, {wxTextCtrl, getNumberOfLines, 0}},
+ {1839, {wxTextCtrl, getRange, 2}},
+ {1840, {wxTextCtrl, getSelection, 2}},
+ {1841, {wxTextCtrl, getStringSelection, 0}},
+ {1842, {wxTextCtrl, getStyle, 2}},
+ {1843, {wxTextCtrl, getValue, 0}},
+ {1844, {wxTextCtrl, isEditable, 0}},
+ {1845, {wxTextCtrl, isModified, 0}},
+ {1846, {wxTextCtrl, isMultiLine, 0}},
+ {1847, {wxTextCtrl, isSingleLine, 0}},
+ {1848, {wxTextCtrl, loadFile, 2}},
+ {1849, {wxTextCtrl, markDirty, 0}},
+ {1850, {wxTextCtrl, paste, 0}},
+ {1851, {wxTextCtrl, positionToXY, 3}},
+ {1852, {wxTextCtrl, redo, 0}},
+ {1853, {wxTextCtrl, remove, 2}},
+ {1854, {wxTextCtrl, replace, 3}},
+ {1855, {wxTextCtrl, saveFile, 1}},
+ {1856, {wxTextCtrl, setDefaultStyle, 1}},
+ {1857, {wxTextCtrl, setEditable, 1}},
+ {1858, {wxTextCtrl, setInsertionPoint, 1}},
+ {1859, {wxTextCtrl, setInsertionPointEnd, 0}},
+ {1861, {wxTextCtrl, setMaxLength, 1}},
+ {1862, {wxTextCtrl, setSelection, 2}},
+ {1863, {wxTextCtrl, setStyle, 3}},
+ {1864, {wxTextCtrl, setValue, 1}},
+ {1865, {wxTextCtrl, showPosition, 1}},
+ {1866, {wxTextCtrl, undo, 0}},
+ {1867, {wxTextCtrl, writeText, 1}},
+ {1868, {wxTextCtrl, xYToPosition, 2}},
+ {1871, {wxNotebook, new_0, 0}},
+ {1872, {wxNotebook, new_3, 3}},
+ {1873, {wxNotebook, destruct, 0}},
+ {1874, {wxNotebook, addPage, 3}},
+ {1875, {wxNotebook, advanceSelection, 1}},
+ {1876, {wxNotebook, assignImageList, 1}},
+ {1877, {wxNotebook, create, 3}},
+ {1878, {wxNotebook, deleteAllPages, 0}},
+ {1879, {wxNotebook, deletePage, 1}},
+ {1880, {wxNotebook, removePage, 1}},
+ {1881, {wxNotebook, getCurrentPage, 0}},
+ {1882, {wxNotebook, getImageList, 0}},
+ {1884, {wxNotebook, getPage, 1}},
+ {1885, {wxNotebook, getPageCount, 0}},
+ {1886, {wxNotebook, getPageImage, 1}},
+ {1887, {wxNotebook, getPageText, 1}},
+ {1888, {wxNotebook, getRowCount, 0}},
+ {1889, {wxNotebook, getSelection, 0}},
+ {1890, {wxNotebook, getThemeBackgroundColour, 0}},
+ {1892, {wxNotebook, hitTest, 2}},
+ {1894, {wxNotebook, insertPage, 4}},
+ {1895, {wxNotebook, setImageList, 1}},
+ {1896, {wxNotebook, setPadding, 1}},
+ {1897, {wxNotebook, setPageSize, 1}},
+ {1898, {wxNotebook, setPageImage, 2}},
+ {1899, {wxNotebook, setPageText, 2}},
+ {1900, {wxNotebook, setSelection, 1}},
+ {1901, {wxNotebook, changeSelection, 1}},
+ {1902, {wxChoicebook, new_0, 0}},
+ {1903, {wxChoicebook, new_3, 3}},
+ {1904, {wxChoicebook, addPage, 3}},
+ {1905, {wxChoicebook, advanceSelection, 1}},
+ {1906, {wxChoicebook, assignImageList, 1}},
+ {1907, {wxChoicebook, create, 3}},
+ {1908, {wxChoicebook, deleteAllPages, 0}},
+ {1909, {wxChoicebook, deletePage, 1}},
+ {1910, {wxChoicebook, removePage, 1}},
+ {1911, {wxChoicebook, getCurrentPage, 0}},
+ {1912, {wxChoicebook, getImageList, 0}},
+ {1914, {wxChoicebook, getPage, 1}},
+ {1915, {wxChoicebook, getPageCount, 0}},
+ {1916, {wxChoicebook, getPageImage, 1}},
+ {1917, {wxChoicebook, getPageText, 1}},
+ {1918, {wxChoicebook, getSelection, 0}},
+ {1919, {wxChoicebook, hitTest, 2}},
+ {1920, {wxChoicebook, insertPage, 4}},
+ {1921, {wxChoicebook, setImageList, 1}},
+ {1922, {wxChoicebook, setPageSize, 1}},
+ {1923, {wxChoicebook, setPageImage, 2}},
+ {1924, {wxChoicebook, setPageText, 2}},
+ {1925, {wxChoicebook, setSelection, 1}},
+ {1926, {wxChoicebook, changeSelection, 1}},
+ {1927, {wxChoicebook, 'Destroy', undefined}},
+ {1928, {wxToolbook, new_0, 0}},
+ {1929, {wxToolbook, new_3, 3}},
+ {1930, {wxToolbook, addPage, 3}},
+ {1931, {wxToolbook, advanceSelection, 1}},
+ {1932, {wxToolbook, assignImageList, 1}},
+ {1933, {wxToolbook, create, 3}},
+ {1934, {wxToolbook, deleteAllPages, 0}},
+ {1935, {wxToolbook, deletePage, 1}},
+ {1936, {wxToolbook, removePage, 1}},
+ {1937, {wxToolbook, getCurrentPage, 0}},
+ {1938, {wxToolbook, getImageList, 0}},
+ {1940, {wxToolbook, getPage, 1}},
+ {1941, {wxToolbook, getPageCount, 0}},
+ {1942, {wxToolbook, getPageImage, 1}},
+ {1943, {wxToolbook, getPageText, 1}},
+ {1944, {wxToolbook, getSelection, 0}},
+ {1946, {wxToolbook, hitTest, 2}},
+ {1947, {wxToolbook, insertPage, 4}},
+ {1948, {wxToolbook, setImageList, 1}},
+ {1949, {wxToolbook, setPageSize, 1}},
+ {1950, {wxToolbook, setPageImage, 2}},
+ {1951, {wxToolbook, setPageText, 2}},
+ {1952, {wxToolbook, setSelection, 1}},
+ {1953, {wxToolbook, changeSelection, 1}},
+ {1954, {wxToolbook, 'Destroy', undefined}},
+ {1955, {wxListbook, new_0, 0}},
+ {1956, {wxListbook, new_3, 3}},
+ {1957, {wxListbook, addPage, 3}},
+ {1958, {wxListbook, advanceSelection, 1}},
+ {1959, {wxListbook, assignImageList, 1}},
+ {1960, {wxListbook, create, 3}},
+ {1961, {wxListbook, deleteAllPages, 0}},
+ {1962, {wxListbook, deletePage, 1}},
+ {1963, {wxListbook, removePage, 1}},
+ {1964, {wxListbook, getCurrentPage, 0}},
+ {1965, {wxListbook, getImageList, 0}},
+ {1967, {wxListbook, getPage, 1}},
+ {1968, {wxListbook, getPageCount, 0}},
+ {1969, {wxListbook, getPageImage, 1}},
+ {1970, {wxListbook, getPageText, 1}},
+ {1971, {wxListbook, getSelection, 0}},
+ {1973, {wxListbook, hitTest, 2}},
+ {1974, {wxListbook, insertPage, 4}},
+ {1975, {wxListbook, setImageList, 1}},
+ {1976, {wxListbook, setPageSize, 1}},
+ {1977, {wxListbook, setPageImage, 2}},
+ {1978, {wxListbook, setPageText, 2}},
+ {1979, {wxListbook, setSelection, 1}},
+ {1980, {wxListbook, changeSelection, 1}},
+ {1981, {wxListbook, 'Destroy', undefined}},
+ {1982, {wxTreebook, new_0, 0}},
+ {1983, {wxTreebook, new_3, 3}},
+ {1984, {wxTreebook, addPage, 3}},
+ {1985, {wxTreebook, advanceSelection, 1}},
+ {1986, {wxTreebook, assignImageList, 1}},
+ {1987, {wxTreebook, create, 3}},
+ {1988, {wxTreebook, deleteAllPages, 0}},
+ {1989, {wxTreebook, deletePage, 1}},
+ {1990, {wxTreebook, removePage, 1}},
+ {1991, {wxTreebook, getCurrentPage, 0}},
+ {1992, {wxTreebook, getImageList, 0}},
+ {1994, {wxTreebook, getPage, 1}},
+ {1995, {wxTreebook, getPageCount, 0}},
+ {1996, {wxTreebook, getPageImage, 1}},
+ {1997, {wxTreebook, getPageText, 1}},
+ {1998, {wxTreebook, getSelection, 0}},
+ {1999, {wxTreebook, expandNode, 2}},
+ {2000, {wxTreebook, isNodeExpanded, 1}},
+ {2002, {wxTreebook, hitTest, 2}},
+ {2003, {wxTreebook, insertPage, 4}},
+ {2004, {wxTreebook, insertSubPage, 4}},
+ {2005, {wxTreebook, setImageList, 1}},
+ {2006, {wxTreebook, setPageSize, 1}},
+ {2007, {wxTreebook, setPageImage, 2}},
+ {2008, {wxTreebook, setPageText, 2}},
+ {2009, {wxTreebook, setSelection, 1}},
+ {2010, {wxTreebook, changeSelection, 1}},
+ {2011, {wxTreebook, 'Destroy', undefined}},
+ {2014, {wxTreeCtrl, new_2, 2}},
+ {2015, {wxTreeCtrl, new_0, 0}},
+ {2017, {wxTreeCtrl, destruct, 0}},
+ {2018, {wxTreeCtrl, addRoot, 2}},
+ {2019, {wxTreeCtrl, appendItem, 3}},
+ {2020, {wxTreeCtrl, assignImageList, 1}},
+ {2021, {wxTreeCtrl, assignStateImageList, 1}},
+ {2022, {wxTreeCtrl, collapse, 1}},
+ {2023, {wxTreeCtrl, collapseAndReset, 1}},
+ {2024, {wxTreeCtrl, create, 2}},
+ {2025, {wxTreeCtrl, delete, 1}},
+ {2026, {wxTreeCtrl, deleteAllItems, 0}},
+ {2027, {wxTreeCtrl, deleteChildren, 1}},
+ {2028, {wxTreeCtrl, editLabel, 1}},
+ {2029, {wxTreeCtrl, ensureVisible, 1}},
+ {2030, {wxTreeCtrl, expand, 1}},
+ {2031, {wxTreeCtrl, getBoundingRect, 3}},
+ {2033, {wxTreeCtrl, getChildrenCount, 2}},
+ {2034, {wxTreeCtrl, getCount, 0}},
+ {2035, {wxTreeCtrl, getEditControl, 0}},
+ {2036, {wxTreeCtrl, getFirstChild, 2}},
+ {2037, {wxTreeCtrl, getNextChild, 2}},
+ {2038, {wxTreeCtrl, getFirstVisibleItem, 0}},
+ {2039, {wxTreeCtrl, getImageList, 0}},
+ {2040, {wxTreeCtrl, getIndent, 0}},
+ {2041, {wxTreeCtrl, getItemBackgroundColour, 1}},
+ {2042, {wxTreeCtrl, getItemData, 1}},
+ {2043, {wxTreeCtrl, getItemFont, 1}},
+ {2044, {wxTreeCtrl, getItemImage_1, 1}},
+ {2045, {wxTreeCtrl, getItemImage_2, 2}},
+ {2046, {wxTreeCtrl, getItemText, 1}},
+ {2047, {wxTreeCtrl, getItemTextColour, 1}},
+ {2048, {wxTreeCtrl, getLastChild, 1}},
+ {2049, {wxTreeCtrl, getNextSibling, 1}},
+ {2050, {wxTreeCtrl, getNextVisible, 1}},
+ {2051, {wxTreeCtrl, getItemParent, 1}},
+ {2052, {wxTreeCtrl, getPrevSibling, 1}},
+ {2053, {wxTreeCtrl, getPrevVisible, 1}},
+ {2054, {wxTreeCtrl, getRootItem, 0}},
+ {2055, {wxTreeCtrl, getSelection, 0}},
+ {2056, {wxTreeCtrl, getSelections, 1}},
+ {2057, {wxTreeCtrl, getStateImageList, 0}},
+ {2058, {wxTreeCtrl, hitTest, 2}},
+ {2060, {wxTreeCtrl, insertItem, 4}},
+ {2061, {wxTreeCtrl, isBold, 1}},
+ {2062, {wxTreeCtrl, isExpanded, 1}},
+ {2063, {wxTreeCtrl, isSelected, 1}},
+ {2064, {wxTreeCtrl, isVisible, 1}},
+ {2065, {wxTreeCtrl, itemHasChildren, 1}},
+ {2066, {wxTreeCtrl, isTreeItemIdOk, 1}},
+ {2067, {wxTreeCtrl, prependItem, 3}},
+ {2068, {wxTreeCtrl, scrollTo, 1}},
+ {2069, {wxTreeCtrl, selectItem_1, 1}},
+ {2070, {wxTreeCtrl, selectItem_2, 2}},
+ {2071, {wxTreeCtrl, setIndent, 1}},
+ {2072, {wxTreeCtrl, setImageList, 1}},
+ {2073, {wxTreeCtrl, setItemBackgroundColour, 2}},
+ {2074, {wxTreeCtrl, setItemBold, 2}},
+ {2075, {wxTreeCtrl, setItemData, 2}},
+ {2076, {wxTreeCtrl, setItemDropHighlight, 2}},
+ {2077, {wxTreeCtrl, setItemFont, 2}},
+ {2078, {wxTreeCtrl, setItemHasChildren, 2}},
+ {2079, {wxTreeCtrl, setItemImage_2, 2}},
+ {2080, {wxTreeCtrl, setItemImage_3, 3}},
+ {2081, {wxTreeCtrl, setItemText, 2}},
+ {2082, {wxTreeCtrl, setItemTextColour, 2}},
+ {2083, {wxTreeCtrl, setStateImageList, 1}},
+ {2084, {wxTreeCtrl, setWindowStyle, 1}},
+ {2085, {wxTreeCtrl, sortChildren, 1}},
+ {2086, {wxTreeCtrl, toggle, 1}},
+ {2087, {wxTreeCtrl, toggleItemSelection, 1}},
+ {2088, {wxTreeCtrl, unselect, 0}},
+ {2089, {wxTreeCtrl, unselectAll, 0}},
+ {2090, {wxTreeCtrl, unselectItem, 1}},
+ {2091, {wxScrollBar, new_0, 0}},
+ {2092, {wxScrollBar, new_3, 3}},
+ {2093, {wxScrollBar, destruct, 0}},
+ {2094, {wxScrollBar, create, 3}},
+ {2095, {wxScrollBar, getRange, 0}},
+ {2096, {wxScrollBar, getPageSize, 0}},
+ {2097, {wxScrollBar, getThumbPosition, 0}},
+ {2098, {wxScrollBar, getThumbSize, 0}},
+ {2099, {wxScrollBar, setThumbPosition, 1}},
+ {2100, {wxScrollBar, setScrollbar, 5}},
+ {2102, {wxSpinButton, new_2, 2}},
+ {2103, {wxSpinButton, new_0, 0}},
+ {2104, {wxSpinButton, create, 2}},
+ {2105, {wxSpinButton, getMax, 0}},
+ {2106, {wxSpinButton, getMin, 0}},
+ {2107, {wxSpinButton, getValue, 0}},
+ {2108, {wxSpinButton, setRange, 2}},
+ {2109, {wxSpinButton, setValue, 1}},
+ {2110, {wxSpinButton, 'Destroy', undefined}},
+ {2111, {wxSpinCtrl, new_0, 0}},
+ {2112, {wxSpinCtrl, new_2, 2}},
+ {2114, {wxSpinCtrl, create, 2}},
+ {2117, {wxSpinCtrl, setValue_1_1, 1}},
+ {2118, {wxSpinCtrl, setValue_1_0, 1}},
+ {2120, {wxSpinCtrl, getValue, 0}},
+ {2122, {wxSpinCtrl, setRange, 2}},
+ {2123, {wxSpinCtrl, setSelection, 2}},
+ {2125, {wxSpinCtrl, getMin, 0}},
+ {2127, {wxSpinCtrl, getMax, 0}},
+ {2128, {wxSpinCtrl, 'Destroy', undefined}},
+ {2129, {wxStaticText, new_0, 0}},
+ {2130, {wxStaticText, new_4, 4}},
+ {2131, {wxStaticText, create, 4}},
+ {2132, {wxStaticText, getLabel, 0}},
+ {2133, {wxStaticText, setLabel, 1}},
+ {2134, {wxStaticText, wrap, 1}},
+ {2135, {wxStaticText, 'Destroy', undefined}},
+ {2136, {wxStaticBitmap, new_0, 0}},
+ {2137, {wxStaticBitmap, new_4, 4}},
+ {2138, {wxStaticBitmap, create, 4}},
+ {2139, {wxStaticBitmap, getBitmap, 0}},
+ {2140, {wxStaticBitmap, setBitmap, 1}},
+ {2141, {wxStaticBitmap, 'Destroy', undefined}},
+ {2142, {wxRadioBox, new, 7}},
+ {2144, {wxRadioBox, destruct, 0}},
+ {2145, {wxRadioBox, create, 7}},
+ {2146, {wxRadioBox, enable_2, 2}},
+ {2147, {wxRadioBox, enable_1, 1}},
+ {2148, {wxRadioBox, getSelection, 0}},
+ {2149, {wxRadioBox, getString, 1}},
+ {2150, {wxRadioBox, setSelection, 1}},
+ {2151, {wxRadioBox, show_2, 2}},
+ {2152, {wxRadioBox, show_1, 1}},
+ {2153, {wxRadioBox, getColumnCount, 0}},
+ {2154, {wxRadioBox, getItemHelpText, 1}},
+ {2155, {wxRadioBox, getItemToolTip, 1}},
+ {2157, {wxRadioBox, getItemFromPoint, 1}},
+ {2158, {wxRadioBox, getRowCount, 0}},
+ {2159, {wxRadioBox, isItemEnabled, 1}},
+ {2160, {wxRadioBox, isItemShown, 1}},
+ {2161, {wxRadioBox, setItemHelpText, 2}},
+ {2162, {wxRadioBox, setItemToolTip, 2}},
+ {2163, {wxRadioButton, new_0, 0}},
+ {2164, {wxRadioButton, new_4, 4}},
+ {2165, {wxRadioButton, create, 4}},
+ {2166, {wxRadioButton, getValue, 0}},
+ {2167, {wxRadioButton, setValue, 1}},
+ {2168, {wxRadioButton, 'Destroy', undefined}},
+ {2170, {wxSlider, new_6, 6}},
+ {2171, {wxSlider, new_0, 0}},
+ {2172, {wxSlider, create, 6}},
+ {2173, {wxSlider, getLineSize, 0}},
+ {2174, {wxSlider, getMax, 0}},
+ {2175, {wxSlider, getMin, 0}},
+ {2176, {wxSlider, getPageSize, 0}},
+ {2177, {wxSlider, getThumbLength, 0}},
+ {2178, {wxSlider, getValue, 0}},
+ {2179, {wxSlider, setLineSize, 1}},
+ {2180, {wxSlider, setPageSize, 1}},
+ {2181, {wxSlider, setRange, 2}},
+ {2182, {wxSlider, setThumbLength, 1}},
+ {2183, {wxSlider, setValue, 1}},
+ {2184, {wxSlider, 'Destroy', undefined}},
+ {2186, {wxDialog, new_4, 4}},
+ {2187, {wxDialog, new_0, 0}},
+ {2189, {wxDialog, destruct, 0}},
+ {2190, {wxDialog, create, 4}},
+ {2191, {wxDialog, createButtonSizer, 1}},
+ {2192, {wxDialog, createStdDialogButtonSizer, 1}},
+ {2193, {wxDialog, endModal, 1}},
+ {2194, {wxDialog, getAffirmativeId, 0}},
+ {2195, {wxDialog, getReturnCode, 0}},
+ {2196, {wxDialog, isModal, 0}},
+ {2197, {wxDialog, setAffirmativeId, 1}},
+ {2198, {wxDialog, setReturnCode, 1}},
+ {2199, {wxDialog, show, 1}},
+ {2200, {wxDialog, showModal, 0}},
+ {2201, {wxColourDialog, new_0, 0}},
+ {2202, {wxColourDialog, new_2, 2}},
+ {2203, {wxColourDialog, destruct, 0}},
+ {2204, {wxColourDialog, create, 2}},
+ {2205, {wxColourDialog, getColourData, 0}},
+ {2206, {wxColourData, new_0, 0}},
+ {2207, {wxColourData, new_1, 1}},
+ {2208, {wxColourData, destruct, 0}},
+ {2209, {wxColourData, getChooseFull, 0}},
+ {2210, {wxColourData, getColour, 0}},
+ {2212, {wxColourData, getCustomColour, 1}},
+ {2213, {wxColourData, setChooseFull, 1}},
+ {2214, {wxColourData, setColour, 1}},
+ {2215, {wxColourData, setCustomColour, 2}},
+ {2216, {wxPalette, new_0, 0}},
+ {2217, {wxPalette, new_4, 4}},
+ {2219, {wxPalette, destruct, 0}},
+ {2220, {wxPalette, create, 4}},
+ {2221, {wxPalette, getColoursCount, 0}},
+ {2222, {wxPalette, getPixel, 3}},
+ {2223, {wxPalette, getRGB, 4}},
+ {2224, {wxPalette, isOk, 0}},
+ {2228, {wxDirDialog, new, 2}},
+ {2229, {wxDirDialog, destruct, 0}},
+ {2230, {wxDirDialog, getPath, 0}},
+ {2231, {wxDirDialog, getMessage, 0}},
+ {2232, {wxDirDialog, setMessage, 1}},
+ {2233, {wxDirDialog, setPath, 1}},
+ {2237, {wxFileDialog, new, 2}},
+ {2238, {wxFileDialog, destruct, 0}},
+ {2239, {wxFileDialog, getDirectory, 0}},
+ {2240, {wxFileDialog, getFilename, 0}},
+ {2241, {wxFileDialog, getFilenames, 1}},
+ {2242, {wxFileDialog, getFilterIndex, 0}},
+ {2243, {wxFileDialog, getMessage, 0}},
+ {2244, {wxFileDialog, getPath, 0}},
+ {2245, {wxFileDialog, getPaths, 1}},
+ {2246, {wxFileDialog, getWildcard, 0}},
+ {2247, {wxFileDialog, setDirectory, 1}},
+ {2248, {wxFileDialog, setFilename, 1}},
+ {2249, {wxFileDialog, setFilterIndex, 1}},
+ {2250, {wxFileDialog, setMessage, 1}},
+ {2251, {wxFileDialog, setPath, 1}},
+ {2252, {wxFileDialog, setWildcard, 1}},
+ {2253, {wxPickerBase, setInternalMargin, 1}},
+ {2254, {wxPickerBase, getInternalMargin, 0}},
+ {2255, {wxPickerBase, setTextCtrlProportion, 1}},
+ {2256, {wxPickerBase, setPickerCtrlProportion, 1}},
+ {2257, {wxPickerBase, getTextCtrlProportion, 0}},
+ {2258, {wxPickerBase, getPickerCtrlProportion, 0}},
+ {2259, {wxPickerBase, hasTextCtrl, 0}},
+ {2260, {wxPickerBase, getTextCtrl, 0}},
+ {2261, {wxPickerBase, isTextCtrlGrowable, 0}},
+ {2262, {wxPickerBase, setPickerCtrlGrowable, 1}},
+ {2263, {wxPickerBase, setTextCtrlGrowable, 1}},
+ {2264, {wxPickerBase, isPickerCtrlGrowable, 0}},
+ {2265, {wxFilePickerCtrl, new_0, 0}},
+ {2266, {wxFilePickerCtrl, new_3, 3}},
+ {2267, {wxFilePickerCtrl, create, 3}},
+ {2268, {wxFilePickerCtrl, getPath, 0}},
+ {2269, {wxFilePickerCtrl, setPath, 1}},
+ {2270, {wxFilePickerCtrl, 'Destroy', undefined}},
+ {2271, {wxDirPickerCtrl, new_0, 0}},
+ {2272, {wxDirPickerCtrl, new_3, 3}},
+ {2273, {wxDirPickerCtrl, create, 3}},
+ {2274, {wxDirPickerCtrl, getPath, 0}},
+ {2275, {wxDirPickerCtrl, setPath, 1}},
+ {2276, {wxDirPickerCtrl, 'Destroy', undefined}},
+ {2277, {wxColourPickerCtrl, new_0, 0}},
+ {2278, {wxColourPickerCtrl, new_3, 3}},
+ {2279, {wxColourPickerCtrl, create, 3}},
+ {2280, {wxColourPickerCtrl, getColour, 0}},
+ {2281, {wxColourPickerCtrl, setColour_1_1, 1}},
+ {2282, {wxColourPickerCtrl, setColour_1_0, 1}},
+ {2283, {wxColourPickerCtrl, 'Destroy', undefined}},
+ {2284, {wxDatePickerCtrl, new_0, 0}},
+ {2285, {wxDatePickerCtrl, new_3, 3}},
+ {2286, {wxDatePickerCtrl, getRange, 2}},
+ {2287, {wxDatePickerCtrl, getValue, 0}},
+ {2288, {wxDatePickerCtrl, setRange, 2}},
+ {2289, {wxDatePickerCtrl, setValue, 1}},
+ {2290, {wxDatePickerCtrl, 'Destroy', undefined}},
+ {2291, {wxFontPickerCtrl, new_0, 0}},
+ {2292, {wxFontPickerCtrl, new_3, 3}},
+ {2293, {wxFontPickerCtrl, create, 3}},
+ {2294, {wxFontPickerCtrl, getSelectedFont, 0}},
+ {2295, {wxFontPickerCtrl, setSelectedFont, 1}},
+ {2296, {wxFontPickerCtrl, getMaxPointSize, 0}},
+ {2297, {wxFontPickerCtrl, setMaxPointSize, 1}},
+ {2298, {wxFontPickerCtrl, 'Destroy', undefined}},
+ {2301, {wxFindReplaceDialog, new_0, 0}},
+ {2302, {wxFindReplaceDialog, new_4, 4}},
+ {2303, {wxFindReplaceDialog, destruct, 0}},
+ {2304, {wxFindReplaceDialog, create, 4}},
+ {2305, {wxFindReplaceDialog, getData, 0}},
+ {2306, {wxFindReplaceData, new_0, 0}},
+ {2307, {wxFindReplaceData, new_1, 1}},
+ {2308, {wxFindReplaceData, getFindString, 0}},
+ {2309, {wxFindReplaceData, getReplaceString, 0}},
+ {2310, {wxFindReplaceData, getFlags, 0}},
+ {2311, {wxFindReplaceData, setFlags, 1}},
+ {2312, {wxFindReplaceData, setFindString, 1}},
+ {2313, {wxFindReplaceData, setReplaceString, 1}},
+ {2314, {wxFindReplaceData, 'Destroy', undefined}},
+ {2315, {wxMultiChoiceDialog, new_0, 0}},
+ {2317, {wxMultiChoiceDialog, new_5, 5}},
+ {2318, {wxMultiChoiceDialog, getSelections, 0}},
+ {2319, {wxMultiChoiceDialog, setSelections, 1}},
+ {2320, {wxMultiChoiceDialog, 'Destroy', undefined}},
+ {2321, {wxSingleChoiceDialog, new_0, 0}},
+ {2323, {wxSingleChoiceDialog, new_5, 5}},
+ {2324, {wxSingleChoiceDialog, getSelection, 0}},
+ {2325, {wxSingleChoiceDialog, getStringSelection, 0}},
+ {2326, {wxSingleChoiceDialog, setSelection, 1}},
+ {2327, {wxSingleChoiceDialog, 'Destroy', undefined}},
+ {2328, {wxTextEntryDialog, new, 3}},
+ {2329, {wxTextEntryDialog, getValue, 0}},
+ {2330, {wxTextEntryDialog, setValue, 1}},
+ {2331, {wxTextEntryDialog, 'Destroy', undefined}},
+ {2332, {wxPasswordEntryDialog, new, 3}},
+ {2333, {wxPasswordEntryDialog, 'Destroy', undefined}},
+ {2334, {wxFontData, new_0, 0}},
+ {2335, {wxFontData, new_1, 1}},
+ {2336, {wxFontData, destruct, 0}},
+ {2337, {wxFontData, enableEffects, 1}},
+ {2338, {wxFontData, getAllowSymbols, 0}},
+ {2339, {wxFontData, getColour, 0}},
+ {2340, {wxFontData, getChosenFont, 0}},
+ {2341, {wxFontData, getEnableEffects, 0}},
+ {2342, {wxFontData, getInitialFont, 0}},
+ {2343, {wxFontData, getShowHelp, 0}},
+ {2344, {wxFontData, setAllowSymbols, 1}},
+ {2345, {wxFontData, setChosenFont, 1}},
+ {2346, {wxFontData, setColour, 1}},
+ {2347, {wxFontData, setInitialFont, 1}},
+ {2348, {wxFontData, setRange, 2}},
+ {2349, {wxFontData, setShowHelp, 1}},
+ {2353, {wxFontDialog, new_0, 0}},
+ {2355, {wxFontDialog, new_2, 2}},
+ {2357, {wxFontDialog, create, 2}},
+ {2358, {wxFontDialog, getFontData, 0}},
+ {2360, {wxFontDialog, 'Destroy', undefined}},
+ {2361, {wxProgressDialog, new, 3}},
+ {2362, {wxProgressDialog, destruct, 0}},
+ {2363, {wxProgressDialog, resume, 0}},
+ {2364, {wxProgressDialog, update_2, 2}},
+ {2365, {wxProgressDialog, update_0, 0}},
+ {2366, {wxMessageDialog, new, 3}},
+ {2367, {wxMessageDialog, destruct, 0}},
+ {2368, {wxPageSetupDialog, new, 2}},
+ {2369, {wxPageSetupDialog, destruct, 0}},
+ {2370, {wxPageSetupDialog, getPageSetupData, 0}},
+ {2371, {wxPageSetupDialog, showModal, 0}},
+ {2372, {wxPageSetupDialogData, new_0, 0}},
+ {2373, {wxPageSetupDialogData, new_1_0, 1}},
+ {2374, {wxPageSetupDialogData, new_1_1, 1}},
+ {2375, {wxPageSetupDialogData, destruct, 0}},
+ {2376, {wxPageSetupDialogData, enableHelp, 1}},
+ {2377, {wxPageSetupDialogData, enableMargins, 1}},
+ {2378, {wxPageSetupDialogData, enableOrientation, 1}},
+ {2379, {wxPageSetupDialogData, enablePaper, 1}},
+ {2380, {wxPageSetupDialogData, enablePrinter, 1}},
+ {2381, {wxPageSetupDialogData, getDefaultMinMargins, 0}},
+ {2382, {wxPageSetupDialogData, getEnableMargins, 0}},
+ {2383, {wxPageSetupDialogData, getEnableOrientation, 0}},
+ {2384, {wxPageSetupDialogData, getEnablePaper, 0}},
+ {2385, {wxPageSetupDialogData, getEnablePrinter, 0}},
+ {2386, {wxPageSetupDialogData, getEnableHelp, 0}},
+ {2387, {wxPageSetupDialogData, getDefaultInfo, 0}},
+ {2388, {wxPageSetupDialogData, getMarginTopLeft, 0}},
+ {2389, {wxPageSetupDialogData, getMarginBottomRight, 0}},
+ {2390, {wxPageSetupDialogData, getMinMarginTopLeft, 0}},
+ {2391, {wxPageSetupDialogData, getMinMarginBottomRight, 0}},
+ {2392, {wxPageSetupDialogData, getPaperId, 0}},
+ {2393, {wxPageSetupDialogData, getPaperSize, 0}},
+ {2395, {wxPageSetupDialogData, getPrintData, 0}},
+ {2396, {wxPageSetupDialogData, isOk, 0}},
+ {2397, {wxPageSetupDialogData, setDefaultInfo, 1}},
+ {2398, {wxPageSetupDialogData, setDefaultMinMargins, 1}},
+ {2399, {wxPageSetupDialogData, setMarginTopLeft, 1}},
+ {2400, {wxPageSetupDialogData, setMarginBottomRight, 1}},
+ {2401, {wxPageSetupDialogData, setMinMarginTopLeft, 1}},
+ {2402, {wxPageSetupDialogData, setMinMarginBottomRight, 1}},
+ {2403, {wxPageSetupDialogData, setPaperId, 1}},
+ {2404, {wxPageSetupDialogData, setPaperSize_1_1, 1}},
+ {2405, {wxPageSetupDialogData, setPaperSize_1_0, 1}},
+ {2406, {wxPageSetupDialogData, setPrintData, 1}},
+ {2407, {wxPrintDialog, new_2_0, 2}},
+ {2408, {wxPrintDialog, new_2_1, 2}},
+ {2409, {wxPrintDialog, destruct, 0}},
+ {2410, {wxPrintDialog, getPrintDialogData, 0}},
+ {2411, {wxPrintDialog, getPrintDC, 0}},
+ {2412, {wxPrintDialogData, new_0, 0}},
+ {2413, {wxPrintDialogData, new_1_1, 1}},
+ {2414, {wxPrintDialogData, new_1_0, 1}},
+ {2415, {wxPrintDialogData, destruct, 0}},
+ {2416, {wxPrintDialogData, enableHelp, 1}},
+ {2417, {wxPrintDialogData, enablePageNumbers, 1}},
+ {2418, {wxPrintDialogData, enablePrintToFile, 1}},
+ {2419, {wxPrintDialogData, enableSelection, 1}},
+ {2420, {wxPrintDialogData, getAllPages, 0}},
+ {2421, {wxPrintDialogData, getCollate, 0}},
+ {2422, {wxPrintDialogData, getFromPage, 0}},
+ {2423, {wxPrintDialogData, getMaxPage, 0}},
+ {2424, {wxPrintDialogData, getMinPage, 0}},
+ {2425, {wxPrintDialogData, getNoCopies, 0}},
+ {2426, {wxPrintDialogData, getPrintData, 0}},
+ {2427, {wxPrintDialogData, getPrintToFile, 0}},
+ {2428, {wxPrintDialogData, getSelection, 0}},
+ {2429, {wxPrintDialogData, getToPage, 0}},
+ {2430, {wxPrintDialogData, isOk, 0}},
+ {2431, {wxPrintDialogData, setCollate, 1}},
+ {2432, {wxPrintDialogData, setFromPage, 1}},
+ {2433, {wxPrintDialogData, setMaxPage, 1}},
+ {2434, {wxPrintDialogData, setMinPage, 1}},
+ {2435, {wxPrintDialogData, setNoCopies, 1}},
+ {2436, {wxPrintDialogData, setPrintData, 1}},
+ {2437, {wxPrintDialogData, setPrintToFile, 1}},
+ {2438, {wxPrintDialogData, setSelection, 1}},
+ {2439, {wxPrintDialogData, setToPage, 1}},
+ {2440, {wxPrintData, new_0, 0}},
+ {2441, {wxPrintData, new_1, 1}},
+ {2442, {wxPrintData, destruct, 0}},
+ {2443, {wxPrintData, getCollate, 0}},
+ {2444, {wxPrintData, getBin, 0}},
+ {2445, {wxPrintData, getColour, 0}},
+ {2446, {wxPrintData, getDuplex, 0}},
+ {2447, {wxPrintData, getNoCopies, 0}},
+ {2448, {wxPrintData, getOrientation, 0}},
+ {2449, {wxPrintData, getPaperId, 0}},
+ {2450, {wxPrintData, getPrinterName, 0}},
+ {2451, {wxPrintData, getQuality, 0}},
+ {2452, {wxPrintData, isOk, 0}},
+ {2453, {wxPrintData, setBin, 1}},
+ {2454, {wxPrintData, setCollate, 1}},
+ {2455, {wxPrintData, setColour, 1}},
+ {2456, {wxPrintData, setDuplex, 1}},
+ {2457, {wxPrintData, setNoCopies, 1}},
+ {2458, {wxPrintData, setOrientation, 1}},
+ {2459, {wxPrintData, setPaperId, 1}},
+ {2460, {wxPrintData, setPrinterName, 1}},
+ {2461, {wxPrintData, setQuality, 1}},
+ {2464, {wxPrintPreview, new_2, 2}},
+ {2465, {wxPrintPreview, new_3, 3}},
+ {2467, {wxPrintPreview, destruct, 0}},
+ {2468, {wxPrintPreview, getCanvas, 0}},
+ {2469, {wxPrintPreview, getCurrentPage, 0}},
+ {2470, {wxPrintPreview, getFrame, 0}},
+ {2471, {wxPrintPreview, getMaxPage, 0}},
+ {2472, {wxPrintPreview, getMinPage, 0}},
+ {2473, {wxPrintPreview, getPrintout, 0}},
+ {2474, {wxPrintPreview, getPrintoutForPrinting, 0}},
+ {2475, {wxPrintPreview, isOk, 0}},
+ {2476, {wxPrintPreview, paintPage, 2}},
+ {2477, {wxPrintPreview, print, 1}},
+ {2478, {wxPrintPreview, renderPage, 1}},
+ {2479, {wxPrintPreview, setCanvas, 1}},
+ {2480, {wxPrintPreview, setCurrentPage, 1}},
+ {2481, {wxPrintPreview, setFrame, 1}},
+ {2482, {wxPrintPreview, setPrintout, 1}},
+ {2483, {wxPrintPreview, setZoom, 1}},
+ {2484, {wxPreviewFrame, new, 3}},
+ {2485, {wxPreviewFrame, destruct, 0}},
+ {2486, {wxPreviewFrame, createControlBar, 0}},
+ {2487, {wxPreviewFrame, createCanvas, 0}},
+ {2488, {wxPreviewFrame, initialize, 0}},
+ {2489, {wxPreviewFrame, onCloseWindow, 1}},
+ {2490, {wxPreviewControlBar, new, 4}},
+ {2491, {wxPreviewControlBar, destruct, 0}},
+ {2492, {wxPreviewControlBar, createButtons, 0}},
+ {2493, {wxPreviewControlBar, getPrintPreview, 0}},
+ {2494, {wxPreviewControlBar, getZoomControl, 0}},
+ {2495, {wxPreviewControlBar, setZoomControl, 1}},
+ {2497, {wxPrinter, new, 1}},
+ {2498, {wxPrinter, createAbortWindow, 2}},
+ {2499, {wxPrinter, getAbort, 0}},
+ {2500, {wxPrinter, getLastError, 0}},
+ {2501, {wxPrinter, getPrintDialogData, 0}},
+ {2502, {wxPrinter, print, 3}},
+ {2503, {wxPrinter, printDialog, 1}},
+ {2504, {wxPrinter, reportError, 3}},
+ {2505, {wxPrinter, setup, 1}},
+ {2506, {wxPrinter, 'Destroy', undefined}},
+ {2507, {wxXmlResource, new_1, 1}},
+ {2508, {wxXmlResource, new_2, 2}},
+ {2509, {wxXmlResource, destruct, 0}},
+ {2510, {wxXmlResource, attachUnknownControl, 3}},
+ {2511, {wxXmlResource, clearHandlers, 0}},
+ {2512, {wxXmlResource, compareVersion, 4}},
+ {2513, {wxXmlResource, get, 0}},
+ {2514, {wxXmlResource, getFlags, 0}},
+ {2515, {wxXmlResource, getVersion, 0}},
+ {2516, {wxXmlResource, getXRCID, 2}},
+ {2517, {wxXmlResource, initAllHandlers, 0}},
+ {2518, {wxXmlResource, load, 1}},
+ {2519, {wxXmlResource, loadBitmap, 1}},
+ {2520, {wxXmlResource, loadDialog_2, 2}},
+ {2521, {wxXmlResource, loadDialog_3, 3}},
+ {2522, {wxXmlResource, loadFrame_2, 2}},
+ {2523, {wxXmlResource, loadFrame_3, 3}},
+ {2524, {wxXmlResource, loadIcon, 1}},
+ {2525, {wxXmlResource, loadMenu, 1}},
+ {2526, {wxXmlResource, loadMenuBar_2, 2}},
+ {2527, {wxXmlResource, loadMenuBar_1, 1}},
+ {2528, {wxXmlResource, loadPanel_2, 2}},
+ {2529, {wxXmlResource, loadPanel_3, 3}},
+ {2530, {wxXmlResource, loadToolBar, 2}},
+ {2531, {wxXmlResource, set, 1}},
+ {2532, {wxXmlResource, setFlags, 1}},
+ {2533, {wxXmlResource, unload, 1}},
+ {2534, {wxXmlResource, xrcctrl, 3}},
+ {2535, {wxHtmlEasyPrinting, new, 1}},
+ {2536, {wxHtmlEasyPrinting, destruct, 0}},
+ {2537, {wxHtmlEasyPrinting, getPrintData, 0}},
+ {2538, {wxHtmlEasyPrinting, getPageSetupData, 0}},
+ {2539, {wxHtmlEasyPrinting, previewFile, 1}},
+ {2540, {wxHtmlEasyPrinting, previewText, 2}},
+ {2541, {wxHtmlEasyPrinting, printFile, 1}},
+ {2542, {wxHtmlEasyPrinting, printText, 2}},
+ {2543, {wxHtmlEasyPrinting, pageSetup, 0}},
+ {2544, {wxHtmlEasyPrinting, setFonts, 3}},
+ {2545, {wxHtmlEasyPrinting, setHeader, 2}},
+ {2546, {wxHtmlEasyPrinting, setFooter, 2}},
+ {2548, {wxGLCanvas, new_2, 2}},
+ {2549, {wxGLCanvas, new_3_1, 3}},
+ {2550, {wxGLCanvas, new_3_0, 3}},
+ {2551, {wxGLCanvas, getContext, 0}},
+ {2553, {wxGLCanvas, setCurrent, 0}},
+ {2554, {wxGLCanvas, swapBuffers, 0}},
+ {2555, {wxGLCanvas, 'Destroy', undefined}},
+ {2556, {wxAuiManager, new, 1}},
+ {2557, {wxAuiManager, destruct, 0}},
+ {2558, {wxAuiManager, addPane_2_1, 2}},
+ {2559, {wxAuiManager, addPane_3, 3}},
+ {2560, {wxAuiManager, addPane_2_0, 2}},
+ {2561, {wxAuiManager, detachPane, 1}},
+ {2562, {wxAuiManager, getAllPanes, 0}},
+ {2563, {wxAuiManager, getArtProvider, 0}},
+ {2564, {wxAuiManager, getDockSizeConstraint, 2}},
+ {2565, {wxAuiManager, getFlags, 0}},
+ {2566, {wxAuiManager, getManagedWindow, 0}},
+ {2567, {wxAuiManager, getManager, 1}},
+ {2568, {wxAuiManager, getPane_1_1, 1}},
+ {2569, {wxAuiManager, getPane_1_0, 1}},
+ {2570, {wxAuiManager, hideHint, 0}},
+ {2571, {wxAuiManager, insertPane, 3}},
+ {2572, {wxAuiManager, loadPaneInfo, 2}},
+ {2573, {wxAuiManager, loadPerspective, 2}},
+ {2574, {wxAuiManager, savePaneInfo, 1}},
+ {2575, {wxAuiManager, savePerspective, 0}},
+ {2576, {wxAuiManager, setArtProvider, 1}},
+ {2577, {wxAuiManager, setDockSizeConstraint, 2}},
+ {2578, {wxAuiManager, setFlags, 1}},
+ {2579, {wxAuiManager, setManagedWindow, 1}},
+ {2580, {wxAuiManager, showHint, 1}},
+ {2581, {wxAuiManager, unInit, 0}},
+ {2582, {wxAuiManager, update, 0}},
+ {2583, {wxAuiPaneInfo, new_0, 0}},
+ {2584, {wxAuiPaneInfo, new_1, 1}},
+ {2585, {wxAuiPaneInfo, destruct, 0}},
+ {2586, {wxAuiPaneInfo, bestSize_1, 1}},
+ {2587, {wxAuiPaneInfo, bestSize_2, 2}},
+ {2588, {wxAuiPaneInfo, bottom, 0}},
+ {2589, {wxAuiPaneInfo, bottomDockable, 1}},
+ {2590, {wxAuiPaneInfo, caption, 1}},
+ {2591, {wxAuiPaneInfo, captionVisible, 1}},
+ {2592, {wxAuiPaneInfo, centre, 0}},
+ {2593, {wxAuiPaneInfo, centrePane, 0}},
+ {2594, {wxAuiPaneInfo, closeButton, 1}},
+ {2595, {wxAuiPaneInfo, defaultPane, 0}},
+ {2596, {wxAuiPaneInfo, destroyOnClose, 1}},
+ {2597, {wxAuiPaneInfo, direction, 1}},
+ {2598, {wxAuiPaneInfo, dock, 0}},
+ {2599, {wxAuiPaneInfo, dockable, 1}},
+ {2600, {wxAuiPaneInfo, fixed, 0}},
+ {2601, {wxAuiPaneInfo, float, 0}},
+ {2602, {wxAuiPaneInfo, floatable, 1}},
+ {2603, {wxAuiPaneInfo, floatingPosition_1, 1}},
+ {2604, {wxAuiPaneInfo, floatingPosition_2, 2}},
+ {2605, {wxAuiPaneInfo, floatingSize_1, 1}},
+ {2606, {wxAuiPaneInfo, floatingSize_2, 2}},
+ {2607, {wxAuiPaneInfo, gripper, 1}},
+ {2608, {wxAuiPaneInfo, gripperTop, 1}},
+ {2609, {wxAuiPaneInfo, hasBorder, 0}},
+ {2610, {wxAuiPaneInfo, hasCaption, 0}},
+ {2611, {wxAuiPaneInfo, hasCloseButton, 0}},
+ {2612, {wxAuiPaneInfo, hasFlag, 1}},
+ {2613, {wxAuiPaneInfo, hasGripper, 0}},
+ {2614, {wxAuiPaneInfo, hasGripperTop, 0}},
+ {2615, {wxAuiPaneInfo, hasMaximizeButton, 0}},
+ {2616, {wxAuiPaneInfo, hasMinimizeButton, 0}},
+ {2617, {wxAuiPaneInfo, hasPinButton, 0}},
+ {2618, {wxAuiPaneInfo, hide, 0}},
+ {2619, {wxAuiPaneInfo, isBottomDockable, 0}},
+ {2620, {wxAuiPaneInfo, isDocked, 0}},
+ {2621, {wxAuiPaneInfo, isFixed, 0}},
+ {2622, {wxAuiPaneInfo, isFloatable, 0}},
+ {2623, {wxAuiPaneInfo, isFloating, 0}},
+ {2624, {wxAuiPaneInfo, isLeftDockable, 0}},
+ {2625, {wxAuiPaneInfo, isMovable, 0}},
+ {2626, {wxAuiPaneInfo, isOk, 0}},
+ {2627, {wxAuiPaneInfo, isResizable, 0}},
+ {2628, {wxAuiPaneInfo, isRightDockable, 0}},
+ {2629, {wxAuiPaneInfo, isShown, 0}},
+ {2630, {wxAuiPaneInfo, isToolbar, 0}},
+ {2631, {wxAuiPaneInfo, isTopDockable, 0}},
+ {2632, {wxAuiPaneInfo, layer, 1}},
+ {2633, {wxAuiPaneInfo, left, 0}},
+ {2634, {wxAuiPaneInfo, leftDockable, 1}},
+ {2635, {wxAuiPaneInfo, maxSize_1, 1}},
+ {2636, {wxAuiPaneInfo, maxSize_2, 2}},
+ {2637, {wxAuiPaneInfo, maximizeButton, 1}},
+ {2638, {wxAuiPaneInfo, minSize_1, 1}},
+ {2639, {wxAuiPaneInfo, minSize_2, 2}},
+ {2640, {wxAuiPaneInfo, minimizeButton, 1}},
+ {2641, {wxAuiPaneInfo, movable, 1}},
+ {2642, {wxAuiPaneInfo, name, 1}},
+ {2643, {wxAuiPaneInfo, paneBorder, 1}},
+ {2644, {wxAuiPaneInfo, pinButton, 1}},
+ {2645, {wxAuiPaneInfo, position, 1}},
+ {2646, {wxAuiPaneInfo, resizable, 1}},
+ {2647, {wxAuiPaneInfo, right, 0}},
+ {2648, {wxAuiPaneInfo, rightDockable, 1}},
+ {2649, {wxAuiPaneInfo, row, 1}},
+ {2650, {wxAuiPaneInfo, safeSet, 1}},
+ {2651, {wxAuiPaneInfo, setFlag, 2}},
+ {2652, {wxAuiPaneInfo, show, 1}},
+ {2653, {wxAuiPaneInfo, toolbarPane, 0}},
+ {2654, {wxAuiPaneInfo, top, 0}},
+ {2655, {wxAuiPaneInfo, topDockable, 1}},
+ {2656, {wxAuiPaneInfo, window, 1}},
+ {2657, {wxAuiPaneInfo, getWindow, 0}},
+ {2658, {wxAuiPaneInfo, getFrame, 0}},
+ {2659, {wxAuiPaneInfo, getDirection, 0}},
+ {2660, {wxAuiPaneInfo, getLayer, 0}},
+ {2661, {wxAuiPaneInfo, getRow, 0}},
+ {2662, {wxAuiPaneInfo, getPosition, 0}},
+ {2663, {wxAuiPaneInfo, getFloatingPosition, 0}},
+ {2664, {wxAuiPaneInfo, getFloatingSize, 0}},
+ {2665, {wxAuiNotebook, new_0, 0}},
+ {2666, {wxAuiNotebook, new_2, 2}},
+ {2667, {wxAuiNotebook, addPage, 3}},
+ {2668, {wxAuiNotebook, create, 2}},
+ {2669, {wxAuiNotebook, deletePage, 1}},
+ {2670, {wxAuiNotebook, getArtProvider, 0}},
+ {2671, {wxAuiNotebook, getPage, 1}},
+ {2672, {wxAuiNotebook, getPageBitmap, 1}},
+ {2673, {wxAuiNotebook, getPageCount, 0}},
+ {2674, {wxAuiNotebook, getPageIndex, 1}},
+ {2675, {wxAuiNotebook, getPageText, 1}},
+ {2676, {wxAuiNotebook, getSelection, 0}},
+ {2677, {wxAuiNotebook, insertPage, 4}},
+ {2678, {wxAuiNotebook, removePage, 1}},
+ {2679, {wxAuiNotebook, setArtProvider, 1}},
+ {2680, {wxAuiNotebook, setFont, 1}},
+ {2681, {wxAuiNotebook, setPageBitmap, 2}},
+ {2682, {wxAuiNotebook, setPageText, 2}},
+ {2683, {wxAuiNotebook, setSelection, 1}},
+ {2684, {wxAuiNotebook, setTabCtrlHeight, 1}},
+ {2685, {wxAuiNotebook, setUniformBitmapSize, 1}},
+ {2686, {wxAuiNotebook, 'Destroy', undefined}},
+ {2687, {wxAuiTabArt, setFlags, 1}},
+ {2688, {wxAuiTabArt, setMeasuringFont, 1}},
+ {2689, {wxAuiTabArt, setNormalFont, 1}},
+ {2690, {wxAuiTabArt, setSelectedFont, 1}},
+ {2691, {wxAuiTabArt, setColour, 1}},
+ {2692, {wxAuiTabArt, setActiveColour, 1}},
+ {2693, {wxAuiDockArt, getColour, 1}},
+ {2694, {wxAuiDockArt, getFont, 1}},
+ {2695, {wxAuiDockArt, getMetric, 1}},
+ {2696, {wxAuiDockArt, setColour, 2}},
+ {2697, {wxAuiDockArt, setFont, 2}},
+ {2698, {wxAuiDockArt, setMetric, 2}},
+ {2699, {wxAuiSimpleTabArt, new, 0}},
+ {2700, {wxAuiSimpleTabArt, 'Destroy', undefined}},
+ {2701, {wxMDIParentFrame, new_0, 0}},
+ {2702, {wxMDIParentFrame, new_4, 4}},
+ {2703, {wxMDIParentFrame, destruct, 0}},
+ {2704, {wxMDIParentFrame, activateNext, 0}},
+ {2705, {wxMDIParentFrame, activatePrevious, 0}},
+ {2706, {wxMDIParentFrame, arrangeIcons, 0}},
+ {2707, {wxMDIParentFrame, cascade, 0}},
+ {2708, {wxMDIParentFrame, create, 4}},
+ {2709, {wxMDIParentFrame, getActiveChild, 0}},
+ {2710, {wxMDIParentFrame, getClientWindow, 0}},
+ {2711, {wxMDIParentFrame, tile, 1}},
+ {2712, {wxMDIChildFrame, new_0, 0}},
+ {2713, {wxMDIChildFrame, new_4, 4}},
+ {2714, {wxMDIChildFrame, destruct, 0}},
+ {2715, {wxMDIChildFrame, activate, 0}},
+ {2716, {wxMDIChildFrame, create, 4}},
+ {2717, {wxMDIChildFrame, maximize, 1}},
+ {2718, {wxMDIChildFrame, restore, 0}},
+ {2719, {wxMDIClientWindow, new_0, 0}},
+ {2720, {wxMDIClientWindow, new_2, 2}},
+ {2721, {wxMDIClientWindow, destruct, 0}},
+ {2722, {wxMDIClientWindow, createClient, 2}},
+ {2723, {wxLayoutAlgorithm, new, 0}},
+ {2724, {wxLayoutAlgorithm, layoutFrame, 2}},
+ {2725, {wxLayoutAlgorithm, layoutMDIFrame, 2}},
+ {2726, {wxLayoutAlgorithm, layoutWindow, 2}},
+ {2727, {wxLayoutAlgorithm, 'Destroy', undefined}},
+ {2728, {wxEvent, getId, 0}},
+ {2729, {wxEvent, getSkipped, 0}},
+ {2730, {wxEvent, getTimestamp, 0}},
+ {2731, {wxEvent, isCommandEvent, 0}},
+ {2732, {wxEvent, resumePropagation, 1}},
+ {2733, {wxEvent, shouldPropagate, 0}},
+ {2734, {wxEvent, skip, 1}},
+ {2735, {wxEvent, stopPropagation, 0}},
+ {2736, {wxCommandEvent, getClientData, 0}},
+ {2737, {wxCommandEvent, getExtraLong, 0}},
+ {2738, {wxCommandEvent, getInt, 0}},
+ {2739, {wxCommandEvent, getSelection, 0}},
+ {2740, {wxCommandEvent, getString, 0}},
+ {2741, {wxCommandEvent, isChecked, 0}},
+ {2742, {wxCommandEvent, isSelection, 0}},
+ {2743, {wxCommandEvent, setInt, 1}},
+ {2744, {wxCommandEvent, setString, 1}},
+ {2745, {wxScrollEvent, getOrientation, 0}},
+ {2746, {wxScrollEvent, getPosition, 0}},
+ {2747, {wxScrollWinEvent, getOrientation, 0}},
+ {2748, {wxScrollWinEvent, getPosition, 0}},
+ {2749, {wxMouseEvent, altDown, 0}},
+ {2750, {wxMouseEvent, button, 1}},
+ {2751, {wxMouseEvent, buttonDClick, 1}},
+ {2752, {wxMouseEvent, buttonDown, 1}},
+ {2753, {wxMouseEvent, buttonUp, 1}},
+ {2754, {wxMouseEvent, cmdDown, 0}},
+ {2755, {wxMouseEvent, controlDown, 0}},
+ {2756, {wxMouseEvent, dragging, 0}},
+ {2757, {wxMouseEvent, entering, 0}},
+ {2758, {wxMouseEvent, getButton, 0}},
+ {2761, {wxMouseEvent, getPosition, 0}},
+ {2762, {wxMouseEvent, getLogicalPosition, 1}},
+ {2763, {wxMouseEvent, getLinesPerAction, 0}},
+ {2764, {wxMouseEvent, getWheelRotation, 0}},
+ {2765, {wxMouseEvent, getWheelDelta, 0}},
+ {2766, {wxMouseEvent, getX, 0}},
+ {2767, {wxMouseEvent, getY, 0}},
+ {2768, {wxMouseEvent, isButton, 0}},
+ {2769, {wxMouseEvent, isPageScroll, 0}},
+ {2770, {wxMouseEvent, leaving, 0}},
+ {2771, {wxMouseEvent, leftDClick, 0}},
+ {2772, {wxMouseEvent, leftDown, 0}},
+ {2773, {wxMouseEvent, leftIsDown, 0}},
+ {2774, {wxMouseEvent, leftUp, 0}},
+ {2775, {wxMouseEvent, metaDown, 0}},
+ {2776, {wxMouseEvent, middleDClick, 0}},
+ {2777, {wxMouseEvent, middleDown, 0}},
+ {2778, {wxMouseEvent, middleIsDown, 0}},
+ {2779, {wxMouseEvent, middleUp, 0}},
+ {2780, {wxMouseEvent, moving, 0}},
+ {2781, {wxMouseEvent, rightDClick, 0}},
+ {2782, {wxMouseEvent, rightDown, 0}},
+ {2783, {wxMouseEvent, rightIsDown, 0}},
+ {2784, {wxMouseEvent, rightUp, 0}},
+ {2785, {wxMouseEvent, shiftDown, 0}},
+ {2786, {wxSetCursorEvent, getCursor, 0}},
+ {2787, {wxSetCursorEvent, getX, 0}},
+ {2788, {wxSetCursorEvent, getY, 0}},
+ {2789, {wxSetCursorEvent, hasCursor, 0}},
+ {2790, {wxSetCursorEvent, setCursor, 1}},
+ {2791, {wxKeyEvent, altDown, 0}},
+ {2792, {wxKeyEvent, cmdDown, 0}},
+ {2793, {wxKeyEvent, controlDown, 0}},
+ {2794, {wxKeyEvent, getKeyCode, 0}},
+ {2795, {wxKeyEvent, getModifiers, 0}},
+ {2798, {wxKeyEvent, getPosition, 0}},
+ {2799, {wxKeyEvent, getRawKeyCode, 0}},
+ {2800, {wxKeyEvent, getRawKeyFlags, 0}},
+ {2801, {wxKeyEvent, getUnicodeKey, 0}},
+ {2802, {wxKeyEvent, getX, 0}},
+ {2803, {wxKeyEvent, getY, 0}},
+ {2804, {wxKeyEvent, hasModifiers, 0}},
+ {2805, {wxKeyEvent, metaDown, 0}},
+ {2806, {wxKeyEvent, shiftDown, 0}},
+ {2807, {wxSizeEvent, getSize, 0}},
+ {2808, {wxMoveEvent, getPosition, 0}},
+ {2809, {wxEraseEvent, getDC, 0}},
+ {2810, {wxFocusEvent, getWindow, 0}},
+ {2811, {wxChildFocusEvent, getWindow, 0}},
+ {2812, {wxMenuEvent, getMenu, 0}},
+ {2813, {wxMenuEvent, getMenuId, 0}},
+ {2814, {wxMenuEvent, isPopup, 0}},
+ {2815, {wxCloseEvent, canVeto, 0}},
+ {2816, {wxCloseEvent, getLoggingOff, 0}},
+ {2817, {wxCloseEvent, setCanVeto, 1}},
+ {2818, {wxCloseEvent, setLoggingOff, 1}},
+ {2819, {wxCloseEvent, veto, 1}},
+ {2820, {wxShowEvent, setShow, 1}},
+ {2821, {wxShowEvent, getShow, 0}},
+ {2822, {wxIconizeEvent, iconized, 0}},
+ {2823, {wxJoystickEvent, buttonDown, 1}},
+ {2824, {wxJoystickEvent, buttonIsDown, 1}},
+ {2825, {wxJoystickEvent, buttonUp, 1}},
+ {2826, {wxJoystickEvent, getButtonChange, 0}},
+ {2827, {wxJoystickEvent, getButtonState, 0}},
+ {2828, {wxJoystickEvent, getJoystick, 0}},
+ {2829, {wxJoystickEvent, getPosition, 0}},
+ {2830, {wxJoystickEvent, getZPosition, 0}},
+ {2831, {wxJoystickEvent, isButton, 0}},
+ {2832, {wxJoystickEvent, isMove, 0}},
+ {2833, {wxJoystickEvent, isZMove, 0}},
+ {2834, {wxUpdateUIEvent, canUpdate, 1}},
+ {2835, {wxUpdateUIEvent, check, 1}},
+ {2836, {wxUpdateUIEvent, enable, 1}},
+ {2837, {wxUpdateUIEvent, show, 1}},
+ {2838, {wxUpdateUIEvent, getChecked, 0}},
+ {2839, {wxUpdateUIEvent, getEnabled, 0}},
+ {2840, {wxUpdateUIEvent, getShown, 0}},
+ {2841, {wxUpdateUIEvent, getSetChecked, 0}},
+ {2842, {wxUpdateUIEvent, getSetEnabled, 0}},
+ {2843, {wxUpdateUIEvent, getSetShown, 0}},
+ {2844, {wxUpdateUIEvent, getSetText, 0}},
+ {2845, {wxUpdateUIEvent, getText, 0}},
+ {2846, {wxUpdateUIEvent, getMode, 0}},
+ {2847, {wxUpdateUIEvent, getUpdateInterval, 0}},
+ {2848, {wxUpdateUIEvent, resetUpdateTime, 0}},
+ {2849, {wxUpdateUIEvent, setMode, 1}},
+ {2850, {wxUpdateUIEvent, setText, 1}},
+ {2851, {wxUpdateUIEvent, setUpdateInterval, 1}},
+ {2852, {wxMouseCaptureChangedEvent, getCapturedWindow, 0}},
+ {2853, {wxPaletteChangedEvent, setChangedWindow, 1}},
+ {2854, {wxPaletteChangedEvent, getChangedWindow, 0}},
+ {2855, {wxQueryNewPaletteEvent, setPaletteRealized, 1}},
+ {2856, {wxQueryNewPaletteEvent, getPaletteRealized, 0}},
+ {2857, {wxNavigationKeyEvent, getDirection, 0}},
+ {2858, {wxNavigationKeyEvent, setDirection, 1}},
+ {2859, {wxNavigationKeyEvent, isWindowChange, 0}},
+ {2860, {wxNavigationKeyEvent, setWindowChange, 1}},
+ {2861, {wxNavigationKeyEvent, isFromTab, 0}},
+ {2862, {wxNavigationKeyEvent, setFromTab, 1}},
+ {2863, {wxNavigationKeyEvent, getCurrentFocus, 0}},
+ {2864, {wxNavigationKeyEvent, setCurrentFocus, 1}},
+ {2865, {wxHelpEvent, getOrigin, 0}},
+ {2866, {wxHelpEvent, getPosition, 0}},
+ {2867, {wxHelpEvent, setOrigin, 1}},
+ {2868, {wxHelpEvent, setPosition, 1}},
+ {2869, {wxContextMenuEvent, getPosition, 0}},
+ {2870, {wxContextMenuEvent, setPosition, 1}},
+ {2871, {wxIdleEvent, canSend, 1}},
+ {2872, {wxIdleEvent, getMode, 0}},
+ {2873, {wxIdleEvent, requestMore, 1}},
+ {2874, {wxIdleEvent, moreRequested, 0}},
+ {2875, {wxIdleEvent, setMode, 1}},
+ {2876, {wxGridEvent, altDown, 0}},
+ {2877, {wxGridEvent, controlDown, 0}},
+ {2878, {wxGridEvent, getCol, 0}},
+ {2879, {wxGridEvent, getPosition, 0}},
+ {2880, {wxGridEvent, getRow, 0}},
+ {2881, {wxGridEvent, metaDown, 0}},
+ {2882, {wxGridEvent, selecting, 0}},
+ {2883, {wxGridEvent, shiftDown, 0}},
+ {2884, {wxNotifyEvent, allow, 0}},
+ {2885, {wxNotifyEvent, isAllowed, 0}},
+ {2886, {wxNotifyEvent, veto, 0}},
+ {2887, {wxSashEvent, getEdge, 0}},
+ {2888, {wxSashEvent, getDragRect, 0}},
+ {2889, {wxSashEvent, getDragStatus, 0}},
+ {2890, {wxListEvent, getCacheFrom, 0}},
+ {2891, {wxListEvent, getCacheTo, 0}},
+ {2892, {wxListEvent, getKeyCode, 0}},
+ {2893, {wxListEvent, getIndex, 0}},
+ {2894, {wxListEvent, getColumn, 0}},
+ {2895, {wxListEvent, getPoint, 0}},
+ {2896, {wxListEvent, getLabel, 0}},
+ {2897, {wxListEvent, getText, 0}},
+ {2898, {wxListEvent, getImage, 0}},
+ {2899, {wxListEvent, getData, 0}},
+ {2900, {wxListEvent, getMask, 0}},
+ {2901, {wxListEvent, getItem, 0}},
+ {2902, {wxListEvent, isEditCancelled, 0}},
+ {2903, {wxDateEvent, getDate, 0}},
+ {2904, {wxCalendarEvent, getWeekDay, 0}},
+ {2905, {wxFileDirPickerEvent, getPath, 0}},
+ {2906, {wxColourPickerEvent, getColour, 0}},
+ {2907, {wxFontPickerEvent, getFont, 0}},
+ {2908, {wxStyledTextEvent, getPosition, 0}},
+ {2909, {wxStyledTextEvent, getKey, 0}},
+ {2910, {wxStyledTextEvent, getModifiers, 0}},
+ {2911, {wxStyledTextEvent, getModificationType, 0}},
+ {2912, {wxStyledTextEvent, getText, 0}},
+ {2913, {wxStyledTextEvent, getLength, 0}},
+ {2914, {wxStyledTextEvent, getLinesAdded, 0}},
+ {2915, {wxStyledTextEvent, getLine, 0}},
+ {2916, {wxStyledTextEvent, getFoldLevelNow, 0}},
+ {2917, {wxStyledTextEvent, getFoldLevelPrev, 0}},
+ {2918, {wxStyledTextEvent, getMargin, 0}},
+ {2919, {wxStyledTextEvent, getMessage, 0}},
+ {2920, {wxStyledTextEvent, getWParam, 0}},
+ {2921, {wxStyledTextEvent, getLParam, 0}},
+ {2922, {wxStyledTextEvent, getListType, 0}},
+ {2923, {wxStyledTextEvent, getX, 0}},
+ {2924, {wxStyledTextEvent, getY, 0}},
+ {2925, {wxStyledTextEvent, getDragText, 0}},
+ {2926, {wxStyledTextEvent, getDragAllowMove, 0}},
+ {2927, {wxStyledTextEvent, getDragResult, 0}},
+ {2928, {wxStyledTextEvent, getShift, 0}},
+ {2929, {wxStyledTextEvent, getControl, 0}},
+ {2930, {wxStyledTextEvent, getAlt, 0}},
+ {2931, {utils, getKeyState, 1}},
+ {2932, {utils, getMousePosition, 2}},
+ {2933, {utils, getMouseState, 0}},
+ {2934, {utils, setDetectableAutoRepeat, 1}},
+ {2935, {utils, bell, 0}},
+ {2936, {utils, findMenuItemId, 3}},
+ {2937, {utils, genericFindWindowAtPoint, 1}},
+ {2938, {utils, findWindowAtPoint, 1}},
+ {2939, {utils, beginBusyCursor, 1}},
+ {2940, {utils, endBusyCursor, 0}},
+ {2941, {utils, isBusy, 0}},
+ {2942, {utils, shutdown, 1}},
+ {2943, {utils, shell, 1}},
+ {2944, {utils, launchDefaultBrowser, 2}},
+ {2945, {utils, getEmailAddress, 0}},
+ {2946, {utils, getUserId, 0}},
+ {2947, {utils, getHomeDir, 0}},
+ {2948, {utils, newId, 0}},
+ {2949, {utils, registerId, 1}},
+ {2950, {utils, getCurrentId, 0}},
+ {2951, {utils, getOsDescription, 0}},
+ {2952, {utils, isPlatformLittleEndian, 0}},
+ {2953, {utils, isPlatform64Bit, 0}},
+ {2954, {gdicmn, displaySize, 2}},
+ {2955, {gdicmn, setCursor, 1}},
+ {2956, {wxPrintout, new, 1}},
+ {2957, {wxPrintout, destruct, 0}},
+ {2958, {wxPrintout, getDC, 0}},
+ {2959, {wxPrintout, getPageSizeMM, 2}},
+ {2960, {wxPrintout, getPageSizePixels, 2}},
+ {2961, {wxPrintout, getPaperRectPixels, 0}},
+ {2962, {wxPrintout, getPPIPrinter, 2}},
+ {2963, {wxPrintout, getPPIScreen, 2}},
+ {2964, {wxPrintout, getTitle, 0}},
+ {2965, {wxPrintout, isPreview, 0}},
+ {2966, {wxPrintout, fitThisSizeToPaper, 1}},
+ {2967, {wxPrintout, fitThisSizeToPage, 1}},
+ {2968, {wxPrintout, fitThisSizeToPageMargins, 2}},
+ {2969, {wxPrintout, mapScreenSizeToPaper, 0}},
+ {2970, {wxPrintout, mapScreenSizeToPage, 0}},
+ {2971, {wxPrintout, mapScreenSizeToPageMargins, 1}},
+ {2972, {wxPrintout, mapScreenSizeToDevice, 0}},
+ {2973, {wxPrintout, getLogicalPaperRect, 0}},
+ {2974, {wxPrintout, getLogicalPageRect, 0}},
+ {2975, {wxPrintout, getLogicalPageMarginsRect, 1}},
+ {2976, {wxPrintout, setLogicalOrigin, 2}},
+ {2977, {wxPrintout, offsetLogicalOrigin, 2}},
+ {2978, {wxStyledTextCtrl, new_2, 2}},
+ {2979, {wxStyledTextCtrl, new_0, 0}},
+ {2980, {wxStyledTextCtrl, destruct, 0}},
+ {2981, {wxStyledTextCtrl, create, 2}},
+ {2982, {wxStyledTextCtrl, addText, 1}},
+ {2983, {wxStyledTextCtrl, addStyledText, 1}},
+ {2984, {wxStyledTextCtrl, insertText, 2}},
+ {2985, {wxStyledTextCtrl, clearAll, 0}},
+ {2986, {wxStyledTextCtrl, clearDocumentStyle, 0}},
+ {2987, {wxStyledTextCtrl, getLength, 0}},
+ {2988, {wxStyledTextCtrl, getCharAt, 1}},
+ {2989, {wxStyledTextCtrl, getCurrentPos, 0}},
+ {2990, {wxStyledTextCtrl, getAnchor, 0}},
+ {2991, {wxStyledTextCtrl, getStyleAt, 1}},
+ {2992, {wxStyledTextCtrl, redo, 0}},
+ {2993, {wxStyledTextCtrl, setUndoCollection, 1}},
+ {2994, {wxStyledTextCtrl, selectAll, 0}},
+ {2995, {wxStyledTextCtrl, setSavePoint, 0}},
+ {2996, {wxStyledTextCtrl, getStyledText, 2}},
+ {2997, {wxStyledTextCtrl, canRedo, 0}},
+ {2998, {wxStyledTextCtrl, markerLineFromHandle, 1}},
+ {2999, {wxStyledTextCtrl, markerDeleteHandle, 1}},
+ {3000, {wxStyledTextCtrl, getUndoCollection, 0}},
+ {3001, {wxStyledTextCtrl, getViewWhiteSpace, 0}},
+ {3002, {wxStyledTextCtrl, setViewWhiteSpace, 1}},
+ {3003, {wxStyledTextCtrl, positionFromPoint, 1}},
+ {3004, {wxStyledTextCtrl, positionFromPointClose, 2}},
+ {3005, {wxStyledTextCtrl, gotoLine, 1}},
+ {3006, {wxStyledTextCtrl, gotoPos, 1}},
+ {3007, {wxStyledTextCtrl, setAnchor, 1}},
+ {3008, {wxStyledTextCtrl, getCurLine, 1}},
+ {3009, {wxStyledTextCtrl, getEndStyled, 0}},
+ {3010, {wxStyledTextCtrl, convertEOLs, 1}},
+ {3011, {wxStyledTextCtrl, getEOLMode, 0}},
+ {3012, {wxStyledTextCtrl, setEOLMode, 1}},
+ {3013, {wxStyledTextCtrl, startStyling, 2}},
+ {3014, {wxStyledTextCtrl, setStyling, 2}},
+ {3015, {wxStyledTextCtrl, getBufferedDraw, 0}},
+ {3016, {wxStyledTextCtrl, setBufferedDraw, 1}},
+ {3017, {wxStyledTextCtrl, setTabWidth, 1}},
+ {3018, {wxStyledTextCtrl, getTabWidth, 0}},
+ {3019, {wxStyledTextCtrl, setCodePage, 1}},
+ {3020, {wxStyledTextCtrl, markerDefine, 3}},
+ {3021, {wxStyledTextCtrl, markerSetForeground, 2}},
+ {3022, {wxStyledTextCtrl, markerSetBackground, 2}},
+ {3023, {wxStyledTextCtrl, markerAdd, 2}},
+ {3024, {wxStyledTextCtrl, markerDelete, 2}},
+ {3025, {wxStyledTextCtrl, markerDeleteAll, 1}},
+ {3026, {wxStyledTextCtrl, markerGet, 1}},
+ {3027, {wxStyledTextCtrl, markerNext, 2}},
+ {3028, {wxStyledTextCtrl, markerPrevious, 2}},
+ {3029, {wxStyledTextCtrl, markerDefineBitmap, 2}},
+ {3030, {wxStyledTextCtrl, markerAddSet, 2}},
+ {3031, {wxStyledTextCtrl, markerSetAlpha, 2}},
+ {3032, {wxStyledTextCtrl, setMarginType, 2}},
+ {3033, {wxStyledTextCtrl, getMarginType, 1}},
+ {3034, {wxStyledTextCtrl, setMarginWidth, 2}},
+ {3035, {wxStyledTextCtrl, getMarginWidth, 1}},
+ {3036, {wxStyledTextCtrl, setMarginMask, 2}},
+ {3037, {wxStyledTextCtrl, getMarginMask, 1}},
+ {3038, {wxStyledTextCtrl, setMarginSensitive, 2}},
+ {3039, {wxStyledTextCtrl, getMarginSensitive, 1}},
+ {3040, {wxStyledTextCtrl, styleClearAll, 0}},
+ {3041, {wxStyledTextCtrl, styleSetForeground, 2}},
+ {3042, {wxStyledTextCtrl, styleSetBackground, 2}},
+ {3043, {wxStyledTextCtrl, styleSetBold, 2}},
+ {3044, {wxStyledTextCtrl, styleSetItalic, 2}},
+ {3045, {wxStyledTextCtrl, styleSetSize, 2}},
+ {3046, {wxStyledTextCtrl, styleSetFaceName, 2}},
+ {3047, {wxStyledTextCtrl, styleSetEOLFilled, 2}},
+ {3048, {wxStyledTextCtrl, styleResetDefault, 0}},
+ {3049, {wxStyledTextCtrl, styleSetUnderline, 2}},
+ {3050, {wxStyledTextCtrl, styleSetCase, 2}},
+ {3051, {wxStyledTextCtrl, styleSetHotSpot, 2}},
+ {3052, {wxStyledTextCtrl, setSelForeground, 2}},
+ {3053, {wxStyledTextCtrl, setSelBackground, 2}},
+ {3054, {wxStyledTextCtrl, getSelAlpha, 0}},
+ {3055, {wxStyledTextCtrl, setSelAlpha, 1}},
+ {3056, {wxStyledTextCtrl, setCaretForeground, 1}},
+ {3057, {wxStyledTextCtrl, cmdKeyAssign, 3}},
+ {3058, {wxStyledTextCtrl, cmdKeyClear, 2}},
+ {3059, {wxStyledTextCtrl, cmdKeyClearAll, 0}},
+ {3060, {wxStyledTextCtrl, setStyleBytes, 2}},
+ {3061, {wxStyledTextCtrl, styleSetVisible, 2}},
+ {3062, {wxStyledTextCtrl, getCaretPeriod, 0}},
+ {3063, {wxStyledTextCtrl, setCaretPeriod, 1}},
+ {3064, {wxStyledTextCtrl, setWordChars, 1}},
+ {3065, {wxStyledTextCtrl, beginUndoAction, 0}},
+ {3066, {wxStyledTextCtrl, endUndoAction, 0}},
+ {3067, {wxStyledTextCtrl, indicatorSetStyle, 2}},
+ {3068, {wxStyledTextCtrl, indicatorGetStyle, 1}},
+ {3069, {wxStyledTextCtrl, indicatorSetForeground, 2}},
+ {3070, {wxStyledTextCtrl, indicatorGetForeground, 1}},
+ {3071, {wxStyledTextCtrl, setWhitespaceForeground, 2}},
+ {3072, {wxStyledTextCtrl, setWhitespaceBackground, 2}},
+ {3073, {wxStyledTextCtrl, getStyleBits, 0}},
+ {3074, {wxStyledTextCtrl, setLineState, 2}},
+ {3075, {wxStyledTextCtrl, getLineState, 1}},
+ {3076, {wxStyledTextCtrl, getMaxLineState, 0}},
+ {3077, {wxStyledTextCtrl, getCaretLineVisible, 0}},
+ {3078, {wxStyledTextCtrl, setCaretLineVisible, 1}},
+ {3079, {wxStyledTextCtrl, getCaretLineBackground, 0}},
+ {3080, {wxStyledTextCtrl, setCaretLineBackground, 1}},
+ {3081, {wxStyledTextCtrl, autoCompShow, 2}},
+ {3082, {wxStyledTextCtrl, autoCompCancel, 0}},
+ {3083, {wxStyledTextCtrl, autoCompActive, 0}},
+ {3084, {wxStyledTextCtrl, autoCompPosStart, 0}},
+ {3085, {wxStyledTextCtrl, autoCompComplete, 0}},
+ {3086, {wxStyledTextCtrl, autoCompStops, 1}},
+ {3087, {wxStyledTextCtrl, autoCompSetSeparator, 1}},
+ {3088, {wxStyledTextCtrl, autoCompGetSeparator, 0}},
+ {3089, {wxStyledTextCtrl, autoCompSelect, 1}},
+ {3090, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}},
+ {3091, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}},
+ {3092, {wxStyledTextCtrl, autoCompSetFillUps, 1}},
+ {3093, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}},
+ {3094, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}},
+ {3095, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}},
+ {3096, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}},
+ {3097, {wxStyledTextCtrl, userListShow, 2}},
+ {3098, {wxStyledTextCtrl, autoCompSetAutoHide, 1}},
+ {3099, {wxStyledTextCtrl, autoCompGetAutoHide, 0}},
+ {3100, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}},
+ {3101, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}},
+ {3102, {wxStyledTextCtrl, registerImage, 2}},
+ {3103, {wxStyledTextCtrl, clearRegisteredImages, 0}},
+ {3104, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}},
+ {3105, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}},
+ {3106, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}},
+ {3107, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}},
+ {3108, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}},
+ {3109, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}},
+ {3110, {wxStyledTextCtrl, setIndent, 1}},
+ {3111, {wxStyledTextCtrl, getIndent, 0}},
+ {3112, {wxStyledTextCtrl, setUseTabs, 1}},
+ {3113, {wxStyledTextCtrl, getUseTabs, 0}},
+ {3114, {wxStyledTextCtrl, setLineIndentation, 2}},
+ {3115, {wxStyledTextCtrl, getLineIndentation, 1}},
+ {3116, {wxStyledTextCtrl, getLineIndentPosition, 1}},
+ {3117, {wxStyledTextCtrl, getColumn, 1}},
+ {3118, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}},
+ {3119, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}},
+ {3120, {wxStyledTextCtrl, setIndentationGuides, 1}},
+ {3121, {wxStyledTextCtrl, getIndentationGuides, 0}},
+ {3122, {wxStyledTextCtrl, setHighlightGuide, 1}},
+ {3123, {wxStyledTextCtrl, getHighlightGuide, 0}},
+ {3124, {wxStyledTextCtrl, getLineEndPosition, 1}},
+ {3125, {wxStyledTextCtrl, getCodePage, 0}},
+ {3126, {wxStyledTextCtrl, getCaretForeground, 0}},
+ {3127, {wxStyledTextCtrl, getReadOnly, 0}},
+ {3128, {wxStyledTextCtrl, setCurrentPos, 1}},
+ {3129, {wxStyledTextCtrl, setSelectionStart, 1}},
+ {3130, {wxStyledTextCtrl, getSelectionStart, 0}},
+ {3131, {wxStyledTextCtrl, setSelectionEnd, 1}},
+ {3132, {wxStyledTextCtrl, getSelectionEnd, 0}},
+ {3133, {wxStyledTextCtrl, setPrintMagnification, 1}},
+ {3134, {wxStyledTextCtrl, getPrintMagnification, 0}},
+ {3135, {wxStyledTextCtrl, setPrintColourMode, 1}},
+ {3136, {wxStyledTextCtrl, getPrintColourMode, 0}},
+ {3137, {wxStyledTextCtrl, findText, 4}},
+ {3138, {wxStyledTextCtrl, formatRange, 7}},
+ {3139, {wxStyledTextCtrl, getFirstVisibleLine, 0}},
+ {3140, {wxStyledTextCtrl, getLine, 1}},
+ {3141, {wxStyledTextCtrl, getLineCount, 0}},
+ {3142, {wxStyledTextCtrl, setMarginLeft, 1}},
+ {3143, {wxStyledTextCtrl, getMarginLeft, 0}},
+ {3144, {wxStyledTextCtrl, setMarginRight, 1}},
+ {3145, {wxStyledTextCtrl, getMarginRight, 0}},
+ {3146, {wxStyledTextCtrl, getModify, 0}},
+ {3147, {wxStyledTextCtrl, setSelection, 2}},
+ {3148, {wxStyledTextCtrl, getSelectedText, 0}},
+ {3149, {wxStyledTextCtrl, getTextRange, 2}},
+ {3150, {wxStyledTextCtrl, hideSelection, 1}},
+ {3151, {wxStyledTextCtrl, lineFromPosition, 1}},
+ {3152, {wxStyledTextCtrl, positionFromLine, 1}},
+ {3153, {wxStyledTextCtrl, lineScroll, 2}},
+ {3154, {wxStyledTextCtrl, ensureCaretVisible, 0}},
+ {3155, {wxStyledTextCtrl, replaceSelection, 1}},
+ {3156, {wxStyledTextCtrl, setReadOnly, 1}},
+ {3157, {wxStyledTextCtrl, canPaste, 0}},
+ {3158, {wxStyledTextCtrl, canUndo, 0}},
+ {3159, {wxStyledTextCtrl, emptyUndoBuffer, 0}},
+ {3160, {wxStyledTextCtrl, undo, 0}},
+ {3161, {wxStyledTextCtrl, cut, 0}},
+ {3162, {wxStyledTextCtrl, copy, 0}},
+ {3163, {wxStyledTextCtrl, paste, 0}},
+ {3164, {wxStyledTextCtrl, clear, 0}},
+ {3165, {wxStyledTextCtrl, setText, 1}},
+ {3166, {wxStyledTextCtrl, getText, 0}},
+ {3167, {wxStyledTextCtrl, getTextLength, 0}},
+ {3168, {wxStyledTextCtrl, getOvertype, 0}},
+ {3169, {wxStyledTextCtrl, setCaretWidth, 1}},
+ {3170, {wxStyledTextCtrl, getCaretWidth, 0}},
+ {3171, {wxStyledTextCtrl, setTargetStart, 1}},
+ {3172, {wxStyledTextCtrl, getTargetStart, 0}},
+ {3173, {wxStyledTextCtrl, setTargetEnd, 1}},
+ {3174, {wxStyledTextCtrl, getTargetEnd, 0}},
+ {3175, {wxStyledTextCtrl, replaceTarget, 1}},
+ {3176, {wxStyledTextCtrl, searchInTarget, 1}},
+ {3177, {wxStyledTextCtrl, setSearchFlags, 1}},
+ {3178, {wxStyledTextCtrl, getSearchFlags, 0}},
+ {3179, {wxStyledTextCtrl, callTipShow, 2}},
+ {3180, {wxStyledTextCtrl, callTipCancel, 0}},
+ {3181, {wxStyledTextCtrl, callTipActive, 0}},
+ {3182, {wxStyledTextCtrl, callTipPosAtStart, 0}},
+ {3183, {wxStyledTextCtrl, callTipSetHighlight, 2}},
+ {3184, {wxStyledTextCtrl, callTipSetBackground, 1}},
+ {3185, {wxStyledTextCtrl, callTipSetForeground, 1}},
+ {3186, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}},
+ {3187, {wxStyledTextCtrl, callTipUseStyle, 1}},
+ {3188, {wxStyledTextCtrl, visibleFromDocLine, 1}},
+ {3189, {wxStyledTextCtrl, docLineFromVisible, 1}},
+ {3190, {wxStyledTextCtrl, wrapCount, 1}},
+ {3191, {wxStyledTextCtrl, setFoldLevel, 2}},
+ {3192, {wxStyledTextCtrl, getFoldLevel, 1}},
+ {3193, {wxStyledTextCtrl, getLastChild, 2}},
+ {3194, {wxStyledTextCtrl, getFoldParent, 1}},
+ {3195, {wxStyledTextCtrl, showLines, 2}},
+ {3196, {wxStyledTextCtrl, hideLines, 2}},
+ {3197, {wxStyledTextCtrl, getLineVisible, 1}},
+ {3198, {wxStyledTextCtrl, setFoldExpanded, 2}},
+ {3199, {wxStyledTextCtrl, getFoldExpanded, 1}},
+ {3200, {wxStyledTextCtrl, toggleFold, 1}},
+ {3201, {wxStyledTextCtrl, ensureVisible, 1}},
+ {3202, {wxStyledTextCtrl, setFoldFlags, 1}},
+ {3203, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}},
+ {3204, {wxStyledTextCtrl, setTabIndents, 1}},
+ {3205, {wxStyledTextCtrl, getTabIndents, 0}},
+ {3206, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}},
+ {3207, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}},
+ {3208, {wxStyledTextCtrl, setMouseDwellTime, 1}},
+ {3209, {wxStyledTextCtrl, getMouseDwellTime, 0}},
+ {3210, {wxStyledTextCtrl, wordStartPosition, 2}},
+ {3211, {wxStyledTextCtrl, wordEndPosition, 2}},
+ {3212, {wxStyledTextCtrl, setWrapMode, 1}},
+ {3213, {wxStyledTextCtrl, getWrapMode, 0}},
+ {3214, {wxStyledTextCtrl, setWrapVisualFlags, 1}},
+ {3215, {wxStyledTextCtrl, getWrapVisualFlags, 0}},
+ {3216, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}},
+ {3217, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}},
+ {3218, {wxStyledTextCtrl, setWrapStartIndent, 1}},
+ {3219, {wxStyledTextCtrl, getWrapStartIndent, 0}},
+ {3220, {wxStyledTextCtrl, setLayoutCache, 1}},
+ {3221, {wxStyledTextCtrl, getLayoutCache, 0}},
+ {3222, {wxStyledTextCtrl, setScrollWidth, 1}},
+ {3223, {wxStyledTextCtrl, getScrollWidth, 0}},
+ {3224, {wxStyledTextCtrl, textWidth, 2}},
+ {3225, {wxStyledTextCtrl, getEndAtLastLine, 0}},
+ {3226, {wxStyledTextCtrl, textHeight, 1}},
+ {3227, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}},
+ {3228, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}},
+ {3229, {wxStyledTextCtrl, appendText, 1}},
+ {3230, {wxStyledTextCtrl, getTwoPhaseDraw, 0}},
+ {3231, {wxStyledTextCtrl, setTwoPhaseDraw, 1}},
+ {3232, {wxStyledTextCtrl, targetFromSelection, 0}},
+ {3233, {wxStyledTextCtrl, linesJoin, 0}},
+ {3234, {wxStyledTextCtrl, linesSplit, 1}},
+ {3235, {wxStyledTextCtrl, setFoldMarginColour, 2}},
+ {3236, {wxStyledTextCtrl, setFoldMarginHiColour, 2}},
+ {3237, {wxStyledTextCtrl, lineDown, 0}},
+ {3238, {wxStyledTextCtrl, lineDownExtend, 0}},
+ {3239, {wxStyledTextCtrl, lineUp, 0}},
+ {3240, {wxStyledTextCtrl, lineUpExtend, 0}},
+ {3241, {wxStyledTextCtrl, charLeft, 0}},
+ {3242, {wxStyledTextCtrl, charLeftExtend, 0}},
+ {3243, {wxStyledTextCtrl, charRight, 0}},
+ {3244, {wxStyledTextCtrl, charRightExtend, 0}},
+ {3245, {wxStyledTextCtrl, wordLeft, 0}},
+ {3246, {wxStyledTextCtrl, wordLeftExtend, 0}},
+ {3247, {wxStyledTextCtrl, wordRight, 0}},
+ {3248, {wxStyledTextCtrl, wordRightExtend, 0}},
+ {3249, {wxStyledTextCtrl, home, 0}},
+ {3250, {wxStyledTextCtrl, homeExtend, 0}},
+ {3251, {wxStyledTextCtrl, lineEnd, 0}},
+ {3252, {wxStyledTextCtrl, lineEndExtend, 0}},
+ {3253, {wxStyledTextCtrl, documentStart, 0}},
+ {3254, {wxStyledTextCtrl, documentStartExtend, 0}},
+ {3255, {wxStyledTextCtrl, documentEnd, 0}},
+ {3256, {wxStyledTextCtrl, documentEndExtend, 0}},
+ {3257, {wxStyledTextCtrl, pageUp, 0}},
+ {3258, {wxStyledTextCtrl, pageUpExtend, 0}},
+ {3259, {wxStyledTextCtrl, pageDown, 0}},
+ {3260, {wxStyledTextCtrl, pageDownExtend, 0}},
+ {3261, {wxStyledTextCtrl, editToggleOvertype, 0}},
+ {3262, {wxStyledTextCtrl, cancel, 0}},
+ {3263, {wxStyledTextCtrl, deleteBack, 0}},
+ {3264, {wxStyledTextCtrl, tab, 0}},
+ {3265, {wxStyledTextCtrl, backTab, 0}},
+ {3266, {wxStyledTextCtrl, newLine, 0}},
+ {3267, {wxStyledTextCtrl, formFeed, 0}},
+ {3268, {wxStyledTextCtrl, vCHome, 0}},
+ {3269, {wxStyledTextCtrl, vCHomeExtend, 0}},
+ {3270, {wxStyledTextCtrl, zoomIn, 0}},
+ {3271, {wxStyledTextCtrl, zoomOut, 0}},
+ {3272, {wxStyledTextCtrl, delWordLeft, 0}},
+ {3273, {wxStyledTextCtrl, delWordRight, 0}},
+ {3274, {wxStyledTextCtrl, lineCut, 0}},
+ {3275, {wxStyledTextCtrl, lineDelete, 0}},
+ {3276, {wxStyledTextCtrl, lineTranspose, 0}},
+ {3277, {wxStyledTextCtrl, lineDuplicate, 0}},
+ {3278, {wxStyledTextCtrl, lowerCase, 0}},
+ {3279, {wxStyledTextCtrl, upperCase, 0}},
+ {3280, {wxStyledTextCtrl, lineScrollDown, 0}},
+ {3281, {wxStyledTextCtrl, lineScrollUp, 0}},
+ {3282, {wxStyledTextCtrl, deleteBackNotLine, 0}},
+ {3283, {wxStyledTextCtrl, homeDisplay, 0}},
+ {3284, {wxStyledTextCtrl, homeDisplayExtend, 0}},
+ {3285, {wxStyledTextCtrl, lineEndDisplay, 0}},
+ {3286, {wxStyledTextCtrl, lineEndDisplayExtend, 0}},
+ {3287, {wxStyledTextCtrl, homeWrapExtend, 0}},
+ {3288, {wxStyledTextCtrl, lineEndWrap, 0}},
+ {3289, {wxStyledTextCtrl, lineEndWrapExtend, 0}},
+ {3290, {wxStyledTextCtrl, vCHomeWrap, 0}},
+ {3291, {wxStyledTextCtrl, vCHomeWrapExtend, 0}},
+ {3292, {wxStyledTextCtrl, lineCopy, 0}},
+ {3293, {wxStyledTextCtrl, moveCaretInsideView, 0}},
+ {3294, {wxStyledTextCtrl, lineLength, 1}},
+ {3295, {wxStyledTextCtrl, braceHighlight, 2}},
+ {3296, {wxStyledTextCtrl, braceBadLight, 1}},
+ {3297, {wxStyledTextCtrl, braceMatch, 1}},
+ {3298, {wxStyledTextCtrl, getViewEOL, 0}},
+ {3299, {wxStyledTextCtrl, setViewEOL, 1}},
+ {3300, {wxStyledTextCtrl, setModEventMask, 1}},
+ {3301, {wxStyledTextCtrl, getEdgeColumn, 0}},
+ {3302, {wxStyledTextCtrl, setEdgeColumn, 1}},
+ {3303, {wxStyledTextCtrl, setEdgeMode, 1}},
+ {3304, {wxStyledTextCtrl, getEdgeMode, 0}},
+ {3305, {wxStyledTextCtrl, getEdgeColour, 0}},
+ {3306, {wxStyledTextCtrl, setEdgeColour, 1}},
+ {3307, {wxStyledTextCtrl, searchAnchor, 0}},
+ {3308, {wxStyledTextCtrl, searchNext, 2}},
+ {3309, {wxStyledTextCtrl, searchPrev, 2}},
+ {3310, {wxStyledTextCtrl, linesOnScreen, 0}},
+ {3311, {wxStyledTextCtrl, usePopUp, 1}},
+ {3312, {wxStyledTextCtrl, selectionIsRectangle, 0}},
+ {3313, {wxStyledTextCtrl, setZoom, 1}},
+ {3314, {wxStyledTextCtrl, getZoom, 0}},
+ {3315, {wxStyledTextCtrl, getModEventMask, 0}},
+ {3316, {wxStyledTextCtrl, setSTCFocus, 1}},
+ {3317, {wxStyledTextCtrl, getSTCFocus, 0}},
+ {3318, {wxStyledTextCtrl, setStatus, 1}},
+ {3319, {wxStyledTextCtrl, getStatus, 0}},
+ {3320, {wxStyledTextCtrl, setMouseDownCaptures, 1}},
+ {3321, {wxStyledTextCtrl, getMouseDownCaptures, 0}},
+ {3322, {wxStyledTextCtrl, setSTCCursor, 1}},
+ {3323, {wxStyledTextCtrl, getSTCCursor, 0}},
+ {3324, {wxStyledTextCtrl, setControlCharSymbol, 1}},
+ {3325, {wxStyledTextCtrl, getControlCharSymbol, 0}},
+ {3326, {wxStyledTextCtrl, wordPartLeft, 0}},
+ {3327, {wxStyledTextCtrl, wordPartLeftExtend, 0}},
+ {3328, {wxStyledTextCtrl, wordPartRight, 0}},
+ {3329, {wxStyledTextCtrl, wordPartRightExtend, 0}},
+ {3330, {wxStyledTextCtrl, setVisiblePolicy, 2}},
+ {3331, {wxStyledTextCtrl, delLineLeft, 0}},
+ {3332, {wxStyledTextCtrl, delLineRight, 0}},
+ {3333, {wxStyledTextCtrl, getXOffset, 0}},
+ {3334, {wxStyledTextCtrl, chooseCaretX, 0}},
+ {3335, {wxStyledTextCtrl, setXCaretPolicy, 2}},
+ {3336, {wxStyledTextCtrl, setYCaretPolicy, 2}},
+ {3337, {wxStyledTextCtrl, getPrintWrapMode, 0}},
+ {3338, {wxStyledTextCtrl, setHotspotActiveForeground, 2}},
+ {3339, {wxStyledTextCtrl, setHotspotActiveBackground, 2}},
+ {3340, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}},
+ {3341, {wxStyledTextCtrl, setHotspotSingleLine, 1}},
+ {3342, {wxStyledTextCtrl, paraDownExtend, 0}},
+ {3343, {wxStyledTextCtrl, paraUp, 0}},
+ {3344, {wxStyledTextCtrl, paraUpExtend, 0}},
+ {3345, {wxStyledTextCtrl, positionBefore, 1}},
+ {3346, {wxStyledTextCtrl, positionAfter, 1}},
+ {3347, {wxStyledTextCtrl, copyRange, 2}},
+ {3348, {wxStyledTextCtrl, copyText, 2}},
+ {3349, {wxStyledTextCtrl, setSelectionMode, 1}},
+ {3350, {wxStyledTextCtrl, getSelectionMode, 0}},
+ {3351, {wxStyledTextCtrl, lineDownRectExtend, 0}},
+ {3352, {wxStyledTextCtrl, lineUpRectExtend, 0}},
+ {3353, {wxStyledTextCtrl, charLeftRectExtend, 0}},
+ {3354, {wxStyledTextCtrl, charRightRectExtend, 0}},
+ {3355, {wxStyledTextCtrl, homeRectExtend, 0}},
+ {3356, {wxStyledTextCtrl, vCHomeRectExtend, 0}},
+ {3357, {wxStyledTextCtrl, lineEndRectExtend, 0}},
+ {3358, {wxStyledTextCtrl, pageUpRectExtend, 0}},
+ {3359, {wxStyledTextCtrl, pageDownRectExtend, 0}},
+ {3360, {wxStyledTextCtrl, stutteredPageUp, 0}},
+ {3361, {wxStyledTextCtrl, stutteredPageUpExtend, 0}},
+ {3362, {wxStyledTextCtrl, stutteredPageDown, 0}},
+ {3363, {wxStyledTextCtrl, stutteredPageDownExtend, 0}},
+ {3364, {wxStyledTextCtrl, wordLeftEnd, 0}},
+ {3365, {wxStyledTextCtrl, wordLeftEndExtend, 0}},
+ {3366, {wxStyledTextCtrl, wordRightEnd, 0}},
+ {3367, {wxStyledTextCtrl, wordRightEndExtend, 0}},
+ {3368, {wxStyledTextCtrl, setWhitespaceChars, 1}},
+ {3369, {wxStyledTextCtrl, setCharsDefault, 0}},
+ {3370, {wxStyledTextCtrl, autoCompGetCurrent, 0}},
+ {3371, {wxStyledTextCtrl, allocate, 1}},
+ {3372, {wxStyledTextCtrl, findColumn, 2}},
+ {3373, {wxStyledTextCtrl, getCaretSticky, 0}},
+ {3374, {wxStyledTextCtrl, setCaretSticky, 1}},
+ {3375, {wxStyledTextCtrl, toggleCaretSticky, 0}},
+ {3376, {wxStyledTextCtrl, setPasteConvertEndings, 1}},
+ {3377, {wxStyledTextCtrl, getPasteConvertEndings, 0}},
+ {3378, {wxStyledTextCtrl, selectionDuplicate, 0}},
+ {3379, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}},
+ {3380, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}},
+ {3381, {wxStyledTextCtrl, startRecord, 0}},
+ {3382, {wxStyledTextCtrl, stopRecord, 0}},
+ {3383, {wxStyledTextCtrl, setLexer, 1}},
+ {3384, {wxStyledTextCtrl, getLexer, 0}},
+ {3385, {wxStyledTextCtrl, colourise, 2}},
+ {3386, {wxStyledTextCtrl, setProperty, 2}},
+ {3387, {wxStyledTextCtrl, setKeyWords, 2}},
+ {3388, {wxStyledTextCtrl, setLexerLanguage, 1}},
+ {3389, {wxStyledTextCtrl, getProperty, 1}},
+ {3390, {wxStyledTextCtrl, getStyleBitsNeeded, 0}},
+ {3391, {wxStyledTextCtrl, getCurrentLine, 0}},
+ {3392, {wxStyledTextCtrl, styleSetSpec, 2}},
+ {3393, {wxStyledTextCtrl, styleSetFont, 2}},
+ {3394, {wxStyledTextCtrl, styleSetFontAttr, 7}},
+ {3395, {wxStyledTextCtrl, styleSetCharacterSet, 2}},
+ {3396, {wxStyledTextCtrl, styleSetFontEncoding, 2}},
+ {3397, {wxStyledTextCtrl, cmdKeyExecute, 1}},
+ {3398, {wxStyledTextCtrl, setMargins, 2}},
+ {3399, {wxStyledTextCtrl, getSelection, 2}},
+ {3400, {wxStyledTextCtrl, pointFromPosition, 1}},
+ {3401, {wxStyledTextCtrl, scrollToLine, 1}},
+ {3402, {wxStyledTextCtrl, scrollToColumn, 1}},
+ {3403, {wxStyledTextCtrl, setVScrollBar, 1}},
+ {3404, {wxStyledTextCtrl, setHScrollBar, 1}},
+ {3405, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
+ {3406, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
+ {3407, {wxStyledTextCtrl, saveFile, 1}},
+ {3408, {wxStyledTextCtrl, loadFile, 1}},
+ {3409, {wxStyledTextCtrl, doDragOver, 3}},
+ {3410, {wxStyledTextCtrl, doDropText, 3}},
+ {3411, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
+ {3412, {wxStyledTextCtrl, addTextRaw, 1}},
+ {3413, {wxStyledTextCtrl, insertTextRaw, 2}},
+ {3414, {wxStyledTextCtrl, getCurLineRaw, 1}},
+ {3415, {wxStyledTextCtrl, getLineRaw, 1}},
+ {3416, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
+ {3417, {wxStyledTextCtrl, getTextRangeRaw, 2}},
+ {3418, {wxStyledTextCtrl, setTextRaw, 1}},
+ {3419, {wxStyledTextCtrl, getTextRaw, 0}},
+ {3420, {wxStyledTextCtrl, appendTextRaw, 1}},
+ {3421, {wxArtProvider, getBitmap, 2}},
+ {3422, {wxArtProvider, getIcon, 2}},
+ {3423, {wxTreeEvent, getKeyCode, 0}},
+ {3424, {wxTreeEvent, getItem, 0}},
+ {3425, {wxTreeEvent, getKeyEvent, 0}},
+ {3426, {wxTreeEvent, getLabel, 0}},
+ {3427, {wxTreeEvent, getOldItem, 0}},
+ {3428, {wxTreeEvent, getPoint, 0}},
+ {3429, {wxTreeEvent, isEditCancelled, 0}},
+ {3430, {wxTreeEvent, setToolTip, 1}},
+ {3431, {wxNotebookEvent, getOldSelection, 0}},
+ {3432, {wxNotebookEvent, getSelection, 0}},
+ {3433, {wxNotebookEvent, setOldSelection, 1}},
+ {3434, {wxNotebookEvent, setSelection, 1}},
+ {3435, {wxFileDataObject, new, 0}},
+ {3436, {wxFileDataObject, addFile, 1}},
+ {3437, {wxFileDataObject, getFilenames, 0}},
+ {3438, {wxFileDataObject, 'Destroy', undefined}},
+ {3439, {wxTextDataObject, new, 1}},
+ {3440, {wxTextDataObject, getTextLength, 0}},
+ {3441, {wxTextDataObject, getText, 0}},
+ {3442, {wxTextDataObject, setText, 1}},
+ {3443, {wxTextDataObject, 'Destroy', undefined}},
+ {3444, {wxBitmapDataObject, new_1_1, 1}},
+ {3445, {wxBitmapDataObject, new_1_0, 1}},
+ {3446, {wxBitmapDataObject, getBitmap, 0}},
+ {3447, {wxBitmapDataObject, setBitmap, 1}},
+ {3448, {wxBitmapDataObject, 'Destroy', undefined}},
+ {3450, {wxClipboard, new, 0}},
+ {3451, {wxClipboard, destruct, 0}},
+ {3452, {wxClipboard, addData, 1}},
+ {3453, {wxClipboard, clear, 0}},
+ {3454, {wxClipboard, close, 0}},
+ {3455, {wxClipboard, flush, 0}},
+ {3456, {wxClipboard, getData, 1}},
+ {3457, {wxClipboard, isOpened, 0}},
+ {3458, {wxClipboard, open, 0}},
+ {3459, {wxClipboard, setData, 1}},
+ {3461, {wxClipboard, usePrimarySelection, 1}},
+ {3462, {wxClipboard, isSupported, 1}},
+ {3463, {wxClipboard, get, 0}},
+ {3464, {wxSpinEvent, getPosition, 0}},
+ {3465, {wxSpinEvent, setPosition, 1}},
+ {3466, {wxSplitterWindow, new_0, 0}},
+ {3467, {wxSplitterWindow, new_2, 2}},
+ {3468, {wxSplitterWindow, destruct, 0}},
+ {3469, {wxSplitterWindow, create, 2}},
+ {3470, {wxSplitterWindow, getMinimumPaneSize, 0}},
+ {3471, {wxSplitterWindow, getSashGravity, 0}},
+ {3472, {wxSplitterWindow, getSashPosition, 0}},
+ {3473, {wxSplitterWindow, getSplitMode, 0}},
+ {3474, {wxSplitterWindow, getWindow1, 0}},
+ {3475, {wxSplitterWindow, getWindow2, 0}},
+ {3476, {wxSplitterWindow, initialize, 1}},
+ {3477, {wxSplitterWindow, isSplit, 0}},
+ {3478, {wxSplitterWindow, replaceWindow, 2}},
+ {3479, {wxSplitterWindow, setSashGravity, 1}},
+ {3480, {wxSplitterWindow, setSashPosition, 2}},
+ {3481, {wxSplitterWindow, setSashSize, 1}},
+ {3482, {wxSplitterWindow, setMinimumPaneSize, 1}},
+ {3483, {wxSplitterWindow, setSplitMode, 1}},
+ {3484, {wxSplitterWindow, splitHorizontally, 3}},
+ {3485, {wxSplitterWindow, splitVertically, 3}},
+ {3486, {wxSplitterWindow, unsplit, 1}},
+ {3487, {wxSplitterWindow, updateSize, 0}},
+ {3488, {wxSplitterEvent, getSashPosition, 0}},
+ {3489, {wxSplitterEvent, getX, 0}},
+ {3490, {wxSplitterEvent, getY, 0}},
+ {3491, {wxSplitterEvent, getWindowBeingRemoved, 0}},
+ {3492, {wxSplitterEvent, setSashPosition, 1}},
+ {3493, {wxHtmlWindow, new_0, 0}},
+ {3494, {wxHtmlWindow, new_2, 2}},
+ {3495, {wxHtmlWindow, appendToPage, 1}},
+ {3496, {wxHtmlWindow, getOpenedAnchor, 0}},
+ {3497, {wxHtmlWindow, getOpenedPage, 0}},
+ {3498, {wxHtmlWindow, getOpenedPageTitle, 0}},
+ {3499, {wxHtmlWindow, getRelatedFrame, 0}},
+ {3500, {wxHtmlWindow, historyBack, 0}},
+ {3501, {wxHtmlWindow, historyCanBack, 0}},
+ {3502, {wxHtmlWindow, historyCanForward, 0}},
+ {3503, {wxHtmlWindow, historyClear, 0}},
+ {3504, {wxHtmlWindow, historyForward, 0}},
+ {3505, {wxHtmlWindow, loadFile, 1}},
+ {3506, {wxHtmlWindow, loadPage, 1}},
+ {3507, {wxHtmlWindow, selectAll, 0}},
+ {3508, {wxHtmlWindow, selectionToText, 0}},
+ {3509, {wxHtmlWindow, selectLine, 1}},
+ {3510, {wxHtmlWindow, selectWord, 1}},
+ {3511, {wxHtmlWindow, setBorders, 1}},
+ {3512, {wxHtmlWindow, setFonts, 3}},
+ {3513, {wxHtmlWindow, setPage, 1}},
+ {3514, {wxHtmlWindow, setRelatedFrame, 2}},
+ {3515, {wxHtmlWindow, setRelatedStatusBar, 1}},
+ {3516, {wxHtmlWindow, toText, 0}},
+ {3517, {wxHtmlWindow, 'Destroy', undefined}},
+ {3518, {wxHtmlLinkEvent, getLinkInfo, 0}},
+ {3519, {wxSystemSettings, getColour, 1}},
+ {3520, {wxSystemSettings, getFont, 1}},
+ {3521, {wxSystemSettings, getMetric, 2}},
+ {3522, {wxSystemSettings, getScreenType, 0}},
+ {3523, {wxSystemOptions, getOption, 1}},
+ {3524, {wxSystemOptions, getOptionInt, 1}},
+ {3525, {wxSystemOptions, hasOption, 1}},
+ {3526, {wxSystemOptions, isFalse, 1}},
+ {3527, {wxSystemOptions, setOption_2_1, 2}},
+ {3528, {wxSystemOptions, setOption_2_0, 2}},
+ {3529, {wxAuiNotebookEvent, setSelection, 1}},
+ {3530, {wxAuiNotebookEvent, getSelection, 0}},
+ {3531, {wxAuiNotebookEvent, setOldSelection, 1}},
+ {3532, {wxAuiNotebookEvent, getOldSelection, 0}},
+ {3533, {wxAuiNotebookEvent, setDragSource, 1}},
+ {3534, {wxAuiNotebookEvent, getDragSource, 0}},
+ {3535, {wxAuiManagerEvent, setManager, 1}},
+ {3536, {wxAuiManagerEvent, getManager, 0}},
+ {3537, {wxAuiManagerEvent, setPane, 1}},
+ {3538, {wxAuiManagerEvent, getPane, 0}},
+ {3539, {wxAuiManagerEvent, setButton, 1}},
+ {3540, {wxAuiManagerEvent, getButton, 0}},
+ {3541, {wxAuiManagerEvent, setDC, 1}},
+ {3542, {wxAuiManagerEvent, getDC, 0}},
+ {3543, {wxAuiManagerEvent, veto, 1}},
+ {3544, {wxAuiManagerEvent, getVeto, 0}},
+ {3545, {wxAuiManagerEvent, setCanVeto, 1}},
+ {3546, {wxAuiManagerEvent, canVeto, 0}},
+ {3547, {wxLogNull, new, 0}},
+ {3548, {wxLogNull, 'Destroy', undefined}},
+ {3549, {wxTaskBarIcon, new, 0}},
+ {3550, {wxTaskBarIcon, destruct, 0}},
+ {3551, {wxTaskBarIcon, popupMenu, 1}},
+ {3552, {wxTaskBarIcon, removeIcon, 0}},
+ {3553, {wxTaskBarIcon, setIcon, 2}},
+ {3554, {wxLocale, new_0, 0}},
+ {3556, {wxLocale, new_2, 2}},
+ {3557, {wxLocale, destruct, 0}},
+ {3559, {wxLocale, init, 1}},
+ {3560, {wxLocale, addCatalog_1, 1}},
+ {3561, {wxLocale, addCatalog_3, 3}},
+ {3562, {wxLocale, addCatalogLookupPathPrefix, 1}},
+ {3563, {wxLocale, getCanonicalName, 0}},
+ {3564, {wxLocale, getLanguage, 0}},
+ {3565, {wxLocale, getLanguageName, 1}},
+ {3566, {wxLocale, getLocale, 0}},
+ {3567, {wxLocale, getName, 0}},
+ {3568, {wxLocale, getString_2, 2}},
+ {3569, {wxLocale, getString_4, 4}},
+ {3570, {wxLocale, getHeaderValue, 2}},
+ {3571, {wxLocale, getSysName, 0}},
+ {3572, {wxLocale, getSystemEncoding, 0}},
+ {3573, {wxLocale, getSystemEncodingName, 0}},
+ {3574, {wxLocale, getSystemLanguage, 0}},
+ {3575, {wxLocale, isLoaded, 1}},
+ {3576, {wxLocale, isOk, 0}},
+ {3577, {wxActivateEvent, getActive, 0}},
+ {3579, {wxPopupWindow, new_2, 2}},
+ {3580, {wxPopupWindow, new_0, 0}},
+ {3582, {wxPopupWindow, destruct, 0}},
+ {3583, {wxPopupWindow, create, 2}},
+ {3584, {wxPopupWindow, position, 2}},
+ {3585, {wxPopupTransientWindow, new_0, 0}},
+ {3586, {wxPopupTransientWindow, new_2, 2}},
+ {3587, {wxPopupTransientWindow, destruct, 0}},
+ {3588, {wxPopupTransientWindow, popup, 1}},
+ {3589, {wxPopupTransientWindow, dismiss, 0}},
+ {3590, {wxOverlay, new, 0}},
+ {3591, {wxOverlay, destruct, 0}},
+ {3592, {wxOverlay, reset, 0}},
+ {3593, {wxDCOverlay, new_6, 6}},
+ {3594, {wxDCOverlay, new_2, 2}},
+ {3595, {wxDCOverlay, destruct, 0}},
+ {3596, {wxDCOverlay, clear, 0}},
+ {3597, {wxDropFilesEvent, getPosition, 0}},
+ {3598, {wxDropFilesEvent, getNumberOfFiles, 0}},
+ {3599, {wxDropFilesEvent, getFiles, 0}},
{-1, {mod, func, -1}}
].
diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl
index 84fa592aaa..af0cee0dcd 100644
--- a/lib/wx/src/gen/wxe_funcs.hrl
+++ b/lib/wx/src/gen/wxe_funcs.hrl
@@ -42,3330 +42,3335 @@
-define(wxWindow_Destroy, 123).
-define(wxWindow_DestroyChildren, 124).
-define(wxWindow_Disable, 125).
--define(wxWindow_Enable, 126).
--define(wxWindow_FindFocus, 127).
--define(wxWindow_FindWindow_1_0, 128).
--define(wxWindow_FindWindow_1_1, 129).
--define(wxWindow_FindWindowById, 130).
--define(wxWindow_FindWindowByName, 131).
--define(wxWindow_FindWindowByLabel, 132).
--define(wxWindow_Fit, 133).
--define(wxWindow_FitInside, 134).
--define(wxWindow_Freeze, 135).
--define(wxWindow_GetAcceleratorTable, 136).
--define(wxWindow_GetBackgroundColour, 137).
--define(wxWindow_GetBackgroundStyle, 138).
--define(wxWindow_GetBestSize, 139).
--define(wxWindow_GetCaret, 141).
--define(wxWindow_GetCapture, 142).
--define(wxWindow_GetCharHeight, 143).
--define(wxWindow_GetCharWidth, 144).
--define(wxWindow_GetChildren, 145).
--define(wxWindow_GetClientSize, 148).
--define(wxWindow_GetContainingSizer, 149).
--define(wxWindow_GetCursor, 150).
--define(wxWindow_GetDropTarget, 151).
--define(wxWindow_GetEventHandler, 152).
--define(wxWindow_GetExtraStyle, 153).
--define(wxWindow_GetFont, 154).
--define(wxWindow_GetForegroundColour, 155).
--define(wxWindow_GetGrandParent, 156).
--define(wxWindow_GetHandle, 157).
--define(wxWindow_GetHelpText, 158).
--define(wxWindow_GetId, 159).
--define(wxWindow_GetLabel, 160).
--define(wxWindow_GetMaxSize, 161).
--define(wxWindow_GetMinSize, 162).
--define(wxWindow_GetName, 163).
--define(wxWindow_GetParent, 164).
--define(wxWindow_GetPosition, 166).
--define(wxWindow_GetRect, 167).
--define(wxWindow_GetScreenPosition, 169).
--define(wxWindow_GetScreenRect, 170).
--define(wxWindow_GetScrollPos, 171).
--define(wxWindow_GetScrollRange, 172).
--define(wxWindow_GetScrollThumb, 173).
--define(wxWindow_GetSize, 175).
--define(wxWindow_GetSizer, 176).
--define(wxWindow_GetTextExtent, 177).
--define(wxWindow_GetToolTip, 178).
--define(wxWindow_GetUpdateRegion, 179).
--define(wxWindow_GetVirtualSize, 181).
--define(wxWindow_GetWindowStyleFlag, 183).
--define(wxWindow_GetWindowVariant, 184).
--define(wxWindow_HasCapture, 185).
--define(wxWindow_HasScrollbar, 186).
--define(wxWindow_HasTransparentBackground, 187).
--define(wxWindow_Hide, 188).
--define(wxWindow_InheritAttributes, 189).
--define(wxWindow_InitDialog, 190).
--define(wxWindow_InvalidateBestSize, 191).
--define(wxWindow_IsEnabled, 192).
--define(wxWindow_IsExposed_2, 193).
--define(wxWindow_IsExposed_4, 194).
--define(wxWindow_IsExposed_1_0, 195).
--define(wxWindow_IsExposed_1_1, 196).
--define(wxWindow_IsRetained, 197).
--define(wxWindow_IsShown, 198).
--define(wxWindow_IsTopLevel, 199).
--define(wxWindow_Layout, 200).
--define(wxWindow_LineDown, 201).
--define(wxWindow_LineUp, 202).
--define(wxWindow_Lower, 203).
--define(wxWindow_MakeModal, 204).
--define(wxWindow_Move_3, 205).
--define(wxWindow_Move_2, 206).
--define(wxWindow_MoveAfterInTabOrder, 207).
--define(wxWindow_MoveBeforeInTabOrder, 208).
--define(wxWindow_Navigate, 209).
--define(wxWindow_PageDown, 210).
--define(wxWindow_PageUp, 211).
--define(wxWindow_PopEventHandler, 212).
--define(wxWindow_PopupMenu_2, 213).
--define(wxWindow_PopupMenu_3, 214).
--define(wxWindow_Raise, 215).
--define(wxWindow_Refresh, 216).
--define(wxWindow_RefreshRect, 217).
--define(wxWindow_ReleaseMouse, 218).
--define(wxWindow_RemoveChild, 219).
--define(wxWindow_Reparent, 220).
--define(wxWindow_ScreenToClient_2, 221).
--define(wxWindow_ScreenToClient_1, 222).
--define(wxWindow_ScrollLines, 224).
--define(wxWindow_ScrollPages, 226).
--define(wxWindow_ScrollWindow, 227).
--define(wxWindow_SetAcceleratorTable, 228).
--define(wxWindow_SetAutoLayout, 229).
--define(wxWindow_SetBackgroundColour, 230).
--define(wxWindow_SetBackgroundStyle, 231).
--define(wxWindow_SetCaret, 232).
--define(wxWindow_SetClientSize_2, 233).
--define(wxWindow_SetClientSize_1_0, 234).
--define(wxWindow_SetClientSize_1_1, 235).
--define(wxWindow_SetContainingSizer, 236).
--define(wxWindow_SetCursor, 237).
--define(wxWindow_SetMaxSize, 238).
--define(wxWindow_SetMinSize, 239).
--define(wxWindow_SetOwnBackgroundColour, 240).
--define(wxWindow_SetOwnFont, 241).
--define(wxWindow_SetOwnForegroundColour, 242).
--define(wxWindow_SetDropTarget, 243).
--define(wxWindow_SetExtraStyle, 244).
--define(wxWindow_SetFocus, 245).
--define(wxWindow_SetFocusFromKbd, 246).
--define(wxWindow_SetFont, 247).
--define(wxWindow_SetForegroundColour, 248).
--define(wxWindow_SetHelpText, 249).
--define(wxWindow_SetId, 250).
--define(wxWindow_SetLabel, 252).
--define(wxWindow_SetName, 253).
--define(wxWindow_SetPalette, 254).
--define(wxWindow_SetScrollbar, 255).
--define(wxWindow_SetScrollPos, 256).
--define(wxWindow_SetSize_5, 257).
--define(wxWindow_SetSize_2_0, 258).
--define(wxWindow_SetSize_1, 259).
--define(wxWindow_SetSize_2_1, 260).
--define(wxWindow_SetSizeHints_3, 261).
--define(wxWindow_SetSizeHints_2, 262).
--define(wxWindow_SetSizer, 263).
--define(wxWindow_SetSizerAndFit, 264).
--define(wxWindow_SetThemeEnabled, 265).
--define(wxWindow_SetToolTip_1_0, 266).
--define(wxWindow_SetToolTip_1_1, 267).
--define(wxWindow_SetVirtualSize_1, 268).
--define(wxWindow_SetVirtualSize_2, 269).
--define(wxWindow_SetVirtualSizeHints_3, 270).
--define(wxWindow_SetVirtualSizeHints_2, 271).
--define(wxWindow_SetWindowStyle, 272).
--define(wxWindow_SetWindowStyleFlag, 273).
--define(wxWindow_SetWindowVariant, 274).
--define(wxWindow_ShouldInheritColours, 275).
--define(wxWindow_Show, 276).
--define(wxWindow_Thaw, 277).
--define(wxWindow_TransferDataFromWindow, 278).
--define(wxWindow_TransferDataToWindow, 279).
--define(wxWindow_Update, 280).
--define(wxWindow_UpdateWindowUI, 281).
--define(wxWindow_Validate, 282).
--define(wxWindow_WarpPointer, 283).
--define(wxWindow_SetTransparent, 284).
--define(wxWindow_CanSetTransparent, 285).
--define(wxWindow_IsDoubleBuffered, 286).
--define(wxWindow_SetDoubleBuffered, 287).
--define(wxTopLevelWindow_GetIcon, 288).
--define(wxTopLevelWindow_GetIcons, 289).
--define(wxTopLevelWindow_GetTitle, 290).
--define(wxTopLevelWindow_IsActive, 291).
--define(wxTopLevelWindow_Iconize, 292).
--define(wxTopLevelWindow_IsFullScreen, 293).
--define(wxTopLevelWindow_IsIconized, 294).
--define(wxTopLevelWindow_IsMaximized, 295).
--define(wxTopLevelWindow_Maximize, 296).
--define(wxTopLevelWindow_RequestUserAttention, 297).
--define(wxTopLevelWindow_SetIcon, 298).
--define(wxTopLevelWindow_SetIcons, 299).
--define(wxTopLevelWindow_CenterOnScreen, 300).
--define(wxTopLevelWindow_CentreOnScreen, 301).
--define(wxTopLevelWindow_SetShape, 303).
--define(wxTopLevelWindow_SetTitle, 304).
--define(wxTopLevelWindow_ShowFullScreen, 305).
--define(wxFrame_new_4, 307).
--define(wxFrame_new_0, 308).
--define(wxFrame_destruct, 310).
--define(wxFrame_Create, 311).
--define(wxFrame_CreateStatusBar, 312).
--define(wxFrame_CreateToolBar, 313).
--define(wxFrame_GetClientAreaOrigin, 314).
--define(wxFrame_GetMenuBar, 315).
--define(wxFrame_GetStatusBar, 316).
--define(wxFrame_GetStatusBarPane, 317).
--define(wxFrame_GetToolBar, 318).
--define(wxFrame_ProcessCommand, 319).
--define(wxFrame_SendSizeEvent, 320).
--define(wxFrame_SetMenuBar, 321).
--define(wxFrame_SetStatusBar, 322).
--define(wxFrame_SetStatusBarPane, 323).
--define(wxFrame_SetStatusText, 324).
--define(wxFrame_SetStatusWidths, 325).
--define(wxFrame_SetToolBar, 326).
--define(wxMiniFrame_new_0, 327).
--define(wxMiniFrame_new_4, 328).
--define(wxMiniFrame_Create, 329).
--define(wxMiniFrame_destroy, 330).
--define(wxSplashScreen_new_0, 331).
--define(wxSplashScreen_new_6, 332).
--define(wxSplashScreen_destruct, 333).
--define(wxSplashScreen_GetSplashStyle, 334).
--define(wxSplashScreen_GetTimeout, 335).
--define(wxPanel_new_0, 336).
--define(wxPanel_new_6, 337).
--define(wxPanel_new_2, 338).
--define(wxPanel_destruct, 339).
--define(wxPanel_InitDialog, 340).
--define(wxPanel_SetFocusIgnoringChildren, 341).
--define(wxScrolledWindow_new_0, 342).
--define(wxScrolledWindow_new_2, 343).
--define(wxScrolledWindow_destruct, 344).
--define(wxScrolledWindow_CalcScrolledPosition_4, 345).
--define(wxScrolledWindow_CalcScrolledPosition_1, 346).
--define(wxScrolledWindow_CalcUnscrolledPosition_4, 347).
--define(wxScrolledWindow_CalcUnscrolledPosition_1, 348).
--define(wxScrolledWindow_EnableScrolling, 349).
--define(wxScrolledWindow_GetScrollPixelsPerUnit, 350).
--define(wxScrolledWindow_GetViewStart, 351).
--define(wxScrolledWindow_DoPrepareDC, 352).
--define(wxScrolledWindow_PrepareDC, 353).
--define(wxScrolledWindow_Scroll, 354).
--define(wxScrolledWindow_SetScrollbars, 355).
--define(wxScrolledWindow_SetScrollRate, 356).
--define(wxScrolledWindow_SetTargetWindow, 357).
--define(wxSashWindow_new_0, 358).
--define(wxSashWindow_new_2, 359).
--define(wxSashWindow_destruct, 360).
--define(wxSashWindow_GetSashVisible, 361).
--define(wxSashWindow_GetMaximumSizeX, 362).
--define(wxSashWindow_GetMaximumSizeY, 363).
--define(wxSashWindow_GetMinimumSizeX, 364).
--define(wxSashWindow_GetMinimumSizeY, 365).
--define(wxSashWindow_SetMaximumSizeX, 366).
--define(wxSashWindow_SetMaximumSizeY, 367).
--define(wxSashWindow_SetMinimumSizeX, 368).
--define(wxSashWindow_SetMinimumSizeY, 369).
--define(wxSashWindow_SetSashVisible, 370).
--define(wxSashLayoutWindow_new_0, 371).
--define(wxSashLayoutWindow_new_2, 372).
--define(wxSashLayoutWindow_Create, 373).
--define(wxSashLayoutWindow_GetAlignment, 374).
--define(wxSashLayoutWindow_GetOrientation, 375).
--define(wxSashLayoutWindow_SetAlignment, 376).
--define(wxSashLayoutWindow_SetDefaultSize, 377).
--define(wxSashLayoutWindow_SetOrientation, 378).
--define(wxSashLayoutWindow_destroy, 379).
--define(wxGrid_new_0, 380).
--define(wxGrid_new_3, 381).
--define(wxGrid_new_4, 382).
--define(wxGrid_destruct, 383).
--define(wxGrid_AppendCols, 384).
--define(wxGrid_AppendRows, 385).
--define(wxGrid_AutoSize, 386).
--define(wxGrid_AutoSizeColumn, 387).
--define(wxGrid_AutoSizeColumns, 388).
--define(wxGrid_AutoSizeRow, 389).
--define(wxGrid_AutoSizeRows, 390).
--define(wxGrid_BeginBatch, 391).
--define(wxGrid_BlockToDeviceRect, 392).
--define(wxGrid_CanDragColSize, 393).
--define(wxGrid_CanDragRowSize, 394).
--define(wxGrid_CanDragGridSize, 395).
--define(wxGrid_CanEnableCellControl, 396).
--define(wxGrid_CellToRect_2, 397).
--define(wxGrid_CellToRect_1, 398).
--define(wxGrid_ClearGrid, 399).
--define(wxGrid_ClearSelection, 400).
--define(wxGrid_CreateGrid, 401).
--define(wxGrid_DeleteCols, 402).
--define(wxGrid_DeleteRows, 403).
--define(wxGrid_DisableCellEditControl, 404).
--define(wxGrid_DisableDragColSize, 405).
--define(wxGrid_DisableDragGridSize, 406).
--define(wxGrid_DisableDragRowSize, 407).
--define(wxGrid_EnableCellEditControl, 408).
--define(wxGrid_EnableDragColSize, 409).
--define(wxGrid_EnableDragGridSize, 410).
--define(wxGrid_EnableDragRowSize, 411).
--define(wxGrid_EnableEditing, 412).
--define(wxGrid_EnableGridLines, 413).
--define(wxGrid_EndBatch, 414).
--define(wxGrid_Fit, 415).
--define(wxGrid_ForceRefresh, 416).
--define(wxGrid_GetBatchCount, 417).
--define(wxGrid_GetCellAlignment, 418).
--define(wxGrid_GetCellBackgroundColour, 419).
--define(wxGrid_GetCellEditor, 420).
--define(wxGrid_GetCellFont, 421).
--define(wxGrid_GetCellRenderer, 422).
--define(wxGrid_GetCellTextColour, 423).
--define(wxGrid_GetCellValue_2, 424).
--define(wxGrid_GetCellValue_1, 425).
--define(wxGrid_GetColLabelAlignment, 426).
--define(wxGrid_GetColLabelSize, 427).
--define(wxGrid_GetColLabelValue, 428).
--define(wxGrid_GetColMinimalAcceptableWidth, 429).
--define(wxGrid_GetDefaultCellAlignment, 430).
--define(wxGrid_GetDefaultCellBackgroundColour, 431).
--define(wxGrid_GetDefaultCellFont, 432).
--define(wxGrid_GetDefaultCellTextColour, 433).
--define(wxGrid_GetDefaultColLabelSize, 434).
--define(wxGrid_GetDefaultColSize, 435).
--define(wxGrid_GetDefaultEditor, 436).
--define(wxGrid_GetDefaultEditorForCell_2, 437).
--define(wxGrid_GetDefaultEditorForCell_1, 438).
--define(wxGrid_GetDefaultEditorForType, 439).
--define(wxGrid_GetDefaultRenderer, 440).
--define(wxGrid_GetDefaultRendererForCell, 441).
--define(wxGrid_GetDefaultRendererForType, 442).
--define(wxGrid_GetDefaultRowLabelSize, 443).
--define(wxGrid_GetDefaultRowSize, 444).
--define(wxGrid_GetGridCursorCol, 445).
--define(wxGrid_GetGridCursorRow, 446).
--define(wxGrid_GetGridLineColour, 447).
--define(wxGrid_GridLinesEnabled, 448).
--define(wxGrid_GetLabelBackgroundColour, 449).
--define(wxGrid_GetLabelFont, 450).
--define(wxGrid_GetLabelTextColour, 451).
--define(wxGrid_GetNumberCols, 452).
--define(wxGrid_GetNumberRows, 453).
--define(wxGrid_GetOrCreateCellAttr, 454).
--define(wxGrid_GetRowMinimalAcceptableHeight, 455).
--define(wxGrid_GetRowLabelAlignment, 456).
--define(wxGrid_GetRowLabelSize, 457).
--define(wxGrid_GetRowLabelValue, 458).
--define(wxGrid_GetRowSize, 459).
--define(wxGrid_GetScrollLineX, 460).
--define(wxGrid_GetScrollLineY, 461).
--define(wxGrid_GetSelectedCells, 462).
--define(wxGrid_GetSelectedCols, 463).
--define(wxGrid_GetSelectedRows, 464).
--define(wxGrid_GetSelectionBackground, 465).
--define(wxGrid_GetSelectionBlockTopLeft, 466).
--define(wxGrid_GetSelectionBlockBottomRight, 467).
--define(wxGrid_GetSelectionForeground, 468).
--define(wxGrid_GetViewWidth, 469).
--define(wxGrid_GetGridWindow, 470).
--define(wxGrid_GetGridRowLabelWindow, 471).
--define(wxGrid_GetGridColLabelWindow, 472).
--define(wxGrid_GetGridCornerLabelWindow, 473).
--define(wxGrid_HideCellEditControl, 474).
--define(wxGrid_InsertCols, 475).
--define(wxGrid_InsertRows, 476).
--define(wxGrid_IsCellEditControlEnabled, 477).
--define(wxGrid_IsCurrentCellReadOnly, 478).
--define(wxGrid_IsEditable, 479).
--define(wxGrid_IsInSelection_2, 480).
--define(wxGrid_IsInSelection_1, 481).
--define(wxGrid_IsReadOnly, 482).
--define(wxGrid_IsSelection, 483).
--define(wxGrid_IsVisible_3, 484).
--define(wxGrid_IsVisible_2, 485).
--define(wxGrid_MakeCellVisible_2, 486).
--define(wxGrid_MakeCellVisible_1, 487).
--define(wxGrid_MoveCursorDown, 488).
--define(wxGrid_MoveCursorLeft, 489).
--define(wxGrid_MoveCursorRight, 490).
--define(wxGrid_MoveCursorUp, 491).
--define(wxGrid_MoveCursorDownBlock, 492).
--define(wxGrid_MoveCursorLeftBlock, 493).
--define(wxGrid_MoveCursorRightBlock, 494).
--define(wxGrid_MoveCursorUpBlock, 495).
--define(wxGrid_MovePageDown, 496).
--define(wxGrid_MovePageUp, 497).
--define(wxGrid_RegisterDataType, 498).
--define(wxGrid_SaveEditControlValue, 499).
--define(wxGrid_SelectAll, 500).
--define(wxGrid_SelectBlock_5, 501).
--define(wxGrid_SelectBlock_3, 502).
--define(wxGrid_SelectCol, 503).
--define(wxGrid_SelectRow, 504).
--define(wxGrid_SetCellAlignment_4, 505).
--define(wxGrid_SetCellAlignment_3, 506).
--define(wxGrid_SetCellAlignment_1, 507).
--define(wxGrid_SetCellBackgroundColour_3_0, 508).
--define(wxGrid_SetCellBackgroundColour_1, 509).
--define(wxGrid_SetCellBackgroundColour_3_1, 510).
--define(wxGrid_SetCellEditor, 511).
--define(wxGrid_SetCellFont, 512).
--define(wxGrid_SetCellRenderer, 513).
--define(wxGrid_SetCellTextColour_3_0, 514).
--define(wxGrid_SetCellTextColour_3_1, 515).
--define(wxGrid_SetCellTextColour_1, 516).
--define(wxGrid_SetCellValue_3_0, 517).
--define(wxGrid_SetCellValue_2, 518).
--define(wxGrid_SetCellValue_3_1, 519).
--define(wxGrid_SetColAttr, 520).
--define(wxGrid_SetColFormatBool, 521).
--define(wxGrid_SetColFormatNumber, 522).
--define(wxGrid_SetColFormatFloat, 523).
--define(wxGrid_SetColFormatCustom, 524).
--define(wxGrid_SetColLabelAlignment, 525).
--define(wxGrid_SetColLabelSize, 526).
--define(wxGrid_SetColLabelValue, 527).
--define(wxGrid_SetColMinimalWidth, 528).
--define(wxGrid_SetColMinimalAcceptableWidth, 529).
--define(wxGrid_SetColSize, 530).
--define(wxGrid_SetDefaultCellAlignment, 531).
--define(wxGrid_SetDefaultCellBackgroundColour, 532).
--define(wxGrid_SetDefaultCellFont, 533).
--define(wxGrid_SetDefaultCellTextColour, 534).
--define(wxGrid_SetDefaultEditor, 535).
--define(wxGrid_SetDefaultRenderer, 536).
--define(wxGrid_SetDefaultColSize, 537).
--define(wxGrid_SetDefaultRowSize, 538).
--define(wxGrid_SetGridCursor, 539).
--define(wxGrid_SetGridLineColour, 540).
--define(wxGrid_SetLabelBackgroundColour, 541).
--define(wxGrid_SetLabelFont, 542).
--define(wxGrid_SetLabelTextColour, 543).
--define(wxGrid_SetMargins, 544).
--define(wxGrid_SetReadOnly, 545).
--define(wxGrid_SetRowAttr, 546).
--define(wxGrid_SetRowLabelAlignment, 547).
--define(wxGrid_SetRowLabelSize, 548).
--define(wxGrid_SetRowLabelValue, 549).
--define(wxGrid_SetRowMinimalHeight, 550).
--define(wxGrid_SetRowMinimalAcceptableHeight, 551).
--define(wxGrid_SetRowSize, 552).
--define(wxGrid_SetScrollLineX, 553).
--define(wxGrid_SetScrollLineY, 554).
--define(wxGrid_SetSelectionBackground, 555).
--define(wxGrid_SetSelectionForeground, 556).
--define(wxGrid_SetSelectionMode, 557).
--define(wxGrid_ShowCellEditControl, 558).
--define(wxGrid_XToCol, 559).
--define(wxGrid_XToEdgeOfCol, 560).
--define(wxGrid_YToEdgeOfRow, 561).
--define(wxGrid_YToRow, 562).
--define(wxGridCellRenderer_Draw, 563).
--define(wxGridCellRenderer_GetBestSize, 564).
--define(wxGridCellEditor_Create, 565).
--define(wxGridCellEditor_IsCreated, 566).
--define(wxGridCellEditor_SetSize, 567).
--define(wxGridCellEditor_Show, 568).
--define(wxGridCellEditor_PaintBackground, 569).
--define(wxGridCellEditor_BeginEdit, 570).
--define(wxGridCellEditor_EndEdit, 571).
--define(wxGridCellEditor_Reset, 572).
--define(wxGridCellEditor_StartingKey, 573).
--define(wxGridCellEditor_StartingClick, 574).
--define(wxGridCellEditor_HandleReturn, 575).
--define(wxGridCellBoolRenderer_new, 576).
--define(wxGridCellBoolRenderer_destroy, 577).
--define(wxGridCellBoolEditor_new, 578).
--define(wxGridCellBoolEditor_IsTrueValue, 579).
--define(wxGridCellBoolEditor_UseStringValues, 580).
--define(wxGridCellBoolEditor_destroy, 581).
--define(wxGridCellFloatRenderer_new, 582).
--define(wxGridCellFloatRenderer_GetPrecision, 583).
--define(wxGridCellFloatRenderer_GetWidth, 584).
--define(wxGridCellFloatRenderer_SetParameters, 585).
--define(wxGridCellFloatRenderer_SetPrecision, 586).
--define(wxGridCellFloatRenderer_SetWidth, 587).
--define(wxGridCellFloatRenderer_destroy, 588).
--define(wxGridCellFloatEditor_new, 589).
--define(wxGridCellFloatEditor_SetParameters, 590).
--define(wxGridCellFloatEditor_destroy, 591).
--define(wxGridCellStringRenderer_new, 592).
--define(wxGridCellStringRenderer_destroy, 593).
--define(wxGridCellTextEditor_new, 594).
--define(wxGridCellTextEditor_SetParameters, 595).
--define(wxGridCellTextEditor_destroy, 596).
--define(wxGridCellChoiceEditor_new, 598).
--define(wxGridCellChoiceEditor_SetParameters, 599).
--define(wxGridCellChoiceEditor_destroy, 600).
--define(wxGridCellNumberRenderer_new, 601).
--define(wxGridCellNumberRenderer_destroy, 602).
--define(wxGridCellNumberEditor_new, 603).
--define(wxGridCellNumberEditor_GetValue, 604).
--define(wxGridCellNumberEditor_SetParameters, 605).
--define(wxGridCellNumberEditor_destroy, 606).
--define(wxGridCellAttr_SetTextColour, 607).
--define(wxGridCellAttr_SetBackgroundColour, 608).
--define(wxGridCellAttr_SetFont, 609).
--define(wxGridCellAttr_SetAlignment, 610).
--define(wxGridCellAttr_SetReadOnly, 611).
--define(wxGridCellAttr_SetRenderer, 612).
--define(wxGridCellAttr_SetEditor, 613).
--define(wxGridCellAttr_HasTextColour, 614).
--define(wxGridCellAttr_HasBackgroundColour, 615).
--define(wxGridCellAttr_HasFont, 616).
--define(wxGridCellAttr_HasAlignment, 617).
--define(wxGridCellAttr_HasRenderer, 618).
--define(wxGridCellAttr_HasEditor, 619).
--define(wxGridCellAttr_GetTextColour, 620).
--define(wxGridCellAttr_GetBackgroundColour, 621).
--define(wxGridCellAttr_GetFont, 622).
--define(wxGridCellAttr_GetAlignment, 623).
--define(wxGridCellAttr_GetRenderer, 624).
--define(wxGridCellAttr_GetEditor, 625).
--define(wxGridCellAttr_IsReadOnly, 626).
--define(wxGridCellAttr_SetDefAttr, 627).
--define(wxDC_Blit, 628).
--define(wxDC_CalcBoundingBox, 629).
--define(wxDC_Clear, 630).
--define(wxDC_ComputeScaleAndOrigin, 631).
--define(wxDC_CrossHair, 632).
--define(wxDC_DestroyClippingRegion, 633).
--define(wxDC_DeviceToLogicalX, 634).
--define(wxDC_DeviceToLogicalXRel, 635).
--define(wxDC_DeviceToLogicalY, 636).
--define(wxDC_DeviceToLogicalYRel, 637).
--define(wxDC_DrawArc, 638).
--define(wxDC_DrawBitmap, 639).
--define(wxDC_DrawCheckMark, 640).
--define(wxDC_DrawCircle, 641).
--define(wxDC_DrawEllipse_2, 643).
--define(wxDC_DrawEllipse_1, 644).
--define(wxDC_DrawEllipticArc, 645).
--define(wxDC_DrawIcon, 646).
--define(wxDC_DrawLabel, 647).
--define(wxDC_DrawLine, 648).
--define(wxDC_DrawLines, 649).
--define(wxDC_DrawPolygon, 651).
--define(wxDC_DrawPoint, 653).
--define(wxDC_DrawRectangle_2, 655).
--define(wxDC_DrawRectangle_1, 656).
--define(wxDC_DrawRotatedText, 657).
--define(wxDC_DrawRoundedRectangle_3, 659).
--define(wxDC_DrawRoundedRectangle_2, 660).
--define(wxDC_DrawText, 661).
--define(wxDC_EndDoc, 662).
--define(wxDC_EndPage, 663).
--define(wxDC_FloodFill, 664).
--define(wxDC_GetBackground, 665).
--define(wxDC_GetBackgroundMode, 666).
--define(wxDC_GetBrush, 667).
--define(wxDC_GetCharHeight, 668).
--define(wxDC_GetCharWidth, 669).
--define(wxDC_GetClippingBox, 670).
--define(wxDC_GetFont, 672).
--define(wxDC_GetLayoutDirection, 673).
--define(wxDC_GetLogicalFunction, 674).
--define(wxDC_GetMapMode, 675).
--define(wxDC_GetMultiLineTextExtent_4, 676).
--define(wxDC_GetMultiLineTextExtent_1, 677).
--define(wxDC_GetPartialTextExtents, 678).
--define(wxDC_GetPen, 679).
--define(wxDC_GetPixel, 680).
--define(wxDC_GetPPI, 681).
--define(wxDC_GetSize, 683).
--define(wxDC_GetSizeMM, 685).
--define(wxDC_GetTextBackground, 686).
--define(wxDC_GetTextExtent_4, 687).
--define(wxDC_GetTextExtent_1, 688).
--define(wxDC_GetTextForeground, 690).
--define(wxDC_GetUserScale, 691).
--define(wxDC_GradientFillConcentric_3, 692).
--define(wxDC_GradientFillConcentric_4, 693).
--define(wxDC_GradientFillLinear, 694).
--define(wxDC_LogicalToDeviceX, 695).
--define(wxDC_LogicalToDeviceXRel, 696).
--define(wxDC_LogicalToDeviceY, 697).
--define(wxDC_LogicalToDeviceYRel, 698).
--define(wxDC_MaxX, 699).
--define(wxDC_MaxY, 700).
--define(wxDC_MinX, 701).
--define(wxDC_MinY, 702).
--define(wxDC_IsOk, 703).
--define(wxDC_ResetBoundingBox, 704).
--define(wxDC_SetAxisOrientation, 705).
--define(wxDC_SetBackground, 706).
--define(wxDC_SetBackgroundMode, 707).
--define(wxDC_SetBrush, 708).
--define(wxDC_SetClippingRegion_2, 710).
--define(wxDC_SetClippingRegion_1_1, 711).
--define(wxDC_SetClippingRegion_1_0, 712).
--define(wxDC_SetDeviceOrigin, 713).
--define(wxDC_SetFont, 714).
--define(wxDC_SetLayoutDirection, 715).
--define(wxDC_SetLogicalFunction, 716).
--define(wxDC_SetMapMode, 717).
--define(wxDC_SetPalette, 718).
--define(wxDC_SetPen, 719).
--define(wxDC_SetTextBackground, 720).
--define(wxDC_SetTextForeground, 721).
--define(wxDC_SetUserScale, 722).
--define(wxDC_StartDoc, 723).
--define(wxDC_StartPage, 724).
--define(wxMirrorDC_new, 725).
--define(wxMirrorDC_destroy, 726).
--define(wxScreenDC_new, 727).
--define(wxScreenDC_destruct, 728).
--define(wxPostScriptDC_new_0, 729).
--define(wxPostScriptDC_new_1, 730).
--define(wxPostScriptDC_destruct, 731).
--define(wxPostScriptDC_SetResolution, 732).
--define(wxPostScriptDC_GetResolution, 733).
--define(wxWindowDC_new_0, 734).
--define(wxWindowDC_new_1, 735).
--define(wxWindowDC_destruct, 736).
--define(wxClientDC_new_0, 737).
--define(wxClientDC_new_1, 738).
--define(wxClientDC_destroy, 739).
--define(wxPaintDC_new_0, 740).
--define(wxPaintDC_new_1, 741).
--define(wxPaintDC_destroy, 742).
--define(wxMemoryDC_new_1_0, 744).
--define(wxMemoryDC_new_1_1, 745).
--define(wxMemoryDC_new_0, 746).
--define(wxMemoryDC_destruct, 748).
--define(wxMemoryDC_SelectObject, 749).
--define(wxMemoryDC_SelectObjectAsSource, 750).
--define(wxBufferedDC_new_0, 751).
--define(wxBufferedDC_new_2, 752).
--define(wxBufferedDC_new_3, 753).
--define(wxBufferedDC_destruct, 754).
--define(wxBufferedDC_Init_2, 755).
--define(wxBufferedDC_Init_3, 756).
--define(wxBufferedPaintDC_new_3, 757).
--define(wxBufferedPaintDC_new_2, 758).
--define(wxBufferedPaintDC_destruct, 759).
--define(wxGraphicsObject_destruct, 760).
--define(wxGraphicsObject_GetRenderer, 761).
--define(wxGraphicsObject_IsNull, 762).
--define(wxGraphicsContext_destruct, 763).
--define(wxGraphicsContext_Create_1_1, 764).
--define(wxGraphicsContext_Create_1_0, 765).
--define(wxGraphicsContext_Create_0, 766).
--define(wxGraphicsContext_CreatePen, 767).
--define(wxGraphicsContext_CreateBrush, 768).
--define(wxGraphicsContext_CreateRadialGradientBrush, 769).
--define(wxGraphicsContext_CreateLinearGradientBrush, 770).
--define(wxGraphicsContext_CreateFont, 771).
--define(wxGraphicsContext_CreateMatrix, 772).
--define(wxGraphicsContext_CreatePath, 773).
--define(wxGraphicsContext_Clip_1, 774).
--define(wxGraphicsContext_Clip_4, 775).
--define(wxGraphicsContext_ResetClip, 776).
--define(wxGraphicsContext_DrawBitmap, 777).
--define(wxGraphicsContext_DrawEllipse, 778).
--define(wxGraphicsContext_DrawIcon, 779).
--define(wxGraphicsContext_DrawLines, 780).
--define(wxGraphicsContext_DrawPath, 781).
--define(wxGraphicsContext_DrawRectangle, 782).
--define(wxGraphicsContext_DrawRoundedRectangle, 783).
--define(wxGraphicsContext_DrawText_3, 784).
--define(wxGraphicsContext_DrawText_4_0, 785).
--define(wxGraphicsContext_DrawText_4_1, 786).
--define(wxGraphicsContext_DrawText_5, 787).
--define(wxGraphicsContext_FillPath, 788).
--define(wxGraphicsContext_StrokePath, 789).
--define(wxGraphicsContext_GetPartialTextExtents, 790).
--define(wxGraphicsContext_GetTextExtent, 791).
--define(wxGraphicsContext_Rotate, 792).
--define(wxGraphicsContext_Scale, 793).
--define(wxGraphicsContext_Translate, 794).
--define(wxGraphicsContext_GetTransform, 795).
--define(wxGraphicsContext_SetTransform, 796).
--define(wxGraphicsContext_ConcatTransform, 797).
--define(wxGraphicsContext_SetBrush_1_1, 798).
--define(wxGraphicsContext_SetBrush_1_0, 799).
--define(wxGraphicsContext_SetFont_1, 800).
--define(wxGraphicsContext_SetFont_2, 801).
--define(wxGraphicsContext_SetPen_1_0, 802).
--define(wxGraphicsContext_SetPen_1_1, 803).
--define(wxGraphicsContext_StrokeLine, 804).
--define(wxGraphicsContext_StrokeLines, 805).
--define(wxGraphicsMatrix_Concat, 807).
--define(wxGraphicsMatrix_Get, 809).
--define(wxGraphicsMatrix_Invert, 810).
--define(wxGraphicsMatrix_IsEqual, 811).
--define(wxGraphicsMatrix_IsIdentity, 813).
--define(wxGraphicsMatrix_Rotate, 814).
--define(wxGraphicsMatrix_Scale, 815).
--define(wxGraphicsMatrix_Translate, 816).
--define(wxGraphicsMatrix_Set, 817).
--define(wxGraphicsMatrix_TransformPoint, 818).
--define(wxGraphicsMatrix_TransformDistance, 819).
--define(wxGraphicsPath_MoveToPoint_2, 820).
--define(wxGraphicsPath_MoveToPoint_1, 821).
--define(wxGraphicsPath_AddArc_6, 822).
--define(wxGraphicsPath_AddArc_5, 823).
--define(wxGraphicsPath_AddArcToPoint, 824).
--define(wxGraphicsPath_AddCircle, 825).
--define(wxGraphicsPath_AddCurveToPoint_6, 826).
--define(wxGraphicsPath_AddCurveToPoint_3, 827).
--define(wxGraphicsPath_AddEllipse, 828).
--define(wxGraphicsPath_AddLineToPoint_2, 829).
--define(wxGraphicsPath_AddLineToPoint_1, 830).
--define(wxGraphicsPath_AddPath, 831).
--define(wxGraphicsPath_AddQuadCurveToPoint, 832).
--define(wxGraphicsPath_AddRectangle, 833).
--define(wxGraphicsPath_AddRoundedRectangle, 834).
--define(wxGraphicsPath_CloseSubpath, 835).
--define(wxGraphicsPath_Contains_3, 836).
--define(wxGraphicsPath_Contains_2, 837).
--define(wxGraphicsPath_GetBox, 839).
--define(wxGraphicsPath_GetCurrentPoint, 841).
--define(wxGraphicsPath_Transform, 842).
--define(wxGraphicsRenderer_GetDefaultRenderer, 843).
--define(wxGraphicsRenderer_CreateContext_1_1, 844).
--define(wxGraphicsRenderer_CreateContext_1_0, 845).
--define(wxGraphicsRenderer_CreatePen, 846).
--define(wxGraphicsRenderer_CreateBrush, 847).
--define(wxGraphicsRenderer_CreateLinearGradientBrush, 848).
--define(wxGraphicsRenderer_CreateRadialGradientBrush, 849).
--define(wxGraphicsRenderer_CreateFont, 850).
--define(wxGraphicsRenderer_CreateMatrix, 851).
--define(wxGraphicsRenderer_CreatePath, 852).
--define(wxMenuBar_new_1, 854).
--define(wxMenuBar_new_0, 856).
--define(wxMenuBar_destruct, 858).
--define(wxMenuBar_Append, 859).
--define(wxMenuBar_Check, 860).
--define(wxMenuBar_Enable_2, 861).
--define(wxMenuBar_Enable_1, 862).
--define(wxMenuBar_EnableTop, 863).
--define(wxMenuBar_FindMenu, 864).
--define(wxMenuBar_FindMenuItem, 865).
--define(wxMenuBar_FindItem, 866).
--define(wxMenuBar_GetHelpString, 867).
--define(wxMenuBar_GetLabel_1, 868).
--define(wxMenuBar_GetLabel_0, 869).
--define(wxMenuBar_GetLabelTop, 870).
--define(wxMenuBar_GetMenu, 871).
--define(wxMenuBar_GetMenuCount, 872).
--define(wxMenuBar_Insert, 873).
--define(wxMenuBar_IsChecked, 874).
--define(wxMenuBar_IsEnabled_1, 875).
--define(wxMenuBar_IsEnabled_0, 876).
--define(wxMenuBar_Remove, 877).
--define(wxMenuBar_Replace, 878).
--define(wxMenuBar_SetHelpString, 879).
--define(wxMenuBar_SetLabel_2, 880).
--define(wxMenuBar_SetLabel_1, 881).
--define(wxMenuBar_SetLabelTop, 882).
--define(wxControl_GetLabel, 883).
--define(wxControl_SetLabel, 884).
--define(wxControlWithItems_Append_1, 885).
--define(wxControlWithItems_Append_2, 886).
--define(wxControlWithItems_appendStrings_1, 887).
--define(wxControlWithItems_Clear, 888).
--define(wxControlWithItems_Delete, 889).
--define(wxControlWithItems_FindString, 890).
--define(wxControlWithItems_getClientData, 891).
--define(wxControlWithItems_setClientData, 892).
--define(wxControlWithItems_GetCount, 893).
--define(wxControlWithItems_GetSelection, 894).
--define(wxControlWithItems_GetString, 895).
--define(wxControlWithItems_GetStringSelection, 896).
--define(wxControlWithItems_Insert_2, 897).
--define(wxControlWithItems_Insert_3, 898).
--define(wxControlWithItems_IsEmpty, 899).
--define(wxControlWithItems_Select, 900).
--define(wxControlWithItems_SetSelection, 901).
--define(wxControlWithItems_SetString, 902).
--define(wxControlWithItems_SetStringSelection, 903).
--define(wxMenu_new_2, 906).
--define(wxMenu_new_1, 907).
--define(wxMenu_destruct, 909).
--define(wxMenu_Append_3, 910).
--define(wxMenu_Append_1, 911).
--define(wxMenu_Append_4_0, 912).
--define(wxMenu_Append_4_1, 913).
--define(wxMenu_AppendCheckItem, 914).
--define(wxMenu_AppendRadioItem, 915).
--define(wxMenu_AppendSeparator, 916).
--define(wxMenu_Break, 917).
--define(wxMenu_Check, 918).
--define(wxMenu_Delete_1_0, 919).
--define(wxMenu_Delete_1_1, 920).
--define(wxMenu_Destroy_1_0, 921).
--define(wxMenu_Destroy_1_1, 922).
--define(wxMenu_Enable, 923).
--define(wxMenu_FindItem_1, 924).
--define(wxMenu_FindItem_2, 925).
--define(wxMenu_FindItemByPosition, 926).
--define(wxMenu_GetHelpString, 927).
--define(wxMenu_GetLabel, 928).
--define(wxMenu_GetMenuItemCount, 929).
--define(wxMenu_GetMenuItems, 930).
--define(wxMenu_GetTitle, 932).
--define(wxMenu_Insert_2, 933).
--define(wxMenu_Insert_3, 934).
--define(wxMenu_Insert_5_1, 935).
--define(wxMenu_Insert_5_0, 936).
--define(wxMenu_InsertCheckItem, 937).
--define(wxMenu_InsertRadioItem, 938).
--define(wxMenu_InsertSeparator, 939).
--define(wxMenu_IsChecked, 940).
--define(wxMenu_IsEnabled, 941).
--define(wxMenu_Prepend_1, 942).
--define(wxMenu_Prepend_2, 943).
--define(wxMenu_Prepend_4_1, 944).
--define(wxMenu_Prepend_4_0, 945).
--define(wxMenu_PrependCheckItem, 946).
--define(wxMenu_PrependRadioItem, 947).
--define(wxMenu_PrependSeparator, 948).
--define(wxMenu_Remove_1_0, 949).
--define(wxMenu_Remove_1_1, 950).
--define(wxMenu_SetHelpString, 951).
--define(wxMenu_SetLabel, 952).
--define(wxMenu_SetTitle, 953).
--define(wxMenuItem_new, 954).
--define(wxMenuItem_destruct, 956).
--define(wxMenuItem_Check, 957).
--define(wxMenuItem_Enable, 958).
--define(wxMenuItem_GetBitmap, 959).
--define(wxMenuItem_GetHelp, 960).
--define(wxMenuItem_GetId, 961).
--define(wxMenuItem_GetKind, 962).
--define(wxMenuItem_GetLabel, 963).
--define(wxMenuItem_GetLabelFromText, 964).
--define(wxMenuItem_GetMenu, 965).
--define(wxMenuItem_GetText, 966).
--define(wxMenuItem_GetSubMenu, 967).
--define(wxMenuItem_IsCheckable, 968).
--define(wxMenuItem_IsChecked, 969).
--define(wxMenuItem_IsEnabled, 970).
--define(wxMenuItem_IsSeparator, 971).
--define(wxMenuItem_IsSubMenu, 972).
--define(wxMenuItem_SetBitmap, 973).
--define(wxMenuItem_SetHelp, 974).
--define(wxMenuItem_SetMenu, 975).
--define(wxMenuItem_SetSubMenu, 976).
--define(wxMenuItem_SetText, 977).
--define(wxToolBar_AddControl, 978).
--define(wxToolBar_AddSeparator, 979).
--define(wxToolBar_AddTool_5, 980).
--define(wxToolBar_AddTool_4_0, 981).
--define(wxToolBar_AddTool_1, 982).
--define(wxToolBar_AddTool_4_1, 983).
--define(wxToolBar_AddTool_3, 984).
--define(wxToolBar_AddTool_6, 985).
--define(wxToolBar_AddCheckTool, 986).
--define(wxToolBar_AddRadioTool, 987).
--define(wxToolBar_AddStretchableSpace, 988).
--define(wxToolBar_InsertStretchableSpace, 989).
--define(wxToolBar_DeleteTool, 990).
--define(wxToolBar_DeleteToolByPos, 991).
--define(wxToolBar_EnableTool, 992).
--define(wxToolBar_FindById, 993).
--define(wxToolBar_FindControl, 994).
--define(wxToolBar_FindToolForPosition, 995).
--define(wxToolBar_GetToolSize, 996).
--define(wxToolBar_GetToolBitmapSize, 997).
--define(wxToolBar_GetMargins, 998).
--define(wxToolBar_GetToolEnabled, 999).
--define(wxToolBar_GetToolLongHelp, 1000).
--define(wxToolBar_GetToolPacking, 1001).
--define(wxToolBar_GetToolPos, 1002).
--define(wxToolBar_GetToolSeparation, 1003).
--define(wxToolBar_GetToolShortHelp, 1004).
--define(wxToolBar_GetToolState, 1005).
--define(wxToolBar_InsertControl, 1006).
--define(wxToolBar_InsertSeparator, 1007).
--define(wxToolBar_InsertTool_5, 1008).
--define(wxToolBar_InsertTool_2, 1009).
--define(wxToolBar_InsertTool_4, 1010).
--define(wxToolBar_Realize, 1011).
--define(wxToolBar_RemoveTool, 1012).
--define(wxToolBar_SetMargins, 1013).
--define(wxToolBar_SetToolBitmapSize, 1014).
--define(wxToolBar_SetToolLongHelp, 1015).
--define(wxToolBar_SetToolPacking, 1016).
--define(wxToolBar_SetToolShortHelp, 1017).
--define(wxToolBar_SetToolSeparation, 1018).
--define(wxToolBar_ToggleTool, 1019).
--define(wxStatusBar_new_0, 1021).
--define(wxStatusBar_new_2, 1022).
--define(wxStatusBar_destruct, 1024).
--define(wxStatusBar_Create, 1025).
--define(wxStatusBar_GetFieldRect, 1026).
--define(wxStatusBar_GetFieldsCount, 1027).
--define(wxStatusBar_GetStatusText, 1028).
--define(wxStatusBar_PopStatusText, 1029).
--define(wxStatusBar_PushStatusText, 1030).
--define(wxStatusBar_SetFieldsCount, 1031).
--define(wxStatusBar_SetMinHeight, 1032).
--define(wxStatusBar_SetStatusText, 1033).
--define(wxStatusBar_SetStatusWidths, 1034).
--define(wxStatusBar_SetStatusStyles, 1035).
--define(wxBitmap_new_0, 1036).
--define(wxBitmap_new_3, 1037).
--define(wxBitmap_new_4, 1038).
--define(wxBitmap_new_2_0, 1039).
--define(wxBitmap_new_2_1, 1040).
--define(wxBitmap_destruct, 1041).
--define(wxBitmap_ConvertToImage, 1042).
--define(wxBitmap_CopyFromIcon, 1043).
--define(wxBitmap_Create, 1044).
--define(wxBitmap_GetDepth, 1045).
--define(wxBitmap_GetHeight, 1046).
--define(wxBitmap_GetPalette, 1047).
--define(wxBitmap_GetMask, 1048).
--define(wxBitmap_GetWidth, 1049).
--define(wxBitmap_GetSubBitmap, 1050).
--define(wxBitmap_LoadFile, 1051).
--define(wxBitmap_Ok, 1052).
--define(wxBitmap_SaveFile, 1053).
--define(wxBitmap_SetDepth, 1054).
--define(wxBitmap_SetHeight, 1055).
--define(wxBitmap_SetMask, 1056).
--define(wxBitmap_SetPalette, 1057).
--define(wxBitmap_SetWidth, 1058).
--define(wxIcon_new_0, 1059).
--define(wxIcon_new_2, 1060).
--define(wxIcon_new_1, 1061).
--define(wxIcon_CopyFromBitmap, 1062).
--define(wxIcon_destroy, 1063).
--define(wxIconBundle_new_0, 1064).
--define(wxIconBundle_new_2, 1065).
--define(wxIconBundle_new_1_0, 1066).
--define(wxIconBundle_new_1_1, 1067).
--define(wxIconBundle_destruct, 1068).
--define(wxIconBundle_AddIcon_2, 1069).
--define(wxIconBundle_AddIcon_1, 1070).
--define(wxIconBundle_GetIcon_1_1, 1071).
--define(wxIconBundle_GetIcon_1_0, 1072).
--define(wxCursor_new_0, 1073).
--define(wxCursor_new_1_0, 1074).
--define(wxCursor_new_1_1, 1075).
--define(wxCursor_new_4, 1076).
--define(wxCursor_destruct, 1077).
--define(wxCursor_Ok, 1078).
--define(wxMask_new_0, 1079).
--define(wxMask_new_2_1, 1080).
--define(wxMask_new_2_0, 1081).
--define(wxMask_new_1, 1082).
--define(wxMask_destruct, 1083).
--define(wxMask_Create_2_1, 1084).
--define(wxMask_Create_2_0, 1085).
--define(wxMask_Create_1, 1086).
--define(wxImage_new_0, 1087).
--define(wxImage_new_3_0, 1088).
--define(wxImage_new_4, 1089).
--define(wxImage_new_5, 1090).
--define(wxImage_new_2, 1091).
--define(wxImage_new_3_1, 1092).
--define(wxImage_Blur, 1093).
--define(wxImage_BlurHorizontal, 1094).
--define(wxImage_BlurVertical, 1095).
--define(wxImage_ConvertAlphaToMask, 1096).
--define(wxImage_ConvertToGreyscale, 1097).
--define(wxImage_ConvertToMono, 1098).
--define(wxImage_Copy, 1099).
--define(wxImage_Create_3, 1100).
--define(wxImage_Create_4, 1101).
--define(wxImage_Create_5, 1102).
--define(wxImage_Destroy, 1103).
--define(wxImage_FindFirstUnusedColour, 1104).
--define(wxImage_GetImageExtWildcard, 1105).
--define(wxImage_GetAlpha_2, 1106).
--define(wxImage_GetAlpha_0, 1107).
--define(wxImage_GetBlue, 1108).
--define(wxImage_GetData, 1109).
--define(wxImage_GetGreen, 1110).
--define(wxImage_GetImageCount, 1111).
--define(wxImage_GetHeight, 1112).
--define(wxImage_GetMaskBlue, 1113).
--define(wxImage_GetMaskGreen, 1114).
--define(wxImage_GetMaskRed, 1115).
--define(wxImage_GetOrFindMaskColour, 1116).
--define(wxImage_GetPalette, 1117).
--define(wxImage_GetRed, 1118).
--define(wxImage_GetSubImage, 1119).
--define(wxImage_GetWidth, 1120).
--define(wxImage_HasAlpha, 1121).
--define(wxImage_HasMask, 1122).
--define(wxImage_GetOption, 1123).
--define(wxImage_GetOptionInt, 1124).
--define(wxImage_HasOption, 1125).
--define(wxImage_InitAlpha, 1126).
--define(wxImage_InitStandardHandlers, 1127).
--define(wxImage_IsTransparent, 1128).
--define(wxImage_LoadFile_2, 1129).
--define(wxImage_LoadFile_3, 1130).
--define(wxImage_Ok, 1131).
--define(wxImage_RemoveHandler, 1132).
--define(wxImage_Mirror, 1133).
--define(wxImage_Replace, 1134).
--define(wxImage_Rescale, 1135).
--define(wxImage_Resize, 1136).
--define(wxImage_Rotate, 1137).
--define(wxImage_RotateHue, 1138).
--define(wxImage_Rotate90, 1139).
--define(wxImage_SaveFile_1, 1140).
--define(wxImage_SaveFile_2_0, 1141).
--define(wxImage_SaveFile_2_1, 1142).
--define(wxImage_Scale, 1143).
--define(wxImage_Size, 1144).
--define(wxImage_SetAlpha_3, 1145).
--define(wxImage_SetAlpha_2, 1146).
--define(wxImage_SetData_2, 1147).
--define(wxImage_SetData_4, 1148).
--define(wxImage_SetMask, 1149).
--define(wxImage_SetMaskColour, 1150).
--define(wxImage_SetMaskFromImage, 1151).
--define(wxImage_SetOption_2_1, 1152).
--define(wxImage_SetOption_2_0, 1153).
--define(wxImage_SetPalette, 1154).
--define(wxImage_SetRGB_5, 1155).
--define(wxImage_SetRGB_4, 1156).
--define(wxImage_destroy, 1157).
--define(wxBrush_new_0, 1158).
--define(wxBrush_new_2, 1159).
--define(wxBrush_new_1, 1160).
--define(wxBrush_destruct, 1162).
--define(wxBrush_GetColour, 1163).
--define(wxBrush_GetStipple, 1164).
--define(wxBrush_GetStyle, 1165).
--define(wxBrush_IsHatch, 1166).
--define(wxBrush_IsOk, 1167).
--define(wxBrush_SetColour_1, 1168).
--define(wxBrush_SetColour_3, 1169).
--define(wxBrush_SetStipple, 1170).
--define(wxBrush_SetStyle, 1171).
--define(wxPen_new_0, 1172).
--define(wxPen_new_2, 1173).
--define(wxPen_destruct, 1174).
--define(wxPen_GetCap, 1175).
--define(wxPen_GetColour, 1176).
--define(wxPen_GetJoin, 1177).
--define(wxPen_GetStyle, 1178).
--define(wxPen_GetWidth, 1179).
--define(wxPen_IsOk, 1180).
--define(wxPen_SetCap, 1181).
--define(wxPen_SetColour_1, 1182).
--define(wxPen_SetColour_3, 1183).
--define(wxPen_SetJoin, 1184).
--define(wxPen_SetStyle, 1185).
--define(wxPen_SetWidth, 1186).
--define(wxRegion_new_0, 1187).
--define(wxRegion_new_4, 1188).
--define(wxRegion_new_2, 1189).
--define(wxRegion_new_1_1, 1190).
--define(wxRegion_new_1_0, 1192).
--define(wxRegion_destruct, 1194).
--define(wxRegion_Clear, 1195).
--define(wxRegion_Contains_2, 1196).
--define(wxRegion_Contains_1_0, 1197).
--define(wxRegion_Contains_4, 1198).
--define(wxRegion_Contains_1_1, 1199).
--define(wxRegion_ConvertToBitmap, 1200).
--define(wxRegion_GetBox, 1201).
--define(wxRegion_Intersect_4, 1202).
--define(wxRegion_Intersect_1_1, 1203).
--define(wxRegion_Intersect_1_0, 1204).
--define(wxRegion_IsEmpty, 1205).
--define(wxRegion_Subtract_4, 1206).
--define(wxRegion_Subtract_1_1, 1207).
--define(wxRegion_Subtract_1_0, 1208).
--define(wxRegion_Offset_2, 1209).
--define(wxRegion_Offset_1, 1210).
--define(wxRegion_Union_4, 1211).
--define(wxRegion_Union_1_2, 1212).
--define(wxRegion_Union_1_1, 1213).
--define(wxRegion_Union_1_0, 1214).
--define(wxRegion_Union_3, 1215).
--define(wxRegion_Xor_4, 1216).
--define(wxRegion_Xor_1_1, 1217).
--define(wxRegion_Xor_1_0, 1218).
--define(wxAcceleratorTable_new_0, 1219).
--define(wxAcceleratorTable_new_2, 1220).
--define(wxAcceleratorTable_destruct, 1221).
--define(wxAcceleratorTable_Ok, 1222).
--define(wxAcceleratorEntry_new_1_0, 1223).
--define(wxAcceleratorEntry_new_1_1, 1224).
--define(wxAcceleratorEntry_GetCommand, 1225).
--define(wxAcceleratorEntry_GetFlags, 1226).
--define(wxAcceleratorEntry_GetKeyCode, 1227).
--define(wxAcceleratorEntry_Set, 1228).
--define(wxAcceleratorEntry_destroy, 1229).
--define(wxCaret_new_3, 1234).
--define(wxCaret_new_2, 1235).
--define(wxCaret_destruct, 1237).
--define(wxCaret_Create_3, 1238).
--define(wxCaret_Create_2, 1239).
--define(wxCaret_GetBlinkTime, 1240).
--define(wxCaret_GetPosition, 1242).
--define(wxCaret_GetSize, 1244).
--define(wxCaret_GetWindow, 1245).
--define(wxCaret_Hide, 1246).
--define(wxCaret_IsOk, 1247).
--define(wxCaret_IsVisible, 1248).
--define(wxCaret_Move_2, 1249).
--define(wxCaret_Move_1, 1250).
--define(wxCaret_SetBlinkTime, 1251).
--define(wxCaret_SetSize_2, 1252).
--define(wxCaret_SetSize_1, 1253).
--define(wxCaret_Show, 1254).
--define(wxSizer_Add_2_1, 1255).
--define(wxSizer_Add_2_0, 1256).
--define(wxSizer_Add_3, 1257).
--define(wxSizer_Add_2_3, 1258).
--define(wxSizer_Add_2_2, 1259).
--define(wxSizer_AddSpacer, 1260).
--define(wxSizer_AddStretchSpacer, 1261).
--define(wxSizer_CalcMin, 1262).
--define(wxSizer_Clear, 1263).
--define(wxSizer_Detach_1_2, 1264).
--define(wxSizer_Detach_1_1, 1265).
--define(wxSizer_Detach_1_0, 1266).
--define(wxSizer_Fit, 1267).
--define(wxSizer_FitInside, 1268).
--define(wxSizer_GetChildren, 1269).
--define(wxSizer_GetItem_2_1, 1270).
--define(wxSizer_GetItem_2_0, 1271).
--define(wxSizer_GetItem_1, 1272).
--define(wxSizer_GetSize, 1273).
--define(wxSizer_GetPosition, 1274).
--define(wxSizer_GetMinSize, 1275).
--define(wxSizer_Hide_2_0, 1276).
--define(wxSizer_Hide_2_1, 1277).
--define(wxSizer_Hide_1, 1278).
--define(wxSizer_Insert_3_1, 1279).
--define(wxSizer_Insert_3_0, 1280).
--define(wxSizer_Insert_4, 1281).
--define(wxSizer_Insert_3_3, 1282).
--define(wxSizer_Insert_3_2, 1283).
--define(wxSizer_Insert_2, 1284).
--define(wxSizer_InsertSpacer, 1285).
--define(wxSizer_InsertStretchSpacer, 1286).
--define(wxSizer_IsShown_1_2, 1287).
--define(wxSizer_IsShown_1_1, 1288).
--define(wxSizer_IsShown_1_0, 1289).
--define(wxSizer_Layout, 1290).
--define(wxSizer_Prepend_2_1, 1291).
--define(wxSizer_Prepend_2_0, 1292).
--define(wxSizer_Prepend_3, 1293).
--define(wxSizer_Prepend_2_3, 1294).
--define(wxSizer_Prepend_2_2, 1295).
--define(wxSizer_Prepend_1, 1296).
--define(wxSizer_PrependSpacer, 1297).
--define(wxSizer_PrependStretchSpacer, 1298).
--define(wxSizer_RecalcSizes, 1299).
--define(wxSizer_Remove_1_1, 1300).
--define(wxSizer_Remove_1_0, 1301).
--define(wxSizer_Replace_3_1, 1302).
--define(wxSizer_Replace_3_0, 1303).
--define(wxSizer_Replace_2, 1304).
--define(wxSizer_SetDimension, 1305).
--define(wxSizer_SetMinSize_2, 1306).
--define(wxSizer_SetMinSize_1, 1307).
--define(wxSizer_SetItemMinSize_3_2, 1308).
--define(wxSizer_SetItemMinSize_2_2, 1309).
--define(wxSizer_SetItemMinSize_3_1, 1310).
--define(wxSizer_SetItemMinSize_2_1, 1311).
--define(wxSizer_SetItemMinSize_3_0, 1312).
--define(wxSizer_SetItemMinSize_2_0, 1313).
--define(wxSizer_SetSizeHints, 1314).
--define(wxSizer_SetVirtualSizeHints, 1315).
--define(wxSizer_Show_2_2, 1316).
--define(wxSizer_Show_2_1, 1317).
--define(wxSizer_Show_2_0, 1318).
--define(wxSizer_Show_1, 1319).
--define(wxSizerFlags_new, 1320).
--define(wxSizerFlags_Align, 1321).
--define(wxSizerFlags_Border_2, 1322).
--define(wxSizerFlags_Border_1, 1323).
--define(wxSizerFlags_Center, 1324).
--define(wxSizerFlags_Centre, 1325).
--define(wxSizerFlags_Expand, 1326).
--define(wxSizerFlags_Left, 1327).
--define(wxSizerFlags_Proportion, 1328).
--define(wxSizerFlags_Right, 1329).
--define(wxSizerFlags_destroy, 1330).
--define(wxSizerItem_new_5_1, 1331).
--define(wxSizerItem_new_2_1, 1332).
--define(wxSizerItem_new_5_0, 1333).
--define(wxSizerItem_new_2_0, 1334).
--define(wxSizerItem_new_6, 1335).
--define(wxSizerItem_new_3, 1336).
--define(wxSizerItem_new_0, 1337).
--define(wxSizerItem_destruct, 1338).
--define(wxSizerItem_CalcMin, 1339).
--define(wxSizerItem_DeleteWindows, 1340).
--define(wxSizerItem_DetachSizer, 1341).
--define(wxSizerItem_GetBorder, 1342).
--define(wxSizerItem_GetFlag, 1343).
--define(wxSizerItem_GetMinSize, 1344).
--define(wxSizerItem_GetPosition, 1345).
--define(wxSizerItem_GetProportion, 1346).
--define(wxSizerItem_GetRatio, 1347).
--define(wxSizerItem_GetRect, 1348).
--define(wxSizerItem_GetSize, 1349).
--define(wxSizerItem_GetSizer, 1350).
--define(wxSizerItem_GetSpacer, 1351).
--define(wxSizerItem_GetUserData, 1352).
--define(wxSizerItem_GetWindow, 1353).
--define(wxSizerItem_IsSizer, 1354).
--define(wxSizerItem_IsShown, 1355).
--define(wxSizerItem_IsSpacer, 1356).
--define(wxSizerItem_IsWindow, 1357).
--define(wxSizerItem_SetBorder, 1358).
--define(wxSizerItem_SetDimension, 1359).
--define(wxSizerItem_SetFlag, 1360).
--define(wxSizerItem_SetInitSize, 1361).
--define(wxSizerItem_SetMinSize_1, 1362).
--define(wxSizerItem_SetMinSize_2, 1363).
--define(wxSizerItem_SetProportion, 1364).
--define(wxSizerItem_SetRatio_2, 1365).
--define(wxSizerItem_SetRatio_1_1, 1366).
--define(wxSizerItem_SetRatio_1_0, 1367).
--define(wxSizerItem_SetSizer, 1368).
--define(wxSizerItem_SetSpacer_1, 1369).
--define(wxSizerItem_SetSpacer_2, 1370).
--define(wxSizerItem_SetWindow, 1371).
--define(wxSizerItem_Show, 1372).
--define(wxBoxSizer_new, 1373).
--define(wxBoxSizer_GetOrientation, 1374).
--define(wxBoxSizer_destroy, 1375).
--define(wxStaticBoxSizer_new_2, 1376).
--define(wxStaticBoxSizer_new_3, 1377).
--define(wxStaticBoxSizer_GetStaticBox, 1378).
--define(wxStaticBoxSizer_destroy, 1379).
--define(wxGridSizer_new_4, 1380).
--define(wxGridSizer_new_2, 1381).
--define(wxGridSizer_GetCols, 1382).
--define(wxGridSizer_GetHGap, 1383).
--define(wxGridSizer_GetRows, 1384).
--define(wxGridSizer_GetVGap, 1385).
--define(wxGridSizer_SetCols, 1386).
--define(wxGridSizer_SetHGap, 1387).
--define(wxGridSizer_SetRows, 1388).
--define(wxGridSizer_SetVGap, 1389).
--define(wxGridSizer_destroy, 1390).
--define(wxFlexGridSizer_new_4, 1391).
--define(wxFlexGridSizer_new_2, 1392).
--define(wxFlexGridSizer_AddGrowableCol, 1393).
--define(wxFlexGridSizer_AddGrowableRow, 1394).
--define(wxFlexGridSizer_GetFlexibleDirection, 1395).
--define(wxFlexGridSizer_GetNonFlexibleGrowMode, 1396).
--define(wxFlexGridSizer_RemoveGrowableCol, 1397).
--define(wxFlexGridSizer_RemoveGrowableRow, 1398).
--define(wxFlexGridSizer_SetFlexibleDirection, 1399).
--define(wxFlexGridSizer_SetNonFlexibleGrowMode, 1400).
--define(wxFlexGridSizer_destroy, 1401).
--define(wxGridBagSizer_new, 1402).
--define(wxGridBagSizer_Add_3_2, 1403).
--define(wxGridBagSizer_Add_3_1, 1404).
--define(wxGridBagSizer_Add_4, 1405).
--define(wxGridBagSizer_Add_1_0, 1406).
--define(wxGridBagSizer_Add_2_1, 1407).
--define(wxGridBagSizer_Add_2_0, 1408).
--define(wxGridBagSizer_Add_3_0, 1409).
--define(wxGridBagSizer_Add_1_1, 1410).
--define(wxGridBagSizer_CalcMin, 1411).
--define(wxGridBagSizer_CheckForIntersection_2, 1412).
--define(wxGridBagSizer_CheckForIntersection_3, 1413).
--define(wxGridBagSizer_FindItem_1_1, 1414).
--define(wxGridBagSizer_FindItem_1_0, 1415).
--define(wxGridBagSizer_FindItemAtPoint, 1416).
--define(wxGridBagSizer_FindItemAtPosition, 1417).
--define(wxGridBagSizer_FindItemWithData, 1418).
--define(wxGridBagSizer_GetCellSize, 1419).
--define(wxGridBagSizer_GetEmptyCellSize, 1420).
--define(wxGridBagSizer_GetItemPosition_1_2, 1421).
--define(wxGridBagSizer_GetItemPosition_1_1, 1422).
--define(wxGridBagSizer_GetItemPosition_1_0, 1423).
--define(wxGridBagSizer_GetItemSpan_1_2, 1424).
--define(wxGridBagSizer_GetItemSpan_1_1, 1425).
--define(wxGridBagSizer_GetItemSpan_1_0, 1426).
--define(wxGridBagSizer_SetEmptyCellSize, 1427).
--define(wxGridBagSizer_SetItemPosition_2_2, 1428).
--define(wxGridBagSizer_SetItemPosition_2_1, 1429).
--define(wxGridBagSizer_SetItemPosition_2_0, 1430).
--define(wxGridBagSizer_SetItemSpan_2_2, 1431).
--define(wxGridBagSizer_SetItemSpan_2_1, 1432).
--define(wxGridBagSizer_SetItemSpan_2_0, 1433).
--define(wxGridBagSizer_destroy, 1434).
--define(wxStdDialogButtonSizer_new, 1435).
--define(wxStdDialogButtonSizer_AddButton, 1436).
--define(wxStdDialogButtonSizer_Realize, 1437).
--define(wxStdDialogButtonSizer_SetAffirmativeButton, 1438).
--define(wxStdDialogButtonSizer_SetCancelButton, 1439).
--define(wxStdDialogButtonSizer_SetNegativeButton, 1440).
--define(wxStdDialogButtonSizer_destroy, 1441).
--define(wxFont_new_0, 1442).
--define(wxFont_new_1, 1443).
--define(wxFont_new_5, 1444).
--define(wxFont_destruct, 1446).
--define(wxFont_IsFixedWidth, 1447).
--define(wxFont_GetDefaultEncoding, 1448).
--define(wxFont_GetFaceName, 1449).
--define(wxFont_GetFamily, 1450).
--define(wxFont_GetNativeFontInfoDesc, 1451).
--define(wxFont_GetNativeFontInfoUserDesc, 1452).
--define(wxFont_GetPointSize, 1453).
--define(wxFont_GetStyle, 1454).
--define(wxFont_GetUnderlined, 1455).
--define(wxFont_GetWeight, 1456).
--define(wxFont_Ok, 1457).
--define(wxFont_SetDefaultEncoding, 1458).
--define(wxFont_SetFaceName, 1459).
--define(wxFont_SetFamily, 1460).
--define(wxFont_SetPointSize, 1461).
--define(wxFont_SetStyle, 1462).
--define(wxFont_SetUnderlined, 1463).
--define(wxFont_SetWeight, 1464).
--define(wxToolTip_Enable, 1465).
--define(wxToolTip_SetDelay, 1466).
--define(wxToolTip_new, 1467).
--define(wxToolTip_SetTip, 1468).
--define(wxToolTip_GetTip, 1469).
--define(wxToolTip_GetWindow, 1470).
--define(wxToolTip_destroy, 1471).
--define(wxButton_new_3, 1473).
--define(wxButton_new_0, 1474).
--define(wxButton_destruct, 1475).
--define(wxButton_Create, 1476).
--define(wxButton_GetDefaultSize, 1477).
--define(wxButton_SetDefault, 1478).
--define(wxButton_SetLabel, 1479).
--define(wxBitmapButton_new_4, 1481).
--define(wxBitmapButton_new_0, 1482).
--define(wxBitmapButton_Create, 1483).
--define(wxBitmapButton_GetBitmapDisabled, 1484).
--define(wxBitmapButton_GetBitmapFocus, 1486).
--define(wxBitmapButton_GetBitmapLabel, 1488).
--define(wxBitmapButton_GetBitmapSelected, 1490).
--define(wxBitmapButton_SetBitmapDisabled, 1492).
--define(wxBitmapButton_SetBitmapFocus, 1493).
--define(wxBitmapButton_SetBitmapLabel, 1494).
--define(wxBitmapButton_SetBitmapSelected, 1495).
--define(wxBitmapButton_destroy, 1496).
--define(wxToggleButton_new_0, 1497).
--define(wxToggleButton_new_4, 1498).
--define(wxToggleButton_Create, 1499).
--define(wxToggleButton_GetValue, 1500).
--define(wxToggleButton_SetValue, 1501).
--define(wxToggleButton_destroy, 1502).
--define(wxCalendarCtrl_new_0, 1503).
--define(wxCalendarCtrl_new_3, 1504).
--define(wxCalendarCtrl_Create, 1505).
--define(wxCalendarCtrl_destruct, 1506).
--define(wxCalendarCtrl_SetDate, 1507).
--define(wxCalendarCtrl_GetDate, 1508).
--define(wxCalendarCtrl_EnableYearChange, 1509).
--define(wxCalendarCtrl_EnableMonthChange, 1510).
--define(wxCalendarCtrl_EnableHolidayDisplay, 1511).
--define(wxCalendarCtrl_SetHeaderColours, 1512).
--define(wxCalendarCtrl_GetHeaderColourFg, 1513).
--define(wxCalendarCtrl_GetHeaderColourBg, 1514).
--define(wxCalendarCtrl_SetHighlightColours, 1515).
--define(wxCalendarCtrl_GetHighlightColourFg, 1516).
--define(wxCalendarCtrl_GetHighlightColourBg, 1517).
--define(wxCalendarCtrl_SetHolidayColours, 1518).
--define(wxCalendarCtrl_GetHolidayColourFg, 1519).
--define(wxCalendarCtrl_GetHolidayColourBg, 1520).
--define(wxCalendarCtrl_GetAttr, 1521).
--define(wxCalendarCtrl_SetAttr, 1522).
--define(wxCalendarCtrl_SetHoliday, 1523).
--define(wxCalendarCtrl_ResetAttr, 1524).
--define(wxCalendarCtrl_HitTest, 1525).
--define(wxCalendarDateAttr_new_0, 1526).
--define(wxCalendarDateAttr_new_2_1, 1527).
--define(wxCalendarDateAttr_new_2_0, 1528).
--define(wxCalendarDateAttr_SetTextColour, 1529).
--define(wxCalendarDateAttr_SetBackgroundColour, 1530).
--define(wxCalendarDateAttr_SetBorderColour, 1531).
--define(wxCalendarDateAttr_SetFont, 1532).
--define(wxCalendarDateAttr_SetBorder, 1533).
--define(wxCalendarDateAttr_SetHoliday, 1534).
--define(wxCalendarDateAttr_HasTextColour, 1535).
--define(wxCalendarDateAttr_HasBackgroundColour, 1536).
--define(wxCalendarDateAttr_HasBorderColour, 1537).
--define(wxCalendarDateAttr_HasFont, 1538).
--define(wxCalendarDateAttr_HasBorder, 1539).
--define(wxCalendarDateAttr_IsHoliday, 1540).
--define(wxCalendarDateAttr_GetTextColour, 1541).
--define(wxCalendarDateAttr_GetBackgroundColour, 1542).
--define(wxCalendarDateAttr_GetBorderColour, 1543).
--define(wxCalendarDateAttr_GetFont, 1544).
--define(wxCalendarDateAttr_GetBorder, 1545).
--define(wxCalendarDateAttr_destroy, 1546).
--define(wxCheckBox_new_4, 1548).
--define(wxCheckBox_new_0, 1549).
--define(wxCheckBox_Create, 1550).
--define(wxCheckBox_GetValue, 1551).
--define(wxCheckBox_Get3StateValue, 1552).
--define(wxCheckBox_Is3rdStateAllowedForUser, 1553).
--define(wxCheckBox_Is3State, 1554).
--define(wxCheckBox_IsChecked, 1555).
--define(wxCheckBox_SetValue, 1556).
--define(wxCheckBox_Set3StateValue, 1557).
--define(wxCheckBox_destroy, 1558).
--define(wxCheckListBox_new_0, 1559).
--define(wxCheckListBox_new_3, 1561).
--define(wxCheckListBox_Check, 1562).
--define(wxCheckListBox_IsChecked, 1563).
--define(wxCheckListBox_destroy, 1564).
--define(wxChoice_new_3, 1567).
--define(wxChoice_new_0, 1568).
--define(wxChoice_destruct, 1570).
--define(wxChoice_Create, 1572).
--define(wxChoice_Delete, 1573).
--define(wxChoice_GetColumns, 1574).
--define(wxChoice_SetColumns, 1575).
--define(wxComboBox_new_0, 1576).
--define(wxComboBox_new_3, 1578).
--define(wxComboBox_destruct, 1579).
--define(wxComboBox_Create, 1581).
--define(wxComboBox_CanCopy, 1582).
--define(wxComboBox_CanCut, 1583).
--define(wxComboBox_CanPaste, 1584).
--define(wxComboBox_CanRedo, 1585).
--define(wxComboBox_CanUndo, 1586).
--define(wxComboBox_Copy, 1587).
--define(wxComboBox_Cut, 1588).
--define(wxComboBox_GetInsertionPoint, 1589).
--define(wxComboBox_GetLastPosition, 1590).
--define(wxComboBox_GetValue, 1591).
--define(wxComboBox_Paste, 1592).
--define(wxComboBox_Redo, 1593).
--define(wxComboBox_Replace, 1594).
--define(wxComboBox_Remove, 1595).
--define(wxComboBox_SetInsertionPoint, 1596).
--define(wxComboBox_SetInsertionPointEnd, 1597).
--define(wxComboBox_SetSelection_1, 1598).
--define(wxComboBox_SetSelection_2, 1599).
--define(wxComboBox_SetValue, 1600).
--define(wxComboBox_Undo, 1601).
--define(wxGauge_new_0, 1602).
--define(wxGauge_new_4, 1603).
--define(wxGauge_Create, 1604).
--define(wxGauge_GetRange, 1605).
--define(wxGauge_GetValue, 1606).
--define(wxGauge_IsVertical, 1607).
--define(wxGauge_SetRange, 1608).
--define(wxGauge_SetValue, 1609).
--define(wxGauge_Pulse, 1610).
--define(wxGauge_destroy, 1611).
--define(wxGenericDirCtrl_new_0, 1612).
--define(wxGenericDirCtrl_new_2, 1613).
--define(wxGenericDirCtrl_destruct, 1614).
--define(wxGenericDirCtrl_Create, 1615).
--define(wxGenericDirCtrl_Init, 1616).
--define(wxGenericDirCtrl_CollapseTree, 1617).
--define(wxGenericDirCtrl_ExpandPath, 1618).
--define(wxGenericDirCtrl_GetDefaultPath, 1619).
--define(wxGenericDirCtrl_GetPath, 1620).
--define(wxGenericDirCtrl_GetFilePath, 1621).
--define(wxGenericDirCtrl_GetFilter, 1622).
--define(wxGenericDirCtrl_GetFilterIndex, 1623).
--define(wxGenericDirCtrl_GetRootId, 1624).
--define(wxGenericDirCtrl_GetTreeCtrl, 1625).
--define(wxGenericDirCtrl_ReCreateTree, 1626).
--define(wxGenericDirCtrl_SetDefaultPath, 1627).
--define(wxGenericDirCtrl_SetFilter, 1628).
--define(wxGenericDirCtrl_SetFilterIndex, 1629).
--define(wxGenericDirCtrl_SetPath, 1630).
--define(wxStaticBox_new_4, 1632).
--define(wxStaticBox_new_0, 1633).
--define(wxStaticBox_Create, 1634).
--define(wxStaticBox_destroy, 1635).
--define(wxStaticLine_new_2, 1637).
--define(wxStaticLine_new_0, 1638).
--define(wxStaticLine_Create, 1639).
--define(wxStaticLine_IsVertical, 1640).
--define(wxStaticLine_GetDefaultSize, 1641).
--define(wxStaticLine_destroy, 1642).
--define(wxListBox_new_3, 1645).
--define(wxListBox_new_0, 1646).
--define(wxListBox_destruct, 1648).
--define(wxListBox_Create, 1650).
--define(wxListBox_Deselect, 1651).
--define(wxListBox_GetSelections, 1652).
--define(wxListBox_InsertItems, 1653).
--define(wxListBox_IsSelected, 1654).
--define(wxListBox_Set, 1655).
--define(wxListBox_HitTest, 1656).
--define(wxListBox_SetFirstItem_1_0, 1657).
--define(wxListBox_SetFirstItem_1_1, 1658).
--define(wxListCtrl_new_0, 1659).
--define(wxListCtrl_new_2, 1660).
--define(wxListCtrl_Arrange, 1661).
--define(wxListCtrl_AssignImageList, 1662).
--define(wxListCtrl_ClearAll, 1663).
--define(wxListCtrl_Create, 1664).
--define(wxListCtrl_DeleteAllItems, 1665).
--define(wxListCtrl_DeleteColumn, 1666).
--define(wxListCtrl_DeleteItem, 1667).
--define(wxListCtrl_EditLabel, 1668).
--define(wxListCtrl_EnsureVisible, 1669).
--define(wxListCtrl_FindItem_3_0, 1670).
--define(wxListCtrl_FindItem_3_1, 1671).
--define(wxListCtrl_GetColumn, 1672).
--define(wxListCtrl_GetColumnCount, 1673).
--define(wxListCtrl_GetColumnWidth, 1674).
--define(wxListCtrl_GetCountPerPage, 1675).
--define(wxListCtrl_GetEditControl, 1676).
--define(wxListCtrl_GetImageList, 1677).
--define(wxListCtrl_GetItem, 1678).
--define(wxListCtrl_GetItemBackgroundColour, 1679).
--define(wxListCtrl_GetItemCount, 1680).
--define(wxListCtrl_GetItemData, 1681).
--define(wxListCtrl_GetItemFont, 1682).
--define(wxListCtrl_GetItemPosition, 1683).
--define(wxListCtrl_GetItemRect, 1684).
--define(wxListCtrl_GetItemSpacing, 1685).
--define(wxListCtrl_GetItemState, 1686).
--define(wxListCtrl_GetItemText, 1687).
--define(wxListCtrl_GetItemTextColour, 1688).
--define(wxListCtrl_GetNextItem, 1689).
--define(wxListCtrl_GetSelectedItemCount, 1690).
--define(wxListCtrl_GetTextColour, 1691).
--define(wxListCtrl_GetTopItem, 1692).
--define(wxListCtrl_GetViewRect, 1693).
--define(wxListCtrl_HitTest, 1694).
--define(wxListCtrl_InsertColumn_2, 1695).
--define(wxListCtrl_InsertColumn_3, 1696).
--define(wxListCtrl_InsertItem_1, 1697).
--define(wxListCtrl_InsertItem_2_1, 1698).
--define(wxListCtrl_InsertItem_2_0, 1699).
--define(wxListCtrl_InsertItem_3, 1700).
--define(wxListCtrl_RefreshItem, 1701).
--define(wxListCtrl_RefreshItems, 1702).
--define(wxListCtrl_ScrollList, 1703).
--define(wxListCtrl_SetBackgroundColour, 1704).
--define(wxListCtrl_SetColumn, 1705).
--define(wxListCtrl_SetColumnWidth, 1706).
--define(wxListCtrl_SetImageList, 1707).
--define(wxListCtrl_SetItem_1, 1708).
--define(wxListCtrl_SetItem_4, 1709).
--define(wxListCtrl_SetItemBackgroundColour, 1710).
--define(wxListCtrl_SetItemCount, 1711).
--define(wxListCtrl_SetItemData, 1712).
--define(wxListCtrl_SetItemFont, 1713).
--define(wxListCtrl_SetItemImage, 1714).
--define(wxListCtrl_SetItemColumnImage, 1715).
--define(wxListCtrl_SetItemPosition, 1716).
--define(wxListCtrl_SetItemState, 1717).
--define(wxListCtrl_SetItemText, 1718).
--define(wxListCtrl_SetItemTextColour, 1719).
--define(wxListCtrl_SetSingleStyle, 1720).
--define(wxListCtrl_SetTextColour, 1721).
--define(wxListCtrl_SetWindowStyleFlag, 1722).
--define(wxListCtrl_SortItems, 1723).
--define(wxListCtrl_destroy, 1724).
--define(wxListView_ClearColumnImage, 1725).
--define(wxListView_Focus, 1726).
--define(wxListView_GetFirstSelected, 1727).
--define(wxListView_GetFocusedItem, 1728).
--define(wxListView_GetNextSelected, 1729).
--define(wxListView_IsSelected, 1730).
--define(wxListView_Select, 1731).
--define(wxListView_SetColumnImage, 1732).
--define(wxListItem_new_0, 1733).
--define(wxListItem_new_1, 1734).
--define(wxListItem_destruct, 1735).
--define(wxListItem_Clear, 1736).
--define(wxListItem_GetAlign, 1737).
--define(wxListItem_GetBackgroundColour, 1738).
--define(wxListItem_GetColumn, 1739).
--define(wxListItem_GetFont, 1740).
--define(wxListItem_GetId, 1741).
--define(wxListItem_GetImage, 1742).
--define(wxListItem_GetMask, 1743).
--define(wxListItem_GetState, 1744).
--define(wxListItem_GetText, 1745).
--define(wxListItem_GetTextColour, 1746).
--define(wxListItem_GetWidth, 1747).
--define(wxListItem_SetAlign, 1748).
--define(wxListItem_SetBackgroundColour, 1749).
--define(wxListItem_SetColumn, 1750).
--define(wxListItem_SetFont, 1751).
--define(wxListItem_SetId, 1752).
--define(wxListItem_SetImage, 1753).
--define(wxListItem_SetMask, 1754).
--define(wxListItem_SetState, 1755).
--define(wxListItem_SetStateMask, 1756).
--define(wxListItem_SetText, 1757).
--define(wxListItem_SetTextColour, 1758).
--define(wxListItem_SetWidth, 1759).
--define(wxListItemAttr_new_0, 1760).
--define(wxListItemAttr_new_3, 1761).
--define(wxListItemAttr_GetBackgroundColour, 1762).
--define(wxListItemAttr_GetFont, 1763).
--define(wxListItemAttr_GetTextColour, 1764).
--define(wxListItemAttr_HasBackgroundColour, 1765).
--define(wxListItemAttr_HasFont, 1766).
--define(wxListItemAttr_HasTextColour, 1767).
--define(wxListItemAttr_SetBackgroundColour, 1768).
--define(wxListItemAttr_SetFont, 1769).
--define(wxListItemAttr_SetTextColour, 1770).
--define(wxListItemAttr_destroy, 1771).
--define(wxImageList_new_0, 1772).
--define(wxImageList_new_3, 1773).
--define(wxImageList_Add_1, 1774).
--define(wxImageList_Add_2_0, 1775).
--define(wxImageList_Add_2_1, 1776).
--define(wxImageList_Create, 1777).
--define(wxImageList_Draw, 1779).
--define(wxImageList_GetBitmap, 1780).
--define(wxImageList_GetIcon, 1781).
--define(wxImageList_GetImageCount, 1782).
--define(wxImageList_GetSize, 1783).
--define(wxImageList_Remove, 1784).
--define(wxImageList_RemoveAll, 1785).
--define(wxImageList_Replace_2, 1786).
--define(wxImageList_Replace_3, 1787).
--define(wxImageList_destroy, 1788).
--define(wxTextAttr_new_0, 1789).
--define(wxTextAttr_new_2, 1790).
--define(wxTextAttr_GetAlignment, 1791).
--define(wxTextAttr_GetBackgroundColour, 1792).
--define(wxTextAttr_GetFont, 1793).
--define(wxTextAttr_GetLeftIndent, 1794).
--define(wxTextAttr_GetLeftSubIndent, 1795).
--define(wxTextAttr_GetRightIndent, 1796).
--define(wxTextAttr_GetTabs, 1797).
--define(wxTextAttr_GetTextColour, 1798).
--define(wxTextAttr_HasBackgroundColour, 1799).
--define(wxTextAttr_HasFont, 1800).
--define(wxTextAttr_HasTextColour, 1801).
--define(wxTextAttr_GetFlags, 1802).
--define(wxTextAttr_IsDefault, 1803).
--define(wxTextAttr_SetAlignment, 1804).
--define(wxTextAttr_SetBackgroundColour, 1805).
--define(wxTextAttr_SetFlags, 1806).
--define(wxTextAttr_SetFont, 1807).
--define(wxTextAttr_SetLeftIndent, 1808).
--define(wxTextAttr_SetRightIndent, 1809).
--define(wxTextAttr_SetTabs, 1810).
--define(wxTextAttr_SetTextColour, 1811).
--define(wxTextAttr_destroy, 1812).
--define(wxTextCtrl_new_3, 1814).
--define(wxTextCtrl_new_0, 1815).
--define(wxTextCtrl_destruct, 1817).
--define(wxTextCtrl_AppendText, 1818).
--define(wxTextCtrl_CanCopy, 1819).
--define(wxTextCtrl_CanCut, 1820).
--define(wxTextCtrl_CanPaste, 1821).
--define(wxTextCtrl_CanRedo, 1822).
--define(wxTextCtrl_CanUndo, 1823).
--define(wxTextCtrl_Clear, 1824).
--define(wxTextCtrl_Copy, 1825).
--define(wxTextCtrl_Create, 1826).
--define(wxTextCtrl_Cut, 1827).
--define(wxTextCtrl_DiscardEdits, 1828).
--define(wxTextCtrl_ChangeValue, 1829).
--define(wxTextCtrl_EmulateKeyPress, 1830).
--define(wxTextCtrl_GetDefaultStyle, 1831).
--define(wxTextCtrl_GetInsertionPoint, 1832).
--define(wxTextCtrl_GetLastPosition, 1833).
--define(wxTextCtrl_GetLineLength, 1834).
--define(wxTextCtrl_GetLineText, 1835).
--define(wxTextCtrl_GetNumberOfLines, 1836).
--define(wxTextCtrl_GetRange, 1837).
--define(wxTextCtrl_GetSelection, 1838).
--define(wxTextCtrl_GetStringSelection, 1839).
--define(wxTextCtrl_GetStyle, 1840).
--define(wxTextCtrl_GetValue, 1841).
--define(wxTextCtrl_IsEditable, 1842).
--define(wxTextCtrl_IsModified, 1843).
--define(wxTextCtrl_IsMultiLine, 1844).
--define(wxTextCtrl_IsSingleLine, 1845).
--define(wxTextCtrl_LoadFile, 1846).
--define(wxTextCtrl_MarkDirty, 1847).
--define(wxTextCtrl_Paste, 1848).
--define(wxTextCtrl_PositionToXY, 1849).
--define(wxTextCtrl_Redo, 1850).
--define(wxTextCtrl_Remove, 1851).
--define(wxTextCtrl_Replace, 1852).
--define(wxTextCtrl_SaveFile, 1853).
--define(wxTextCtrl_SetDefaultStyle, 1854).
--define(wxTextCtrl_SetEditable, 1855).
--define(wxTextCtrl_SetInsertionPoint, 1856).
--define(wxTextCtrl_SetInsertionPointEnd, 1857).
--define(wxTextCtrl_SetMaxLength, 1859).
--define(wxTextCtrl_SetSelection, 1860).
--define(wxTextCtrl_SetStyle, 1861).
--define(wxTextCtrl_SetValue, 1862).
--define(wxTextCtrl_ShowPosition, 1863).
--define(wxTextCtrl_Undo, 1864).
--define(wxTextCtrl_WriteText, 1865).
--define(wxTextCtrl_XYToPosition, 1866).
--define(wxNotebook_new_0, 1869).
--define(wxNotebook_new_3, 1870).
--define(wxNotebook_destruct, 1871).
--define(wxNotebook_AddPage, 1872).
--define(wxNotebook_AdvanceSelection, 1873).
--define(wxNotebook_AssignImageList, 1874).
--define(wxNotebook_Create, 1875).
--define(wxNotebook_DeleteAllPages, 1876).
--define(wxNotebook_DeletePage, 1877).
--define(wxNotebook_RemovePage, 1878).
--define(wxNotebook_GetCurrentPage, 1879).
--define(wxNotebook_GetImageList, 1880).
--define(wxNotebook_GetPage, 1882).
--define(wxNotebook_GetPageCount, 1883).
--define(wxNotebook_GetPageImage, 1884).
--define(wxNotebook_GetPageText, 1885).
--define(wxNotebook_GetRowCount, 1886).
--define(wxNotebook_GetSelection, 1887).
--define(wxNotebook_GetThemeBackgroundColour, 1888).
--define(wxNotebook_HitTest, 1890).
--define(wxNotebook_InsertPage, 1892).
--define(wxNotebook_SetImageList, 1893).
--define(wxNotebook_SetPadding, 1894).
--define(wxNotebook_SetPageSize, 1895).
--define(wxNotebook_SetPageImage, 1896).
--define(wxNotebook_SetPageText, 1897).
--define(wxNotebook_SetSelection, 1898).
--define(wxNotebook_ChangeSelection, 1899).
--define(wxChoicebook_new_0, 1900).
--define(wxChoicebook_new_3, 1901).
--define(wxChoicebook_AddPage, 1902).
--define(wxChoicebook_AdvanceSelection, 1903).
--define(wxChoicebook_AssignImageList, 1904).
--define(wxChoicebook_Create, 1905).
--define(wxChoicebook_DeleteAllPages, 1906).
--define(wxChoicebook_DeletePage, 1907).
--define(wxChoicebook_RemovePage, 1908).
--define(wxChoicebook_GetCurrentPage, 1909).
--define(wxChoicebook_GetImageList, 1910).
--define(wxChoicebook_GetPage, 1912).
--define(wxChoicebook_GetPageCount, 1913).
--define(wxChoicebook_GetPageImage, 1914).
--define(wxChoicebook_GetPageText, 1915).
--define(wxChoicebook_GetSelection, 1916).
--define(wxChoicebook_HitTest, 1917).
--define(wxChoicebook_InsertPage, 1918).
--define(wxChoicebook_SetImageList, 1919).
--define(wxChoicebook_SetPageSize, 1920).
--define(wxChoicebook_SetPageImage, 1921).
--define(wxChoicebook_SetPageText, 1922).
--define(wxChoicebook_SetSelection, 1923).
--define(wxChoicebook_ChangeSelection, 1924).
--define(wxChoicebook_destroy, 1925).
--define(wxToolbook_new_0, 1926).
--define(wxToolbook_new_3, 1927).
--define(wxToolbook_AddPage, 1928).
--define(wxToolbook_AdvanceSelection, 1929).
--define(wxToolbook_AssignImageList, 1930).
--define(wxToolbook_Create, 1931).
--define(wxToolbook_DeleteAllPages, 1932).
--define(wxToolbook_DeletePage, 1933).
--define(wxToolbook_RemovePage, 1934).
--define(wxToolbook_GetCurrentPage, 1935).
--define(wxToolbook_GetImageList, 1936).
--define(wxToolbook_GetPage, 1938).
--define(wxToolbook_GetPageCount, 1939).
--define(wxToolbook_GetPageImage, 1940).
--define(wxToolbook_GetPageText, 1941).
--define(wxToolbook_GetSelection, 1942).
--define(wxToolbook_HitTest, 1944).
--define(wxToolbook_InsertPage, 1945).
--define(wxToolbook_SetImageList, 1946).
--define(wxToolbook_SetPageSize, 1947).
--define(wxToolbook_SetPageImage, 1948).
--define(wxToolbook_SetPageText, 1949).
--define(wxToolbook_SetSelection, 1950).
--define(wxToolbook_ChangeSelection, 1951).
--define(wxToolbook_destroy, 1952).
--define(wxListbook_new_0, 1953).
--define(wxListbook_new_3, 1954).
--define(wxListbook_AddPage, 1955).
--define(wxListbook_AdvanceSelection, 1956).
--define(wxListbook_AssignImageList, 1957).
--define(wxListbook_Create, 1958).
--define(wxListbook_DeleteAllPages, 1959).
--define(wxListbook_DeletePage, 1960).
--define(wxListbook_RemovePage, 1961).
--define(wxListbook_GetCurrentPage, 1962).
--define(wxListbook_GetImageList, 1963).
--define(wxListbook_GetPage, 1965).
--define(wxListbook_GetPageCount, 1966).
--define(wxListbook_GetPageImage, 1967).
--define(wxListbook_GetPageText, 1968).
--define(wxListbook_GetSelection, 1969).
--define(wxListbook_HitTest, 1971).
--define(wxListbook_InsertPage, 1972).
--define(wxListbook_SetImageList, 1973).
--define(wxListbook_SetPageSize, 1974).
--define(wxListbook_SetPageImage, 1975).
--define(wxListbook_SetPageText, 1976).
--define(wxListbook_SetSelection, 1977).
--define(wxListbook_ChangeSelection, 1978).
--define(wxListbook_destroy, 1979).
--define(wxTreebook_new_0, 1980).
--define(wxTreebook_new_3, 1981).
--define(wxTreebook_AddPage, 1982).
--define(wxTreebook_AdvanceSelection, 1983).
--define(wxTreebook_AssignImageList, 1984).
--define(wxTreebook_Create, 1985).
--define(wxTreebook_DeleteAllPages, 1986).
--define(wxTreebook_DeletePage, 1987).
--define(wxTreebook_RemovePage, 1988).
--define(wxTreebook_GetCurrentPage, 1989).
--define(wxTreebook_GetImageList, 1990).
--define(wxTreebook_GetPage, 1992).
--define(wxTreebook_GetPageCount, 1993).
--define(wxTreebook_GetPageImage, 1994).
--define(wxTreebook_GetPageText, 1995).
--define(wxTreebook_GetSelection, 1996).
--define(wxTreebook_ExpandNode, 1997).
--define(wxTreebook_IsNodeExpanded, 1998).
--define(wxTreebook_HitTest, 2000).
--define(wxTreebook_InsertPage, 2001).
--define(wxTreebook_InsertSubPage, 2002).
--define(wxTreebook_SetImageList, 2003).
--define(wxTreebook_SetPageSize, 2004).
--define(wxTreebook_SetPageImage, 2005).
--define(wxTreebook_SetPageText, 2006).
--define(wxTreebook_SetSelection, 2007).
--define(wxTreebook_ChangeSelection, 2008).
--define(wxTreebook_destroy, 2009).
--define(wxTreeCtrl_new_2, 2012).
--define(wxTreeCtrl_new_0, 2013).
--define(wxTreeCtrl_destruct, 2015).
--define(wxTreeCtrl_AddRoot, 2016).
--define(wxTreeCtrl_AppendItem, 2017).
--define(wxTreeCtrl_AssignImageList, 2018).
--define(wxTreeCtrl_AssignStateImageList, 2019).
--define(wxTreeCtrl_Collapse, 2020).
--define(wxTreeCtrl_CollapseAndReset, 2021).
--define(wxTreeCtrl_Create, 2022).
--define(wxTreeCtrl_Delete, 2023).
--define(wxTreeCtrl_DeleteAllItems, 2024).
--define(wxTreeCtrl_DeleteChildren, 2025).
--define(wxTreeCtrl_EditLabel, 2026).
--define(wxTreeCtrl_EnsureVisible, 2027).
--define(wxTreeCtrl_Expand, 2028).
--define(wxTreeCtrl_GetBoundingRect, 2029).
--define(wxTreeCtrl_GetChildrenCount, 2031).
--define(wxTreeCtrl_GetCount, 2032).
--define(wxTreeCtrl_GetEditControl, 2033).
--define(wxTreeCtrl_GetFirstChild, 2034).
--define(wxTreeCtrl_GetNextChild, 2035).
--define(wxTreeCtrl_GetFirstVisibleItem, 2036).
--define(wxTreeCtrl_GetImageList, 2037).
--define(wxTreeCtrl_GetIndent, 2038).
--define(wxTreeCtrl_GetItemBackgroundColour, 2039).
--define(wxTreeCtrl_GetItemData, 2040).
--define(wxTreeCtrl_GetItemFont, 2041).
--define(wxTreeCtrl_GetItemImage_1, 2042).
--define(wxTreeCtrl_GetItemImage_2, 2043).
--define(wxTreeCtrl_GetItemText, 2044).
--define(wxTreeCtrl_GetItemTextColour, 2045).
--define(wxTreeCtrl_GetLastChild, 2046).
--define(wxTreeCtrl_GetNextSibling, 2047).
--define(wxTreeCtrl_GetNextVisible, 2048).
--define(wxTreeCtrl_GetItemParent, 2049).
--define(wxTreeCtrl_GetPrevSibling, 2050).
--define(wxTreeCtrl_GetPrevVisible, 2051).
--define(wxTreeCtrl_GetRootItem, 2052).
--define(wxTreeCtrl_GetSelection, 2053).
--define(wxTreeCtrl_GetSelections, 2054).
--define(wxTreeCtrl_GetStateImageList, 2055).
--define(wxTreeCtrl_HitTest, 2056).
--define(wxTreeCtrl_InsertItem, 2058).
--define(wxTreeCtrl_IsBold, 2059).
--define(wxTreeCtrl_IsExpanded, 2060).
--define(wxTreeCtrl_IsSelected, 2061).
--define(wxTreeCtrl_IsVisible, 2062).
--define(wxTreeCtrl_ItemHasChildren, 2063).
--define(wxTreeCtrl_IsTreeItemIdOk, 2064).
--define(wxTreeCtrl_PrependItem, 2065).
--define(wxTreeCtrl_ScrollTo, 2066).
--define(wxTreeCtrl_SelectItem_1, 2067).
--define(wxTreeCtrl_SelectItem_2, 2068).
--define(wxTreeCtrl_SetIndent, 2069).
--define(wxTreeCtrl_SetImageList, 2070).
--define(wxTreeCtrl_SetItemBackgroundColour, 2071).
--define(wxTreeCtrl_SetItemBold, 2072).
--define(wxTreeCtrl_SetItemData, 2073).
--define(wxTreeCtrl_SetItemDropHighlight, 2074).
--define(wxTreeCtrl_SetItemFont, 2075).
--define(wxTreeCtrl_SetItemHasChildren, 2076).
--define(wxTreeCtrl_SetItemImage_2, 2077).
--define(wxTreeCtrl_SetItemImage_3, 2078).
--define(wxTreeCtrl_SetItemText, 2079).
--define(wxTreeCtrl_SetItemTextColour, 2080).
--define(wxTreeCtrl_SetStateImageList, 2081).
--define(wxTreeCtrl_SetWindowStyle, 2082).
--define(wxTreeCtrl_SortChildren, 2083).
--define(wxTreeCtrl_Toggle, 2084).
--define(wxTreeCtrl_ToggleItemSelection, 2085).
--define(wxTreeCtrl_Unselect, 2086).
--define(wxTreeCtrl_UnselectAll, 2087).
--define(wxTreeCtrl_UnselectItem, 2088).
--define(wxScrollBar_new_0, 2089).
--define(wxScrollBar_new_3, 2090).
--define(wxScrollBar_destruct, 2091).
--define(wxScrollBar_Create, 2092).
--define(wxScrollBar_GetRange, 2093).
--define(wxScrollBar_GetPageSize, 2094).
--define(wxScrollBar_GetThumbPosition, 2095).
--define(wxScrollBar_GetThumbSize, 2096).
--define(wxScrollBar_SetThumbPosition, 2097).
--define(wxScrollBar_SetScrollbar, 2098).
--define(wxSpinButton_new_2, 2100).
--define(wxSpinButton_new_0, 2101).
--define(wxSpinButton_Create, 2102).
--define(wxSpinButton_GetMax, 2103).
--define(wxSpinButton_GetMin, 2104).
--define(wxSpinButton_GetValue, 2105).
--define(wxSpinButton_SetRange, 2106).
--define(wxSpinButton_SetValue, 2107).
--define(wxSpinButton_destroy, 2108).
--define(wxSpinCtrl_new_0, 2109).
--define(wxSpinCtrl_new_2, 2110).
--define(wxSpinCtrl_Create, 2112).
--define(wxSpinCtrl_SetValue_1_1, 2115).
--define(wxSpinCtrl_SetValue_1_0, 2116).
--define(wxSpinCtrl_GetValue, 2118).
--define(wxSpinCtrl_SetRange, 2120).
--define(wxSpinCtrl_SetSelection, 2121).
--define(wxSpinCtrl_GetMin, 2123).
--define(wxSpinCtrl_GetMax, 2125).
--define(wxSpinCtrl_destroy, 2126).
--define(wxStaticText_new_0, 2127).
--define(wxStaticText_new_4, 2128).
--define(wxStaticText_Create, 2129).
--define(wxStaticText_GetLabel, 2130).
--define(wxStaticText_SetLabel, 2131).
--define(wxStaticText_Wrap, 2132).
--define(wxStaticText_destroy, 2133).
--define(wxStaticBitmap_new_0, 2134).
--define(wxStaticBitmap_new_4, 2135).
--define(wxStaticBitmap_Create, 2136).
--define(wxStaticBitmap_GetBitmap, 2137).
--define(wxStaticBitmap_SetBitmap, 2138).
--define(wxStaticBitmap_destroy, 2139).
--define(wxRadioBox_new, 2140).
--define(wxRadioBox_destruct, 2142).
--define(wxRadioBox_Create, 2143).
--define(wxRadioBox_Enable_2, 2144).
--define(wxRadioBox_Enable_1, 2145).
--define(wxRadioBox_GetSelection, 2146).
--define(wxRadioBox_GetString, 2147).
--define(wxRadioBox_SetSelection, 2148).
--define(wxRadioBox_Show_2, 2149).
--define(wxRadioBox_Show_1, 2150).
--define(wxRadioBox_GetColumnCount, 2151).
--define(wxRadioBox_GetItemHelpText, 2152).
--define(wxRadioBox_GetItemToolTip, 2153).
--define(wxRadioBox_GetItemFromPoint, 2155).
--define(wxRadioBox_GetRowCount, 2156).
--define(wxRadioBox_IsItemEnabled, 2157).
--define(wxRadioBox_IsItemShown, 2158).
--define(wxRadioBox_SetItemHelpText, 2159).
--define(wxRadioBox_SetItemToolTip, 2160).
--define(wxRadioButton_new_0, 2161).
--define(wxRadioButton_new_4, 2162).
--define(wxRadioButton_Create, 2163).
--define(wxRadioButton_GetValue, 2164).
--define(wxRadioButton_SetValue, 2165).
--define(wxRadioButton_destroy, 2166).
--define(wxSlider_new_6, 2168).
--define(wxSlider_new_0, 2169).
--define(wxSlider_Create, 2170).
--define(wxSlider_GetLineSize, 2171).
--define(wxSlider_GetMax, 2172).
--define(wxSlider_GetMin, 2173).
--define(wxSlider_GetPageSize, 2174).
--define(wxSlider_GetThumbLength, 2175).
--define(wxSlider_GetValue, 2176).
--define(wxSlider_SetLineSize, 2177).
--define(wxSlider_SetPageSize, 2178).
--define(wxSlider_SetRange, 2179).
--define(wxSlider_SetThumbLength, 2180).
--define(wxSlider_SetValue, 2181).
--define(wxSlider_destroy, 2182).
--define(wxDialog_new_4, 2184).
--define(wxDialog_new_0, 2185).
--define(wxDialog_destruct, 2187).
--define(wxDialog_Create, 2188).
--define(wxDialog_CreateButtonSizer, 2189).
--define(wxDialog_CreateStdDialogButtonSizer, 2190).
--define(wxDialog_EndModal, 2191).
--define(wxDialog_GetAffirmativeId, 2192).
--define(wxDialog_GetReturnCode, 2193).
--define(wxDialog_IsModal, 2194).
--define(wxDialog_SetAffirmativeId, 2195).
--define(wxDialog_SetReturnCode, 2196).
--define(wxDialog_Show, 2197).
--define(wxDialog_ShowModal, 2198).
--define(wxColourDialog_new_0, 2199).
--define(wxColourDialog_new_2, 2200).
--define(wxColourDialog_destruct, 2201).
--define(wxColourDialog_Create, 2202).
--define(wxColourDialog_GetColourData, 2203).
--define(wxColourData_new_0, 2204).
--define(wxColourData_new_1, 2205).
--define(wxColourData_destruct, 2206).
--define(wxColourData_GetChooseFull, 2207).
--define(wxColourData_GetColour, 2208).
--define(wxColourData_GetCustomColour, 2210).
--define(wxColourData_SetChooseFull, 2211).
--define(wxColourData_SetColour, 2212).
--define(wxColourData_SetCustomColour, 2213).
--define(wxPalette_new_0, 2214).
--define(wxPalette_new_4, 2215).
--define(wxPalette_destruct, 2217).
--define(wxPalette_Create, 2218).
--define(wxPalette_GetColoursCount, 2219).
--define(wxPalette_GetPixel, 2220).
--define(wxPalette_GetRGB, 2221).
--define(wxPalette_IsOk, 2222).
--define(wxDirDialog_new, 2226).
--define(wxDirDialog_destruct, 2227).
--define(wxDirDialog_GetPath, 2228).
--define(wxDirDialog_GetMessage, 2229).
--define(wxDirDialog_SetMessage, 2230).
--define(wxDirDialog_SetPath, 2231).
--define(wxFileDialog_new, 2235).
--define(wxFileDialog_destruct, 2236).
--define(wxFileDialog_GetDirectory, 2237).
--define(wxFileDialog_GetFilename, 2238).
--define(wxFileDialog_GetFilenames, 2239).
--define(wxFileDialog_GetFilterIndex, 2240).
--define(wxFileDialog_GetMessage, 2241).
--define(wxFileDialog_GetPath, 2242).
--define(wxFileDialog_GetPaths, 2243).
--define(wxFileDialog_GetWildcard, 2244).
--define(wxFileDialog_SetDirectory, 2245).
--define(wxFileDialog_SetFilename, 2246).
--define(wxFileDialog_SetFilterIndex, 2247).
--define(wxFileDialog_SetMessage, 2248).
--define(wxFileDialog_SetPath, 2249).
--define(wxFileDialog_SetWildcard, 2250).
--define(wxPickerBase_SetInternalMargin, 2251).
--define(wxPickerBase_GetInternalMargin, 2252).
--define(wxPickerBase_SetTextCtrlProportion, 2253).
--define(wxPickerBase_SetPickerCtrlProportion, 2254).
--define(wxPickerBase_GetTextCtrlProportion, 2255).
--define(wxPickerBase_GetPickerCtrlProportion, 2256).
--define(wxPickerBase_HasTextCtrl, 2257).
--define(wxPickerBase_GetTextCtrl, 2258).
--define(wxPickerBase_IsTextCtrlGrowable, 2259).
--define(wxPickerBase_SetPickerCtrlGrowable, 2260).
--define(wxPickerBase_SetTextCtrlGrowable, 2261).
--define(wxPickerBase_IsPickerCtrlGrowable, 2262).
--define(wxFilePickerCtrl_new_0, 2263).
--define(wxFilePickerCtrl_new_3, 2264).
--define(wxFilePickerCtrl_Create, 2265).
--define(wxFilePickerCtrl_GetPath, 2266).
--define(wxFilePickerCtrl_SetPath, 2267).
--define(wxFilePickerCtrl_destroy, 2268).
--define(wxDirPickerCtrl_new_0, 2269).
--define(wxDirPickerCtrl_new_3, 2270).
--define(wxDirPickerCtrl_Create, 2271).
--define(wxDirPickerCtrl_GetPath, 2272).
--define(wxDirPickerCtrl_SetPath, 2273).
--define(wxDirPickerCtrl_destroy, 2274).
--define(wxColourPickerCtrl_new_0, 2275).
--define(wxColourPickerCtrl_new_3, 2276).
--define(wxColourPickerCtrl_Create, 2277).
--define(wxColourPickerCtrl_GetColour, 2278).
--define(wxColourPickerCtrl_SetColour_1_1, 2279).
--define(wxColourPickerCtrl_SetColour_1_0, 2280).
--define(wxColourPickerCtrl_destroy, 2281).
--define(wxDatePickerCtrl_new_0, 2282).
--define(wxDatePickerCtrl_new_3, 2283).
--define(wxDatePickerCtrl_GetRange, 2284).
--define(wxDatePickerCtrl_GetValue, 2285).
--define(wxDatePickerCtrl_SetRange, 2286).
--define(wxDatePickerCtrl_SetValue, 2287).
--define(wxDatePickerCtrl_destroy, 2288).
--define(wxFontPickerCtrl_new_0, 2289).
--define(wxFontPickerCtrl_new_3, 2290).
--define(wxFontPickerCtrl_Create, 2291).
--define(wxFontPickerCtrl_GetSelectedFont, 2292).
--define(wxFontPickerCtrl_SetSelectedFont, 2293).
--define(wxFontPickerCtrl_GetMaxPointSize, 2294).
--define(wxFontPickerCtrl_SetMaxPointSize, 2295).
--define(wxFontPickerCtrl_destroy, 2296).
--define(wxFindReplaceDialog_new_0, 2299).
--define(wxFindReplaceDialog_new_4, 2300).
--define(wxFindReplaceDialog_destruct, 2301).
--define(wxFindReplaceDialog_Create, 2302).
--define(wxFindReplaceDialog_GetData, 2303).
--define(wxFindReplaceData_new_0, 2304).
--define(wxFindReplaceData_new_1, 2305).
--define(wxFindReplaceData_GetFindString, 2306).
--define(wxFindReplaceData_GetReplaceString, 2307).
--define(wxFindReplaceData_GetFlags, 2308).
--define(wxFindReplaceData_SetFlags, 2309).
--define(wxFindReplaceData_SetFindString, 2310).
--define(wxFindReplaceData_SetReplaceString, 2311).
--define(wxFindReplaceData_destroy, 2312).
--define(wxMultiChoiceDialog_new_0, 2313).
--define(wxMultiChoiceDialog_new_5, 2315).
--define(wxMultiChoiceDialog_GetSelections, 2316).
--define(wxMultiChoiceDialog_SetSelections, 2317).
--define(wxMultiChoiceDialog_destroy, 2318).
--define(wxSingleChoiceDialog_new_0, 2319).
--define(wxSingleChoiceDialog_new_5, 2321).
--define(wxSingleChoiceDialog_GetSelection, 2322).
--define(wxSingleChoiceDialog_GetStringSelection, 2323).
--define(wxSingleChoiceDialog_SetSelection, 2324).
--define(wxSingleChoiceDialog_destroy, 2325).
--define(wxTextEntryDialog_new, 2326).
--define(wxTextEntryDialog_GetValue, 2327).
--define(wxTextEntryDialog_SetValue, 2328).
--define(wxTextEntryDialog_destroy, 2329).
--define(wxPasswordEntryDialog_new, 2330).
--define(wxPasswordEntryDialog_destroy, 2331).
--define(wxFontData_new_0, 2332).
--define(wxFontData_new_1, 2333).
--define(wxFontData_destruct, 2334).
--define(wxFontData_EnableEffects, 2335).
--define(wxFontData_GetAllowSymbols, 2336).
--define(wxFontData_GetColour, 2337).
--define(wxFontData_GetChosenFont, 2338).
--define(wxFontData_GetEnableEffects, 2339).
--define(wxFontData_GetInitialFont, 2340).
--define(wxFontData_GetShowHelp, 2341).
--define(wxFontData_SetAllowSymbols, 2342).
--define(wxFontData_SetChosenFont, 2343).
--define(wxFontData_SetColour, 2344).
--define(wxFontData_SetInitialFont, 2345).
--define(wxFontData_SetRange, 2346).
--define(wxFontData_SetShowHelp, 2347).
--define(wxFontDialog_new_0, 2351).
--define(wxFontDialog_new_2, 2353).
--define(wxFontDialog_Create, 2355).
--define(wxFontDialog_GetFontData, 2356).
--define(wxFontDialog_destroy, 2358).
--define(wxProgressDialog_new, 2359).
--define(wxProgressDialog_destruct, 2360).
--define(wxProgressDialog_Resume, 2361).
--define(wxProgressDialog_Update_2, 2362).
--define(wxProgressDialog_Update_0, 2363).
--define(wxMessageDialog_new, 2364).
--define(wxMessageDialog_destruct, 2365).
--define(wxPageSetupDialog_new, 2366).
--define(wxPageSetupDialog_destruct, 2367).
--define(wxPageSetupDialog_GetPageSetupData, 2368).
--define(wxPageSetupDialog_ShowModal, 2369).
--define(wxPageSetupDialogData_new_0, 2370).
--define(wxPageSetupDialogData_new_1_0, 2371).
--define(wxPageSetupDialogData_new_1_1, 2372).
--define(wxPageSetupDialogData_destruct, 2373).
--define(wxPageSetupDialogData_EnableHelp, 2374).
--define(wxPageSetupDialogData_EnableMargins, 2375).
--define(wxPageSetupDialogData_EnableOrientation, 2376).
--define(wxPageSetupDialogData_EnablePaper, 2377).
--define(wxPageSetupDialogData_EnablePrinter, 2378).
--define(wxPageSetupDialogData_GetDefaultMinMargins, 2379).
--define(wxPageSetupDialogData_GetEnableMargins, 2380).
--define(wxPageSetupDialogData_GetEnableOrientation, 2381).
--define(wxPageSetupDialogData_GetEnablePaper, 2382).
--define(wxPageSetupDialogData_GetEnablePrinter, 2383).
--define(wxPageSetupDialogData_GetEnableHelp, 2384).
--define(wxPageSetupDialogData_GetDefaultInfo, 2385).
--define(wxPageSetupDialogData_GetMarginTopLeft, 2386).
--define(wxPageSetupDialogData_GetMarginBottomRight, 2387).
--define(wxPageSetupDialogData_GetMinMarginTopLeft, 2388).
--define(wxPageSetupDialogData_GetMinMarginBottomRight, 2389).
--define(wxPageSetupDialogData_GetPaperId, 2390).
--define(wxPageSetupDialogData_GetPaperSize, 2391).
--define(wxPageSetupDialogData_GetPrintData, 2393).
--define(wxPageSetupDialogData_IsOk, 2394).
--define(wxPageSetupDialogData_SetDefaultInfo, 2395).
--define(wxPageSetupDialogData_SetDefaultMinMargins, 2396).
--define(wxPageSetupDialogData_SetMarginTopLeft, 2397).
--define(wxPageSetupDialogData_SetMarginBottomRight, 2398).
--define(wxPageSetupDialogData_SetMinMarginTopLeft, 2399).
--define(wxPageSetupDialogData_SetMinMarginBottomRight, 2400).
--define(wxPageSetupDialogData_SetPaperId, 2401).
--define(wxPageSetupDialogData_SetPaperSize_1_1, 2402).
--define(wxPageSetupDialogData_SetPaperSize_1_0, 2403).
--define(wxPageSetupDialogData_SetPrintData, 2404).
--define(wxPrintDialog_new_2_0, 2405).
--define(wxPrintDialog_new_2_1, 2406).
--define(wxPrintDialog_destruct, 2407).
--define(wxPrintDialog_GetPrintDialogData, 2408).
--define(wxPrintDialog_GetPrintDC, 2409).
--define(wxPrintDialogData_new_0, 2410).
--define(wxPrintDialogData_new_1_1, 2411).
--define(wxPrintDialogData_new_1_0, 2412).
--define(wxPrintDialogData_destruct, 2413).
--define(wxPrintDialogData_EnableHelp, 2414).
--define(wxPrintDialogData_EnablePageNumbers, 2415).
--define(wxPrintDialogData_EnablePrintToFile, 2416).
--define(wxPrintDialogData_EnableSelection, 2417).
--define(wxPrintDialogData_GetAllPages, 2418).
--define(wxPrintDialogData_GetCollate, 2419).
--define(wxPrintDialogData_GetFromPage, 2420).
--define(wxPrintDialogData_GetMaxPage, 2421).
--define(wxPrintDialogData_GetMinPage, 2422).
--define(wxPrintDialogData_GetNoCopies, 2423).
--define(wxPrintDialogData_GetPrintData, 2424).
--define(wxPrintDialogData_GetPrintToFile, 2425).
--define(wxPrintDialogData_GetSelection, 2426).
--define(wxPrintDialogData_GetToPage, 2427).
--define(wxPrintDialogData_IsOk, 2428).
--define(wxPrintDialogData_SetCollate, 2429).
--define(wxPrintDialogData_SetFromPage, 2430).
--define(wxPrintDialogData_SetMaxPage, 2431).
--define(wxPrintDialogData_SetMinPage, 2432).
--define(wxPrintDialogData_SetNoCopies, 2433).
--define(wxPrintDialogData_SetPrintData, 2434).
--define(wxPrintDialogData_SetPrintToFile, 2435).
--define(wxPrintDialogData_SetSelection, 2436).
--define(wxPrintDialogData_SetToPage, 2437).
--define(wxPrintData_new_0, 2438).
--define(wxPrintData_new_1, 2439).
--define(wxPrintData_destruct, 2440).
--define(wxPrintData_GetCollate, 2441).
--define(wxPrintData_GetBin, 2442).
--define(wxPrintData_GetColour, 2443).
--define(wxPrintData_GetDuplex, 2444).
--define(wxPrintData_GetNoCopies, 2445).
--define(wxPrintData_GetOrientation, 2446).
--define(wxPrintData_GetPaperId, 2447).
--define(wxPrintData_GetPrinterName, 2448).
--define(wxPrintData_GetQuality, 2449).
--define(wxPrintData_IsOk, 2450).
--define(wxPrintData_SetBin, 2451).
--define(wxPrintData_SetCollate, 2452).
--define(wxPrintData_SetColour, 2453).
--define(wxPrintData_SetDuplex, 2454).
--define(wxPrintData_SetNoCopies, 2455).
--define(wxPrintData_SetOrientation, 2456).
--define(wxPrintData_SetPaperId, 2457).
--define(wxPrintData_SetPrinterName, 2458).
--define(wxPrintData_SetQuality, 2459).
--define(wxPrintPreview_new_2, 2462).
--define(wxPrintPreview_new_3, 2463).
--define(wxPrintPreview_destruct, 2465).
--define(wxPrintPreview_GetCanvas, 2466).
--define(wxPrintPreview_GetCurrentPage, 2467).
--define(wxPrintPreview_GetFrame, 2468).
--define(wxPrintPreview_GetMaxPage, 2469).
--define(wxPrintPreview_GetMinPage, 2470).
--define(wxPrintPreview_GetPrintout, 2471).
--define(wxPrintPreview_GetPrintoutForPrinting, 2472).
--define(wxPrintPreview_IsOk, 2473).
--define(wxPrintPreview_PaintPage, 2474).
--define(wxPrintPreview_Print, 2475).
--define(wxPrintPreview_RenderPage, 2476).
--define(wxPrintPreview_SetCanvas, 2477).
--define(wxPrintPreview_SetCurrentPage, 2478).
--define(wxPrintPreview_SetFrame, 2479).
--define(wxPrintPreview_SetPrintout, 2480).
--define(wxPrintPreview_SetZoom, 2481).
--define(wxPreviewFrame_new, 2482).
--define(wxPreviewFrame_destruct, 2483).
--define(wxPreviewFrame_CreateControlBar, 2484).
--define(wxPreviewFrame_CreateCanvas, 2485).
--define(wxPreviewFrame_Initialize, 2486).
--define(wxPreviewFrame_OnCloseWindow, 2487).
--define(wxPreviewControlBar_new, 2488).
--define(wxPreviewControlBar_destruct, 2489).
--define(wxPreviewControlBar_CreateButtons, 2490).
--define(wxPreviewControlBar_GetPrintPreview, 2491).
--define(wxPreviewControlBar_GetZoomControl, 2492).
--define(wxPreviewControlBar_SetZoomControl, 2493).
--define(wxPrinter_new, 2495).
--define(wxPrinter_CreateAbortWindow, 2496).
--define(wxPrinter_GetAbort, 2497).
--define(wxPrinter_GetLastError, 2498).
--define(wxPrinter_GetPrintDialogData, 2499).
--define(wxPrinter_Print, 2500).
--define(wxPrinter_PrintDialog, 2501).
--define(wxPrinter_ReportError, 2502).
--define(wxPrinter_Setup, 2503).
--define(wxPrinter_destroy, 2504).
--define(wxXmlResource_new_1, 2505).
--define(wxXmlResource_new_2, 2506).
--define(wxXmlResource_destruct, 2507).
--define(wxXmlResource_AttachUnknownControl, 2508).
--define(wxXmlResource_ClearHandlers, 2509).
--define(wxXmlResource_CompareVersion, 2510).
--define(wxXmlResource_Get, 2511).
--define(wxXmlResource_GetFlags, 2512).
--define(wxXmlResource_GetVersion, 2513).
--define(wxXmlResource_GetXRCID, 2514).
--define(wxXmlResource_InitAllHandlers, 2515).
--define(wxXmlResource_Load, 2516).
--define(wxXmlResource_LoadBitmap, 2517).
--define(wxXmlResource_LoadDialog_2, 2518).
--define(wxXmlResource_LoadDialog_3, 2519).
--define(wxXmlResource_LoadFrame_2, 2520).
--define(wxXmlResource_LoadFrame_3, 2521).
--define(wxXmlResource_LoadIcon, 2522).
--define(wxXmlResource_LoadMenu, 2523).
--define(wxXmlResource_LoadMenuBar_2, 2524).
--define(wxXmlResource_LoadMenuBar_1, 2525).
--define(wxXmlResource_LoadPanel_2, 2526).
--define(wxXmlResource_LoadPanel_3, 2527).
--define(wxXmlResource_LoadToolBar, 2528).
--define(wxXmlResource_Set, 2529).
--define(wxXmlResource_SetFlags, 2530).
--define(wxXmlResource_Unload, 2531).
--define(wxXmlResource_xrcctrl, 2532).
--define(wxHtmlEasyPrinting_new, 2533).
--define(wxHtmlEasyPrinting_destruct, 2534).
--define(wxHtmlEasyPrinting_GetPrintData, 2535).
--define(wxHtmlEasyPrinting_GetPageSetupData, 2536).
--define(wxHtmlEasyPrinting_PreviewFile, 2537).
--define(wxHtmlEasyPrinting_PreviewText, 2538).
--define(wxHtmlEasyPrinting_PrintFile, 2539).
--define(wxHtmlEasyPrinting_PrintText, 2540).
--define(wxHtmlEasyPrinting_PageSetup, 2541).
--define(wxHtmlEasyPrinting_SetFonts, 2542).
--define(wxHtmlEasyPrinting_SetHeader, 2543).
--define(wxHtmlEasyPrinting_SetFooter, 2544).
--define(wxGLCanvas_new_2, 2546).
--define(wxGLCanvas_new_3_1, 2547).
--define(wxGLCanvas_new_3_0, 2548).
--define(wxGLCanvas_GetContext, 2549).
--define(wxGLCanvas_SetCurrent, 2551).
--define(wxGLCanvas_SwapBuffers, 2552).
--define(wxGLCanvas_destroy, 2553).
--define(wxAuiManager_new, 2554).
--define(wxAuiManager_destruct, 2555).
--define(wxAuiManager_AddPane_2_1, 2556).
--define(wxAuiManager_AddPane_3, 2557).
--define(wxAuiManager_AddPane_2_0, 2558).
--define(wxAuiManager_DetachPane, 2559).
--define(wxAuiManager_GetAllPanes, 2560).
--define(wxAuiManager_GetArtProvider, 2561).
--define(wxAuiManager_GetDockSizeConstraint, 2562).
--define(wxAuiManager_GetFlags, 2563).
--define(wxAuiManager_GetManagedWindow, 2564).
--define(wxAuiManager_GetManager, 2565).
--define(wxAuiManager_GetPane_1_1, 2566).
--define(wxAuiManager_GetPane_1_0, 2567).
--define(wxAuiManager_HideHint, 2568).
--define(wxAuiManager_InsertPane, 2569).
--define(wxAuiManager_LoadPaneInfo, 2570).
--define(wxAuiManager_LoadPerspective, 2571).
--define(wxAuiManager_SavePaneInfo, 2572).
--define(wxAuiManager_SavePerspective, 2573).
--define(wxAuiManager_SetArtProvider, 2574).
--define(wxAuiManager_SetDockSizeConstraint, 2575).
--define(wxAuiManager_SetFlags, 2576).
--define(wxAuiManager_SetManagedWindow, 2577).
--define(wxAuiManager_ShowHint, 2578).
--define(wxAuiManager_UnInit, 2579).
--define(wxAuiManager_Update, 2580).
--define(wxAuiPaneInfo_new_0, 2581).
--define(wxAuiPaneInfo_new_1, 2582).
--define(wxAuiPaneInfo_destruct, 2583).
--define(wxAuiPaneInfo_BestSize_1, 2584).
--define(wxAuiPaneInfo_BestSize_2, 2585).
--define(wxAuiPaneInfo_Bottom, 2586).
--define(wxAuiPaneInfo_BottomDockable, 2587).
--define(wxAuiPaneInfo_Caption, 2588).
--define(wxAuiPaneInfo_CaptionVisible, 2589).
--define(wxAuiPaneInfo_Centre, 2590).
--define(wxAuiPaneInfo_CentrePane, 2591).
--define(wxAuiPaneInfo_CloseButton, 2592).
--define(wxAuiPaneInfo_DefaultPane, 2593).
--define(wxAuiPaneInfo_DestroyOnClose, 2594).
--define(wxAuiPaneInfo_Direction, 2595).
--define(wxAuiPaneInfo_Dock, 2596).
--define(wxAuiPaneInfo_Dockable, 2597).
--define(wxAuiPaneInfo_Fixed, 2598).
--define(wxAuiPaneInfo_Float, 2599).
--define(wxAuiPaneInfo_Floatable, 2600).
--define(wxAuiPaneInfo_FloatingPosition_1, 2601).
--define(wxAuiPaneInfo_FloatingPosition_2, 2602).
--define(wxAuiPaneInfo_FloatingSize_1, 2603).
--define(wxAuiPaneInfo_FloatingSize_2, 2604).
--define(wxAuiPaneInfo_Gripper, 2605).
--define(wxAuiPaneInfo_GripperTop, 2606).
--define(wxAuiPaneInfo_HasBorder, 2607).
--define(wxAuiPaneInfo_HasCaption, 2608).
--define(wxAuiPaneInfo_HasCloseButton, 2609).
--define(wxAuiPaneInfo_HasFlag, 2610).
--define(wxAuiPaneInfo_HasGripper, 2611).
--define(wxAuiPaneInfo_HasGripperTop, 2612).
--define(wxAuiPaneInfo_HasMaximizeButton, 2613).
--define(wxAuiPaneInfo_HasMinimizeButton, 2614).
--define(wxAuiPaneInfo_HasPinButton, 2615).
--define(wxAuiPaneInfo_Hide, 2616).
--define(wxAuiPaneInfo_IsBottomDockable, 2617).
--define(wxAuiPaneInfo_IsDocked, 2618).
--define(wxAuiPaneInfo_IsFixed, 2619).
--define(wxAuiPaneInfo_IsFloatable, 2620).
--define(wxAuiPaneInfo_IsFloating, 2621).
--define(wxAuiPaneInfo_IsLeftDockable, 2622).
--define(wxAuiPaneInfo_IsMovable, 2623).
--define(wxAuiPaneInfo_IsOk, 2624).
--define(wxAuiPaneInfo_IsResizable, 2625).
--define(wxAuiPaneInfo_IsRightDockable, 2626).
--define(wxAuiPaneInfo_IsShown, 2627).
--define(wxAuiPaneInfo_IsToolbar, 2628).
--define(wxAuiPaneInfo_IsTopDockable, 2629).
--define(wxAuiPaneInfo_Layer, 2630).
--define(wxAuiPaneInfo_Left, 2631).
--define(wxAuiPaneInfo_LeftDockable, 2632).
--define(wxAuiPaneInfo_MaxSize_1, 2633).
--define(wxAuiPaneInfo_MaxSize_2, 2634).
--define(wxAuiPaneInfo_MaximizeButton, 2635).
--define(wxAuiPaneInfo_MinSize_1, 2636).
--define(wxAuiPaneInfo_MinSize_2, 2637).
--define(wxAuiPaneInfo_MinimizeButton, 2638).
--define(wxAuiPaneInfo_Movable, 2639).
--define(wxAuiPaneInfo_Name, 2640).
--define(wxAuiPaneInfo_PaneBorder, 2641).
--define(wxAuiPaneInfo_PinButton, 2642).
--define(wxAuiPaneInfo_Position, 2643).
--define(wxAuiPaneInfo_Resizable, 2644).
--define(wxAuiPaneInfo_Right, 2645).
--define(wxAuiPaneInfo_RightDockable, 2646).
--define(wxAuiPaneInfo_Row, 2647).
--define(wxAuiPaneInfo_SafeSet, 2648).
--define(wxAuiPaneInfo_SetFlag, 2649).
--define(wxAuiPaneInfo_Show, 2650).
--define(wxAuiPaneInfo_ToolbarPane, 2651).
--define(wxAuiPaneInfo_Top, 2652).
--define(wxAuiPaneInfo_TopDockable, 2653).
--define(wxAuiPaneInfo_Window, 2654).
--define(wxAuiPaneInfo_GetWindow, 2655).
--define(wxAuiPaneInfo_GetFrame, 2656).
--define(wxAuiPaneInfo_GetDirection, 2657).
--define(wxAuiPaneInfo_GetLayer, 2658).
--define(wxAuiPaneInfo_GetRow, 2659).
--define(wxAuiPaneInfo_GetPosition, 2660).
--define(wxAuiPaneInfo_GetFloatingPosition, 2661).
--define(wxAuiPaneInfo_GetFloatingSize, 2662).
--define(wxAuiNotebook_new_0, 2663).
--define(wxAuiNotebook_new_2, 2664).
--define(wxAuiNotebook_AddPage, 2665).
--define(wxAuiNotebook_Create, 2666).
--define(wxAuiNotebook_DeletePage, 2667).
--define(wxAuiNotebook_GetArtProvider, 2668).
--define(wxAuiNotebook_GetPage, 2669).
--define(wxAuiNotebook_GetPageBitmap, 2670).
--define(wxAuiNotebook_GetPageCount, 2671).
--define(wxAuiNotebook_GetPageIndex, 2672).
--define(wxAuiNotebook_GetPageText, 2673).
--define(wxAuiNotebook_GetSelection, 2674).
--define(wxAuiNotebook_InsertPage, 2675).
--define(wxAuiNotebook_RemovePage, 2676).
--define(wxAuiNotebook_SetArtProvider, 2677).
--define(wxAuiNotebook_SetFont, 2678).
--define(wxAuiNotebook_SetPageBitmap, 2679).
--define(wxAuiNotebook_SetPageText, 2680).
--define(wxAuiNotebook_SetSelection, 2681).
--define(wxAuiNotebook_SetTabCtrlHeight, 2682).
--define(wxAuiNotebook_SetUniformBitmapSize, 2683).
--define(wxAuiNotebook_destroy, 2684).
--define(wxAuiTabArt_SetFlags, 2685).
--define(wxAuiTabArt_SetMeasuringFont, 2686).
--define(wxAuiTabArt_SetNormalFont, 2687).
--define(wxAuiTabArt_SetSelectedFont, 2688).
--define(wxAuiTabArt_SetColour, 2689).
--define(wxAuiTabArt_SetActiveColour, 2690).
--define(wxAuiDockArt_GetColour, 2691).
--define(wxAuiDockArt_GetFont, 2692).
--define(wxAuiDockArt_GetMetric, 2693).
--define(wxAuiDockArt_SetColour, 2694).
--define(wxAuiDockArt_SetFont, 2695).
--define(wxAuiDockArt_SetMetric, 2696).
--define(wxAuiSimpleTabArt_new, 2697).
--define(wxAuiSimpleTabArt_destroy, 2698).
--define(wxMDIParentFrame_new_0, 2699).
--define(wxMDIParentFrame_new_4, 2700).
--define(wxMDIParentFrame_destruct, 2701).
--define(wxMDIParentFrame_ActivateNext, 2702).
--define(wxMDIParentFrame_ActivatePrevious, 2703).
--define(wxMDIParentFrame_ArrangeIcons, 2704).
--define(wxMDIParentFrame_Cascade, 2705).
--define(wxMDIParentFrame_Create, 2706).
--define(wxMDIParentFrame_GetActiveChild, 2707).
--define(wxMDIParentFrame_GetClientWindow, 2708).
--define(wxMDIParentFrame_Tile, 2709).
--define(wxMDIChildFrame_new_0, 2710).
--define(wxMDIChildFrame_new_4, 2711).
--define(wxMDIChildFrame_destruct, 2712).
--define(wxMDIChildFrame_Activate, 2713).
--define(wxMDIChildFrame_Create, 2714).
--define(wxMDIChildFrame_Maximize, 2715).
--define(wxMDIChildFrame_Restore, 2716).
--define(wxMDIClientWindow_new_0, 2717).
--define(wxMDIClientWindow_new_2, 2718).
--define(wxMDIClientWindow_destruct, 2719).
--define(wxMDIClientWindow_CreateClient, 2720).
--define(wxLayoutAlgorithm_new, 2721).
--define(wxLayoutAlgorithm_LayoutFrame, 2722).
--define(wxLayoutAlgorithm_LayoutMDIFrame, 2723).
--define(wxLayoutAlgorithm_LayoutWindow, 2724).
--define(wxLayoutAlgorithm_destroy, 2725).
--define(wxEvent_GetId, 2726).
--define(wxEvent_GetSkipped, 2727).
--define(wxEvent_GetTimestamp, 2728).
--define(wxEvent_IsCommandEvent, 2729).
--define(wxEvent_ResumePropagation, 2730).
--define(wxEvent_ShouldPropagate, 2731).
--define(wxEvent_Skip, 2732).
--define(wxEvent_StopPropagation, 2733).
--define(wxCommandEvent_getClientData, 2734).
--define(wxCommandEvent_GetExtraLong, 2735).
--define(wxCommandEvent_GetInt, 2736).
--define(wxCommandEvent_GetSelection, 2737).
--define(wxCommandEvent_GetString, 2738).
--define(wxCommandEvent_IsChecked, 2739).
--define(wxCommandEvent_IsSelection, 2740).
--define(wxCommandEvent_SetInt, 2741).
--define(wxCommandEvent_SetString, 2742).
--define(wxScrollEvent_GetOrientation, 2743).
--define(wxScrollEvent_GetPosition, 2744).
--define(wxScrollWinEvent_GetOrientation, 2745).
--define(wxScrollWinEvent_GetPosition, 2746).
--define(wxMouseEvent_AltDown, 2747).
--define(wxMouseEvent_Button, 2748).
--define(wxMouseEvent_ButtonDClick, 2749).
--define(wxMouseEvent_ButtonDown, 2750).
--define(wxMouseEvent_ButtonUp, 2751).
--define(wxMouseEvent_CmdDown, 2752).
--define(wxMouseEvent_ControlDown, 2753).
--define(wxMouseEvent_Dragging, 2754).
--define(wxMouseEvent_Entering, 2755).
--define(wxMouseEvent_GetButton, 2756).
--define(wxMouseEvent_GetPosition, 2759).
--define(wxMouseEvent_GetLogicalPosition, 2760).
--define(wxMouseEvent_GetLinesPerAction, 2761).
--define(wxMouseEvent_GetWheelRotation, 2762).
--define(wxMouseEvent_GetWheelDelta, 2763).
--define(wxMouseEvent_GetX, 2764).
--define(wxMouseEvent_GetY, 2765).
--define(wxMouseEvent_IsButton, 2766).
--define(wxMouseEvent_IsPageScroll, 2767).
--define(wxMouseEvent_Leaving, 2768).
--define(wxMouseEvent_LeftDClick, 2769).
--define(wxMouseEvent_LeftDown, 2770).
--define(wxMouseEvent_LeftIsDown, 2771).
--define(wxMouseEvent_LeftUp, 2772).
--define(wxMouseEvent_MetaDown, 2773).
--define(wxMouseEvent_MiddleDClick, 2774).
--define(wxMouseEvent_MiddleDown, 2775).
--define(wxMouseEvent_MiddleIsDown, 2776).
--define(wxMouseEvent_MiddleUp, 2777).
--define(wxMouseEvent_Moving, 2778).
--define(wxMouseEvent_RightDClick, 2779).
--define(wxMouseEvent_RightDown, 2780).
--define(wxMouseEvent_RightIsDown, 2781).
--define(wxMouseEvent_RightUp, 2782).
--define(wxMouseEvent_ShiftDown, 2783).
--define(wxSetCursorEvent_GetCursor, 2784).
--define(wxSetCursorEvent_GetX, 2785).
--define(wxSetCursorEvent_GetY, 2786).
--define(wxSetCursorEvent_HasCursor, 2787).
--define(wxSetCursorEvent_SetCursor, 2788).
--define(wxKeyEvent_AltDown, 2789).
--define(wxKeyEvent_CmdDown, 2790).
--define(wxKeyEvent_ControlDown, 2791).
--define(wxKeyEvent_GetKeyCode, 2792).
--define(wxKeyEvent_GetModifiers, 2793).
--define(wxKeyEvent_GetPosition, 2796).
--define(wxKeyEvent_GetRawKeyCode, 2797).
--define(wxKeyEvent_GetRawKeyFlags, 2798).
--define(wxKeyEvent_GetUnicodeKey, 2799).
--define(wxKeyEvent_GetX, 2800).
--define(wxKeyEvent_GetY, 2801).
--define(wxKeyEvent_HasModifiers, 2802).
--define(wxKeyEvent_MetaDown, 2803).
--define(wxKeyEvent_ShiftDown, 2804).
--define(wxSizeEvent_GetSize, 2805).
--define(wxMoveEvent_GetPosition, 2806).
--define(wxEraseEvent_GetDC, 2807).
--define(wxFocusEvent_GetWindow, 2808).
--define(wxChildFocusEvent_GetWindow, 2809).
--define(wxMenuEvent_GetMenu, 2810).
--define(wxMenuEvent_GetMenuId, 2811).
--define(wxMenuEvent_IsPopup, 2812).
--define(wxCloseEvent_CanVeto, 2813).
--define(wxCloseEvent_GetLoggingOff, 2814).
--define(wxCloseEvent_SetCanVeto, 2815).
--define(wxCloseEvent_SetLoggingOff, 2816).
--define(wxCloseEvent_Veto, 2817).
--define(wxShowEvent_SetShow, 2818).
--define(wxShowEvent_GetShow, 2819).
--define(wxIconizeEvent_Iconized, 2820).
--define(wxJoystickEvent_ButtonDown, 2821).
--define(wxJoystickEvent_ButtonIsDown, 2822).
--define(wxJoystickEvent_ButtonUp, 2823).
--define(wxJoystickEvent_GetButtonChange, 2824).
--define(wxJoystickEvent_GetButtonState, 2825).
--define(wxJoystickEvent_GetJoystick, 2826).
--define(wxJoystickEvent_GetPosition, 2827).
--define(wxJoystickEvent_GetZPosition, 2828).
--define(wxJoystickEvent_IsButton, 2829).
--define(wxJoystickEvent_IsMove, 2830).
--define(wxJoystickEvent_IsZMove, 2831).
--define(wxUpdateUIEvent_CanUpdate, 2832).
--define(wxUpdateUIEvent_Check, 2833).
--define(wxUpdateUIEvent_Enable, 2834).
--define(wxUpdateUIEvent_Show, 2835).
--define(wxUpdateUIEvent_GetChecked, 2836).
--define(wxUpdateUIEvent_GetEnabled, 2837).
--define(wxUpdateUIEvent_GetShown, 2838).
--define(wxUpdateUIEvent_GetSetChecked, 2839).
--define(wxUpdateUIEvent_GetSetEnabled, 2840).
--define(wxUpdateUIEvent_GetSetShown, 2841).
--define(wxUpdateUIEvent_GetSetText, 2842).
--define(wxUpdateUIEvent_GetText, 2843).
--define(wxUpdateUIEvent_GetMode, 2844).
--define(wxUpdateUIEvent_GetUpdateInterval, 2845).
--define(wxUpdateUIEvent_ResetUpdateTime, 2846).
--define(wxUpdateUIEvent_SetMode, 2847).
--define(wxUpdateUIEvent_SetText, 2848).
--define(wxUpdateUIEvent_SetUpdateInterval, 2849).
--define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2850).
--define(wxPaletteChangedEvent_SetChangedWindow, 2851).
--define(wxPaletteChangedEvent_GetChangedWindow, 2852).
--define(wxQueryNewPaletteEvent_SetPaletteRealized, 2853).
--define(wxQueryNewPaletteEvent_GetPaletteRealized, 2854).
--define(wxNavigationKeyEvent_GetDirection, 2855).
--define(wxNavigationKeyEvent_SetDirection, 2856).
--define(wxNavigationKeyEvent_IsWindowChange, 2857).
--define(wxNavigationKeyEvent_SetWindowChange, 2858).
--define(wxNavigationKeyEvent_IsFromTab, 2859).
--define(wxNavigationKeyEvent_SetFromTab, 2860).
--define(wxNavigationKeyEvent_GetCurrentFocus, 2861).
--define(wxNavigationKeyEvent_SetCurrentFocus, 2862).
--define(wxHelpEvent_GetOrigin, 2863).
--define(wxHelpEvent_GetPosition, 2864).
--define(wxHelpEvent_SetOrigin, 2865).
--define(wxHelpEvent_SetPosition, 2866).
--define(wxContextMenuEvent_GetPosition, 2867).
--define(wxContextMenuEvent_SetPosition, 2868).
--define(wxIdleEvent_CanSend, 2869).
--define(wxIdleEvent_GetMode, 2870).
--define(wxIdleEvent_RequestMore, 2871).
--define(wxIdleEvent_MoreRequested, 2872).
--define(wxIdleEvent_SetMode, 2873).
--define(wxGridEvent_AltDown, 2874).
--define(wxGridEvent_ControlDown, 2875).
--define(wxGridEvent_GetCol, 2876).
--define(wxGridEvent_GetPosition, 2877).
--define(wxGridEvent_GetRow, 2878).
--define(wxGridEvent_MetaDown, 2879).
--define(wxGridEvent_Selecting, 2880).
--define(wxGridEvent_ShiftDown, 2881).
--define(wxNotifyEvent_Allow, 2882).
--define(wxNotifyEvent_IsAllowed, 2883).
--define(wxNotifyEvent_Veto, 2884).
--define(wxSashEvent_GetEdge, 2885).
--define(wxSashEvent_GetDragRect, 2886).
--define(wxSashEvent_GetDragStatus, 2887).
--define(wxListEvent_GetCacheFrom, 2888).
--define(wxListEvent_GetCacheTo, 2889).
--define(wxListEvent_GetKeyCode, 2890).
--define(wxListEvent_GetIndex, 2891).
--define(wxListEvent_GetColumn, 2892).
--define(wxListEvent_GetPoint, 2893).
--define(wxListEvent_GetLabel, 2894).
--define(wxListEvent_GetText, 2895).
--define(wxListEvent_GetImage, 2896).
--define(wxListEvent_GetData, 2897).
--define(wxListEvent_GetMask, 2898).
--define(wxListEvent_GetItem, 2899).
--define(wxListEvent_IsEditCancelled, 2900).
--define(wxDateEvent_GetDate, 2901).
--define(wxCalendarEvent_GetWeekDay, 2902).
--define(wxFileDirPickerEvent_GetPath, 2903).
--define(wxColourPickerEvent_GetColour, 2904).
--define(wxFontPickerEvent_GetFont, 2905).
--define(wxStyledTextEvent_GetPosition, 2906).
--define(wxStyledTextEvent_GetKey, 2907).
--define(wxStyledTextEvent_GetModifiers, 2908).
--define(wxStyledTextEvent_GetModificationType, 2909).
--define(wxStyledTextEvent_GetText, 2910).
--define(wxStyledTextEvent_GetLength, 2911).
--define(wxStyledTextEvent_GetLinesAdded, 2912).
--define(wxStyledTextEvent_GetLine, 2913).
--define(wxStyledTextEvent_GetFoldLevelNow, 2914).
--define(wxStyledTextEvent_GetFoldLevelPrev, 2915).
--define(wxStyledTextEvent_GetMargin, 2916).
--define(wxStyledTextEvent_GetMessage, 2917).
--define(wxStyledTextEvent_GetWParam, 2918).
--define(wxStyledTextEvent_GetLParam, 2919).
--define(wxStyledTextEvent_GetListType, 2920).
--define(wxStyledTextEvent_GetX, 2921).
--define(wxStyledTextEvent_GetY, 2922).
--define(wxStyledTextEvent_GetDragText, 2923).
--define(wxStyledTextEvent_GetDragAllowMove, 2924).
--define(wxStyledTextEvent_GetDragResult, 2925).
--define(wxStyledTextEvent_GetShift, 2926).
--define(wxStyledTextEvent_GetControl, 2927).
--define(wxStyledTextEvent_GetAlt, 2928).
--define(utils_wxGetKeyState, 2929).
--define(utils_wxGetMousePosition, 2930).
--define(utils_wxGetMouseState, 2931).
--define(utils_wxSetDetectableAutoRepeat, 2932).
--define(utils_wxBell, 2933).
--define(utils_wxFindMenuItemId, 2934).
--define(utils_wxGenericFindWindowAtPoint, 2935).
--define(utils_wxFindWindowAtPoint, 2936).
--define(utils_wxBeginBusyCursor, 2937).
--define(utils_wxEndBusyCursor, 2938).
--define(utils_wxIsBusy, 2939).
--define(utils_wxShutdown, 2940).
--define(utils_wxShell, 2941).
--define(utils_wxLaunchDefaultBrowser, 2942).
--define(utils_wxGetEmailAddress, 2943).
--define(utils_wxGetUserId, 2944).
--define(utils_wxGetHomeDir, 2945).
--define(utils_wxNewId, 2946).
--define(utils_wxRegisterId, 2947).
--define(utils_wxGetCurrentId, 2948).
--define(utils_wxGetOsDescription, 2949).
--define(utils_wxIsPlatformLittleEndian, 2950).
--define(utils_wxIsPlatform64Bit, 2951).
--define(gdicmn_wxDisplaySize, 2952).
--define(gdicmn_wxSetCursor, 2953).
--define(wxPrintout_new, 2954).
--define(wxPrintout_destruct, 2955).
--define(wxPrintout_GetDC, 2956).
--define(wxPrintout_GetPageSizeMM, 2957).
--define(wxPrintout_GetPageSizePixels, 2958).
--define(wxPrintout_GetPaperRectPixels, 2959).
--define(wxPrintout_GetPPIPrinter, 2960).
--define(wxPrintout_GetPPIScreen, 2961).
--define(wxPrintout_GetTitle, 2962).
--define(wxPrintout_IsPreview, 2963).
--define(wxPrintout_FitThisSizeToPaper, 2964).
--define(wxPrintout_FitThisSizeToPage, 2965).
--define(wxPrintout_FitThisSizeToPageMargins, 2966).
--define(wxPrintout_MapScreenSizeToPaper, 2967).
--define(wxPrintout_MapScreenSizeToPage, 2968).
--define(wxPrintout_MapScreenSizeToPageMargins, 2969).
--define(wxPrintout_MapScreenSizeToDevice, 2970).
--define(wxPrintout_GetLogicalPaperRect, 2971).
--define(wxPrintout_GetLogicalPageRect, 2972).
--define(wxPrintout_GetLogicalPageMarginsRect, 2973).
--define(wxPrintout_SetLogicalOrigin, 2974).
--define(wxPrintout_OffsetLogicalOrigin, 2975).
--define(wxStyledTextCtrl_new_2, 2976).
--define(wxStyledTextCtrl_new_0, 2977).
--define(wxStyledTextCtrl_destruct, 2978).
--define(wxStyledTextCtrl_Create, 2979).
--define(wxStyledTextCtrl_AddText, 2980).
--define(wxStyledTextCtrl_AddStyledText, 2981).
--define(wxStyledTextCtrl_InsertText, 2982).
--define(wxStyledTextCtrl_ClearAll, 2983).
--define(wxStyledTextCtrl_ClearDocumentStyle, 2984).
--define(wxStyledTextCtrl_GetLength, 2985).
--define(wxStyledTextCtrl_GetCharAt, 2986).
--define(wxStyledTextCtrl_GetCurrentPos, 2987).
--define(wxStyledTextCtrl_GetAnchor, 2988).
--define(wxStyledTextCtrl_GetStyleAt, 2989).
--define(wxStyledTextCtrl_Redo, 2990).
--define(wxStyledTextCtrl_SetUndoCollection, 2991).
--define(wxStyledTextCtrl_SelectAll, 2992).
--define(wxStyledTextCtrl_SetSavePoint, 2993).
--define(wxStyledTextCtrl_GetStyledText, 2994).
--define(wxStyledTextCtrl_CanRedo, 2995).
--define(wxStyledTextCtrl_MarkerLineFromHandle, 2996).
--define(wxStyledTextCtrl_MarkerDeleteHandle, 2997).
--define(wxStyledTextCtrl_GetUndoCollection, 2998).
--define(wxStyledTextCtrl_GetViewWhiteSpace, 2999).
--define(wxStyledTextCtrl_SetViewWhiteSpace, 3000).
--define(wxStyledTextCtrl_PositionFromPoint, 3001).
--define(wxStyledTextCtrl_PositionFromPointClose, 3002).
--define(wxStyledTextCtrl_GotoLine, 3003).
--define(wxStyledTextCtrl_GotoPos, 3004).
--define(wxStyledTextCtrl_SetAnchor, 3005).
--define(wxStyledTextCtrl_GetCurLine, 3006).
--define(wxStyledTextCtrl_GetEndStyled, 3007).
--define(wxStyledTextCtrl_ConvertEOLs, 3008).
--define(wxStyledTextCtrl_GetEOLMode, 3009).
--define(wxStyledTextCtrl_SetEOLMode, 3010).
--define(wxStyledTextCtrl_StartStyling, 3011).
--define(wxStyledTextCtrl_SetStyling, 3012).
--define(wxStyledTextCtrl_GetBufferedDraw, 3013).
--define(wxStyledTextCtrl_SetBufferedDraw, 3014).
--define(wxStyledTextCtrl_SetTabWidth, 3015).
--define(wxStyledTextCtrl_GetTabWidth, 3016).
--define(wxStyledTextCtrl_SetCodePage, 3017).
--define(wxStyledTextCtrl_MarkerDefine, 3018).
--define(wxStyledTextCtrl_MarkerSetForeground, 3019).
--define(wxStyledTextCtrl_MarkerSetBackground, 3020).
--define(wxStyledTextCtrl_MarkerAdd, 3021).
--define(wxStyledTextCtrl_MarkerDelete, 3022).
--define(wxStyledTextCtrl_MarkerDeleteAll, 3023).
--define(wxStyledTextCtrl_MarkerGet, 3024).
--define(wxStyledTextCtrl_MarkerNext, 3025).
--define(wxStyledTextCtrl_MarkerPrevious, 3026).
--define(wxStyledTextCtrl_MarkerDefineBitmap, 3027).
--define(wxStyledTextCtrl_MarkerAddSet, 3028).
--define(wxStyledTextCtrl_MarkerSetAlpha, 3029).
--define(wxStyledTextCtrl_SetMarginType, 3030).
--define(wxStyledTextCtrl_GetMarginType, 3031).
--define(wxStyledTextCtrl_SetMarginWidth, 3032).
--define(wxStyledTextCtrl_GetMarginWidth, 3033).
--define(wxStyledTextCtrl_SetMarginMask, 3034).
--define(wxStyledTextCtrl_GetMarginMask, 3035).
--define(wxStyledTextCtrl_SetMarginSensitive, 3036).
--define(wxStyledTextCtrl_GetMarginSensitive, 3037).
--define(wxStyledTextCtrl_StyleClearAll, 3038).
--define(wxStyledTextCtrl_StyleSetForeground, 3039).
--define(wxStyledTextCtrl_StyleSetBackground, 3040).
--define(wxStyledTextCtrl_StyleSetBold, 3041).
--define(wxStyledTextCtrl_StyleSetItalic, 3042).
--define(wxStyledTextCtrl_StyleSetSize, 3043).
--define(wxStyledTextCtrl_StyleSetFaceName, 3044).
--define(wxStyledTextCtrl_StyleSetEOLFilled, 3045).
--define(wxStyledTextCtrl_StyleResetDefault, 3046).
--define(wxStyledTextCtrl_StyleSetUnderline, 3047).
--define(wxStyledTextCtrl_StyleSetCase, 3048).
--define(wxStyledTextCtrl_StyleSetHotSpot, 3049).
--define(wxStyledTextCtrl_SetSelForeground, 3050).
--define(wxStyledTextCtrl_SetSelBackground, 3051).
--define(wxStyledTextCtrl_GetSelAlpha, 3052).
--define(wxStyledTextCtrl_SetSelAlpha, 3053).
--define(wxStyledTextCtrl_SetCaretForeground, 3054).
--define(wxStyledTextCtrl_CmdKeyAssign, 3055).
--define(wxStyledTextCtrl_CmdKeyClear, 3056).
--define(wxStyledTextCtrl_CmdKeyClearAll, 3057).
--define(wxStyledTextCtrl_SetStyleBytes, 3058).
--define(wxStyledTextCtrl_StyleSetVisible, 3059).
--define(wxStyledTextCtrl_GetCaretPeriod, 3060).
--define(wxStyledTextCtrl_SetCaretPeriod, 3061).
--define(wxStyledTextCtrl_SetWordChars, 3062).
--define(wxStyledTextCtrl_BeginUndoAction, 3063).
--define(wxStyledTextCtrl_EndUndoAction, 3064).
--define(wxStyledTextCtrl_IndicatorSetStyle, 3065).
--define(wxStyledTextCtrl_IndicatorGetStyle, 3066).
--define(wxStyledTextCtrl_IndicatorSetForeground, 3067).
--define(wxStyledTextCtrl_IndicatorGetForeground, 3068).
--define(wxStyledTextCtrl_SetWhitespaceForeground, 3069).
--define(wxStyledTextCtrl_SetWhitespaceBackground, 3070).
--define(wxStyledTextCtrl_GetStyleBits, 3071).
--define(wxStyledTextCtrl_SetLineState, 3072).
--define(wxStyledTextCtrl_GetLineState, 3073).
--define(wxStyledTextCtrl_GetMaxLineState, 3074).
--define(wxStyledTextCtrl_GetCaretLineVisible, 3075).
--define(wxStyledTextCtrl_SetCaretLineVisible, 3076).
--define(wxStyledTextCtrl_GetCaretLineBackground, 3077).
--define(wxStyledTextCtrl_SetCaretLineBackground, 3078).
--define(wxStyledTextCtrl_AutoCompShow, 3079).
--define(wxStyledTextCtrl_AutoCompCancel, 3080).
--define(wxStyledTextCtrl_AutoCompActive, 3081).
--define(wxStyledTextCtrl_AutoCompPosStart, 3082).
--define(wxStyledTextCtrl_AutoCompComplete, 3083).
--define(wxStyledTextCtrl_AutoCompStops, 3084).
--define(wxStyledTextCtrl_AutoCompSetSeparator, 3085).
--define(wxStyledTextCtrl_AutoCompGetSeparator, 3086).
--define(wxStyledTextCtrl_AutoCompSelect, 3087).
--define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3088).
--define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3089).
--define(wxStyledTextCtrl_AutoCompSetFillUps, 3090).
--define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3091).
--define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3092).
--define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3093).
--define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3094).
--define(wxStyledTextCtrl_UserListShow, 3095).
--define(wxStyledTextCtrl_AutoCompSetAutoHide, 3096).
--define(wxStyledTextCtrl_AutoCompGetAutoHide, 3097).
--define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3098).
--define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3099).
--define(wxStyledTextCtrl_RegisterImage, 3100).
--define(wxStyledTextCtrl_ClearRegisteredImages, 3101).
--define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3102).
--define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3103).
--define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3104).
--define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3105).
--define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3106).
--define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3107).
--define(wxStyledTextCtrl_SetIndent, 3108).
--define(wxStyledTextCtrl_GetIndent, 3109).
--define(wxStyledTextCtrl_SetUseTabs, 3110).
--define(wxStyledTextCtrl_GetUseTabs, 3111).
--define(wxStyledTextCtrl_SetLineIndentation, 3112).
--define(wxStyledTextCtrl_GetLineIndentation, 3113).
--define(wxStyledTextCtrl_GetLineIndentPosition, 3114).
--define(wxStyledTextCtrl_GetColumn, 3115).
--define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3116).
--define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3117).
--define(wxStyledTextCtrl_SetIndentationGuides, 3118).
--define(wxStyledTextCtrl_GetIndentationGuides, 3119).
--define(wxStyledTextCtrl_SetHighlightGuide, 3120).
--define(wxStyledTextCtrl_GetHighlightGuide, 3121).
--define(wxStyledTextCtrl_GetLineEndPosition, 3122).
--define(wxStyledTextCtrl_GetCodePage, 3123).
--define(wxStyledTextCtrl_GetCaretForeground, 3124).
--define(wxStyledTextCtrl_GetReadOnly, 3125).
--define(wxStyledTextCtrl_SetCurrentPos, 3126).
--define(wxStyledTextCtrl_SetSelectionStart, 3127).
--define(wxStyledTextCtrl_GetSelectionStart, 3128).
--define(wxStyledTextCtrl_SetSelectionEnd, 3129).
--define(wxStyledTextCtrl_GetSelectionEnd, 3130).
--define(wxStyledTextCtrl_SetPrintMagnification, 3131).
--define(wxStyledTextCtrl_GetPrintMagnification, 3132).
--define(wxStyledTextCtrl_SetPrintColourMode, 3133).
--define(wxStyledTextCtrl_GetPrintColourMode, 3134).
--define(wxStyledTextCtrl_FindText, 3135).
--define(wxStyledTextCtrl_FormatRange, 3136).
--define(wxStyledTextCtrl_GetFirstVisibleLine, 3137).
--define(wxStyledTextCtrl_GetLine, 3138).
--define(wxStyledTextCtrl_GetLineCount, 3139).
--define(wxStyledTextCtrl_SetMarginLeft, 3140).
--define(wxStyledTextCtrl_GetMarginLeft, 3141).
--define(wxStyledTextCtrl_SetMarginRight, 3142).
--define(wxStyledTextCtrl_GetMarginRight, 3143).
--define(wxStyledTextCtrl_GetModify, 3144).
--define(wxStyledTextCtrl_SetSelection, 3145).
--define(wxStyledTextCtrl_GetSelectedText, 3146).
--define(wxStyledTextCtrl_GetTextRange, 3147).
--define(wxStyledTextCtrl_HideSelection, 3148).
--define(wxStyledTextCtrl_LineFromPosition, 3149).
--define(wxStyledTextCtrl_PositionFromLine, 3150).
--define(wxStyledTextCtrl_LineScroll, 3151).
--define(wxStyledTextCtrl_EnsureCaretVisible, 3152).
--define(wxStyledTextCtrl_ReplaceSelection, 3153).
--define(wxStyledTextCtrl_SetReadOnly, 3154).
--define(wxStyledTextCtrl_CanPaste, 3155).
--define(wxStyledTextCtrl_CanUndo, 3156).
--define(wxStyledTextCtrl_EmptyUndoBuffer, 3157).
--define(wxStyledTextCtrl_Undo, 3158).
--define(wxStyledTextCtrl_Cut, 3159).
--define(wxStyledTextCtrl_Copy, 3160).
--define(wxStyledTextCtrl_Paste, 3161).
--define(wxStyledTextCtrl_Clear, 3162).
--define(wxStyledTextCtrl_SetText, 3163).
--define(wxStyledTextCtrl_GetText, 3164).
--define(wxStyledTextCtrl_GetTextLength, 3165).
--define(wxStyledTextCtrl_GetOvertype, 3166).
--define(wxStyledTextCtrl_SetCaretWidth, 3167).
--define(wxStyledTextCtrl_GetCaretWidth, 3168).
--define(wxStyledTextCtrl_SetTargetStart, 3169).
--define(wxStyledTextCtrl_GetTargetStart, 3170).
--define(wxStyledTextCtrl_SetTargetEnd, 3171).
--define(wxStyledTextCtrl_GetTargetEnd, 3172).
--define(wxStyledTextCtrl_ReplaceTarget, 3173).
--define(wxStyledTextCtrl_SearchInTarget, 3174).
--define(wxStyledTextCtrl_SetSearchFlags, 3175).
--define(wxStyledTextCtrl_GetSearchFlags, 3176).
--define(wxStyledTextCtrl_CallTipShow, 3177).
--define(wxStyledTextCtrl_CallTipCancel, 3178).
--define(wxStyledTextCtrl_CallTipActive, 3179).
--define(wxStyledTextCtrl_CallTipPosAtStart, 3180).
--define(wxStyledTextCtrl_CallTipSetHighlight, 3181).
--define(wxStyledTextCtrl_CallTipSetBackground, 3182).
--define(wxStyledTextCtrl_CallTipSetForeground, 3183).
--define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3184).
--define(wxStyledTextCtrl_CallTipUseStyle, 3185).
--define(wxStyledTextCtrl_VisibleFromDocLine, 3186).
--define(wxStyledTextCtrl_DocLineFromVisible, 3187).
--define(wxStyledTextCtrl_WrapCount, 3188).
--define(wxStyledTextCtrl_SetFoldLevel, 3189).
--define(wxStyledTextCtrl_GetFoldLevel, 3190).
--define(wxStyledTextCtrl_GetLastChild, 3191).
--define(wxStyledTextCtrl_GetFoldParent, 3192).
--define(wxStyledTextCtrl_ShowLines, 3193).
--define(wxStyledTextCtrl_HideLines, 3194).
--define(wxStyledTextCtrl_GetLineVisible, 3195).
--define(wxStyledTextCtrl_SetFoldExpanded, 3196).
--define(wxStyledTextCtrl_GetFoldExpanded, 3197).
--define(wxStyledTextCtrl_ToggleFold, 3198).
--define(wxStyledTextCtrl_EnsureVisible, 3199).
--define(wxStyledTextCtrl_SetFoldFlags, 3200).
--define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3201).
--define(wxStyledTextCtrl_SetTabIndents, 3202).
--define(wxStyledTextCtrl_GetTabIndents, 3203).
--define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3204).
--define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3205).
--define(wxStyledTextCtrl_SetMouseDwellTime, 3206).
--define(wxStyledTextCtrl_GetMouseDwellTime, 3207).
--define(wxStyledTextCtrl_WordStartPosition, 3208).
--define(wxStyledTextCtrl_WordEndPosition, 3209).
--define(wxStyledTextCtrl_SetWrapMode, 3210).
--define(wxStyledTextCtrl_GetWrapMode, 3211).
--define(wxStyledTextCtrl_SetWrapVisualFlags, 3212).
--define(wxStyledTextCtrl_GetWrapVisualFlags, 3213).
--define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3214).
--define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3215).
--define(wxStyledTextCtrl_SetWrapStartIndent, 3216).
--define(wxStyledTextCtrl_GetWrapStartIndent, 3217).
--define(wxStyledTextCtrl_SetLayoutCache, 3218).
--define(wxStyledTextCtrl_GetLayoutCache, 3219).
--define(wxStyledTextCtrl_SetScrollWidth, 3220).
--define(wxStyledTextCtrl_GetScrollWidth, 3221).
--define(wxStyledTextCtrl_TextWidth, 3222).
--define(wxStyledTextCtrl_GetEndAtLastLine, 3223).
--define(wxStyledTextCtrl_TextHeight, 3224).
--define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3225).
--define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3226).
--define(wxStyledTextCtrl_AppendText, 3227).
--define(wxStyledTextCtrl_GetTwoPhaseDraw, 3228).
--define(wxStyledTextCtrl_SetTwoPhaseDraw, 3229).
--define(wxStyledTextCtrl_TargetFromSelection, 3230).
--define(wxStyledTextCtrl_LinesJoin, 3231).
--define(wxStyledTextCtrl_LinesSplit, 3232).
--define(wxStyledTextCtrl_SetFoldMarginColour, 3233).
--define(wxStyledTextCtrl_SetFoldMarginHiColour, 3234).
--define(wxStyledTextCtrl_LineDown, 3235).
--define(wxStyledTextCtrl_LineDownExtend, 3236).
--define(wxStyledTextCtrl_LineUp, 3237).
--define(wxStyledTextCtrl_LineUpExtend, 3238).
--define(wxStyledTextCtrl_CharLeft, 3239).
--define(wxStyledTextCtrl_CharLeftExtend, 3240).
--define(wxStyledTextCtrl_CharRight, 3241).
--define(wxStyledTextCtrl_CharRightExtend, 3242).
--define(wxStyledTextCtrl_WordLeft, 3243).
--define(wxStyledTextCtrl_WordLeftExtend, 3244).
--define(wxStyledTextCtrl_WordRight, 3245).
--define(wxStyledTextCtrl_WordRightExtend, 3246).
--define(wxStyledTextCtrl_Home, 3247).
--define(wxStyledTextCtrl_HomeExtend, 3248).
--define(wxStyledTextCtrl_LineEnd, 3249).
--define(wxStyledTextCtrl_LineEndExtend, 3250).
--define(wxStyledTextCtrl_DocumentStart, 3251).
--define(wxStyledTextCtrl_DocumentStartExtend, 3252).
--define(wxStyledTextCtrl_DocumentEnd, 3253).
--define(wxStyledTextCtrl_DocumentEndExtend, 3254).
--define(wxStyledTextCtrl_PageUp, 3255).
--define(wxStyledTextCtrl_PageUpExtend, 3256).
--define(wxStyledTextCtrl_PageDown, 3257).
--define(wxStyledTextCtrl_PageDownExtend, 3258).
--define(wxStyledTextCtrl_EditToggleOvertype, 3259).
--define(wxStyledTextCtrl_Cancel, 3260).
--define(wxStyledTextCtrl_DeleteBack, 3261).
--define(wxStyledTextCtrl_Tab, 3262).
--define(wxStyledTextCtrl_BackTab, 3263).
--define(wxStyledTextCtrl_NewLine, 3264).
--define(wxStyledTextCtrl_FormFeed, 3265).
--define(wxStyledTextCtrl_VCHome, 3266).
--define(wxStyledTextCtrl_VCHomeExtend, 3267).
--define(wxStyledTextCtrl_ZoomIn, 3268).
--define(wxStyledTextCtrl_ZoomOut, 3269).
--define(wxStyledTextCtrl_DelWordLeft, 3270).
--define(wxStyledTextCtrl_DelWordRight, 3271).
--define(wxStyledTextCtrl_LineCut, 3272).
--define(wxStyledTextCtrl_LineDelete, 3273).
--define(wxStyledTextCtrl_LineTranspose, 3274).
--define(wxStyledTextCtrl_LineDuplicate, 3275).
--define(wxStyledTextCtrl_LowerCase, 3276).
--define(wxStyledTextCtrl_UpperCase, 3277).
--define(wxStyledTextCtrl_LineScrollDown, 3278).
--define(wxStyledTextCtrl_LineScrollUp, 3279).
--define(wxStyledTextCtrl_DeleteBackNotLine, 3280).
--define(wxStyledTextCtrl_HomeDisplay, 3281).
--define(wxStyledTextCtrl_HomeDisplayExtend, 3282).
--define(wxStyledTextCtrl_LineEndDisplay, 3283).
--define(wxStyledTextCtrl_LineEndDisplayExtend, 3284).
--define(wxStyledTextCtrl_HomeWrapExtend, 3285).
--define(wxStyledTextCtrl_LineEndWrap, 3286).
--define(wxStyledTextCtrl_LineEndWrapExtend, 3287).
--define(wxStyledTextCtrl_VCHomeWrap, 3288).
--define(wxStyledTextCtrl_VCHomeWrapExtend, 3289).
--define(wxStyledTextCtrl_LineCopy, 3290).
--define(wxStyledTextCtrl_MoveCaretInsideView, 3291).
--define(wxStyledTextCtrl_LineLength, 3292).
--define(wxStyledTextCtrl_BraceHighlight, 3293).
--define(wxStyledTextCtrl_BraceBadLight, 3294).
--define(wxStyledTextCtrl_BraceMatch, 3295).
--define(wxStyledTextCtrl_GetViewEOL, 3296).
--define(wxStyledTextCtrl_SetViewEOL, 3297).
--define(wxStyledTextCtrl_SetModEventMask, 3298).
--define(wxStyledTextCtrl_GetEdgeColumn, 3299).
--define(wxStyledTextCtrl_SetEdgeColumn, 3300).
--define(wxStyledTextCtrl_SetEdgeMode, 3301).
--define(wxStyledTextCtrl_GetEdgeMode, 3302).
--define(wxStyledTextCtrl_GetEdgeColour, 3303).
--define(wxStyledTextCtrl_SetEdgeColour, 3304).
--define(wxStyledTextCtrl_SearchAnchor, 3305).
--define(wxStyledTextCtrl_SearchNext, 3306).
--define(wxStyledTextCtrl_SearchPrev, 3307).
--define(wxStyledTextCtrl_LinesOnScreen, 3308).
--define(wxStyledTextCtrl_UsePopUp, 3309).
--define(wxStyledTextCtrl_SelectionIsRectangle, 3310).
--define(wxStyledTextCtrl_SetZoom, 3311).
--define(wxStyledTextCtrl_GetZoom, 3312).
--define(wxStyledTextCtrl_GetModEventMask, 3313).
--define(wxStyledTextCtrl_SetSTCFocus, 3314).
--define(wxStyledTextCtrl_GetSTCFocus, 3315).
--define(wxStyledTextCtrl_SetStatus, 3316).
--define(wxStyledTextCtrl_GetStatus, 3317).
--define(wxStyledTextCtrl_SetMouseDownCaptures, 3318).
--define(wxStyledTextCtrl_GetMouseDownCaptures, 3319).
--define(wxStyledTextCtrl_SetSTCCursor, 3320).
--define(wxStyledTextCtrl_GetSTCCursor, 3321).
--define(wxStyledTextCtrl_SetControlCharSymbol, 3322).
--define(wxStyledTextCtrl_GetControlCharSymbol, 3323).
--define(wxStyledTextCtrl_WordPartLeft, 3324).
--define(wxStyledTextCtrl_WordPartLeftExtend, 3325).
--define(wxStyledTextCtrl_WordPartRight, 3326).
--define(wxStyledTextCtrl_WordPartRightExtend, 3327).
--define(wxStyledTextCtrl_SetVisiblePolicy, 3328).
--define(wxStyledTextCtrl_DelLineLeft, 3329).
--define(wxStyledTextCtrl_DelLineRight, 3330).
--define(wxStyledTextCtrl_GetXOffset, 3331).
--define(wxStyledTextCtrl_ChooseCaretX, 3332).
--define(wxStyledTextCtrl_SetXCaretPolicy, 3333).
--define(wxStyledTextCtrl_SetYCaretPolicy, 3334).
--define(wxStyledTextCtrl_GetPrintWrapMode, 3335).
--define(wxStyledTextCtrl_SetHotspotActiveForeground, 3336).
--define(wxStyledTextCtrl_SetHotspotActiveBackground, 3337).
--define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3338).
--define(wxStyledTextCtrl_SetHotspotSingleLine, 3339).
--define(wxStyledTextCtrl_ParaDownExtend, 3340).
--define(wxStyledTextCtrl_ParaUp, 3341).
--define(wxStyledTextCtrl_ParaUpExtend, 3342).
--define(wxStyledTextCtrl_PositionBefore, 3343).
--define(wxStyledTextCtrl_PositionAfter, 3344).
--define(wxStyledTextCtrl_CopyRange, 3345).
--define(wxStyledTextCtrl_CopyText, 3346).
--define(wxStyledTextCtrl_SetSelectionMode, 3347).
--define(wxStyledTextCtrl_GetSelectionMode, 3348).
--define(wxStyledTextCtrl_LineDownRectExtend, 3349).
--define(wxStyledTextCtrl_LineUpRectExtend, 3350).
--define(wxStyledTextCtrl_CharLeftRectExtend, 3351).
--define(wxStyledTextCtrl_CharRightRectExtend, 3352).
--define(wxStyledTextCtrl_HomeRectExtend, 3353).
--define(wxStyledTextCtrl_VCHomeRectExtend, 3354).
--define(wxStyledTextCtrl_LineEndRectExtend, 3355).
--define(wxStyledTextCtrl_PageUpRectExtend, 3356).
--define(wxStyledTextCtrl_PageDownRectExtend, 3357).
--define(wxStyledTextCtrl_StutteredPageUp, 3358).
--define(wxStyledTextCtrl_StutteredPageUpExtend, 3359).
--define(wxStyledTextCtrl_StutteredPageDown, 3360).
--define(wxStyledTextCtrl_StutteredPageDownExtend, 3361).
--define(wxStyledTextCtrl_WordLeftEnd, 3362).
--define(wxStyledTextCtrl_WordLeftEndExtend, 3363).
--define(wxStyledTextCtrl_WordRightEnd, 3364).
--define(wxStyledTextCtrl_WordRightEndExtend, 3365).
--define(wxStyledTextCtrl_SetWhitespaceChars, 3366).
--define(wxStyledTextCtrl_SetCharsDefault, 3367).
--define(wxStyledTextCtrl_AutoCompGetCurrent, 3368).
--define(wxStyledTextCtrl_Allocate, 3369).
--define(wxStyledTextCtrl_FindColumn, 3370).
--define(wxStyledTextCtrl_GetCaretSticky, 3371).
--define(wxStyledTextCtrl_SetCaretSticky, 3372).
--define(wxStyledTextCtrl_ToggleCaretSticky, 3373).
--define(wxStyledTextCtrl_SetPasteConvertEndings, 3374).
--define(wxStyledTextCtrl_GetPasteConvertEndings, 3375).
--define(wxStyledTextCtrl_SelectionDuplicate, 3376).
--define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3377).
--define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3378).
--define(wxStyledTextCtrl_StartRecord, 3379).
--define(wxStyledTextCtrl_StopRecord, 3380).
--define(wxStyledTextCtrl_SetLexer, 3381).
--define(wxStyledTextCtrl_GetLexer, 3382).
--define(wxStyledTextCtrl_Colourise, 3383).
--define(wxStyledTextCtrl_SetProperty, 3384).
--define(wxStyledTextCtrl_SetKeyWords, 3385).
--define(wxStyledTextCtrl_SetLexerLanguage, 3386).
--define(wxStyledTextCtrl_GetProperty, 3387).
--define(wxStyledTextCtrl_GetStyleBitsNeeded, 3388).
--define(wxStyledTextCtrl_GetCurrentLine, 3389).
--define(wxStyledTextCtrl_StyleSetSpec, 3390).
--define(wxStyledTextCtrl_StyleSetFont, 3391).
--define(wxStyledTextCtrl_StyleSetFontAttr, 3392).
--define(wxStyledTextCtrl_StyleSetCharacterSet, 3393).
--define(wxStyledTextCtrl_StyleSetFontEncoding, 3394).
--define(wxStyledTextCtrl_CmdKeyExecute, 3395).
--define(wxStyledTextCtrl_SetMargins, 3396).
--define(wxStyledTextCtrl_GetSelection, 3397).
--define(wxStyledTextCtrl_PointFromPosition, 3398).
--define(wxStyledTextCtrl_ScrollToLine, 3399).
--define(wxStyledTextCtrl_ScrollToColumn, 3400).
--define(wxStyledTextCtrl_SetVScrollBar, 3401).
--define(wxStyledTextCtrl_SetHScrollBar, 3402).
--define(wxStyledTextCtrl_GetLastKeydownProcessed, 3403).
--define(wxStyledTextCtrl_SetLastKeydownProcessed, 3404).
--define(wxStyledTextCtrl_SaveFile, 3405).
--define(wxStyledTextCtrl_LoadFile, 3406).
--define(wxStyledTextCtrl_DoDragOver, 3407).
--define(wxStyledTextCtrl_DoDropText, 3408).
--define(wxStyledTextCtrl_GetUseAntiAliasing, 3409).
--define(wxStyledTextCtrl_AddTextRaw, 3410).
--define(wxStyledTextCtrl_InsertTextRaw, 3411).
--define(wxStyledTextCtrl_GetCurLineRaw, 3412).
--define(wxStyledTextCtrl_GetLineRaw, 3413).
--define(wxStyledTextCtrl_GetSelectedTextRaw, 3414).
--define(wxStyledTextCtrl_GetTextRangeRaw, 3415).
--define(wxStyledTextCtrl_SetTextRaw, 3416).
--define(wxStyledTextCtrl_GetTextRaw, 3417).
--define(wxStyledTextCtrl_AppendTextRaw, 3418).
--define(wxArtProvider_GetBitmap, 3419).
--define(wxArtProvider_GetIcon, 3420).
--define(wxTreeEvent_GetKeyCode, 3421).
--define(wxTreeEvent_GetItem, 3422).
--define(wxTreeEvent_GetKeyEvent, 3423).
--define(wxTreeEvent_GetLabel, 3424).
--define(wxTreeEvent_GetOldItem, 3425).
--define(wxTreeEvent_GetPoint, 3426).
--define(wxTreeEvent_IsEditCancelled, 3427).
--define(wxTreeEvent_SetToolTip, 3428).
--define(wxNotebookEvent_GetOldSelection, 3429).
--define(wxNotebookEvent_GetSelection, 3430).
--define(wxNotebookEvent_SetOldSelection, 3431).
--define(wxNotebookEvent_SetSelection, 3432).
--define(wxFileDataObject_new, 3433).
--define(wxFileDataObject_AddFile, 3434).
--define(wxFileDataObject_GetFilenames, 3435).
--define(wxFileDataObject_destroy, 3436).
--define(wxTextDataObject_new, 3437).
--define(wxTextDataObject_GetTextLength, 3438).
--define(wxTextDataObject_GetText, 3439).
--define(wxTextDataObject_SetText, 3440).
--define(wxTextDataObject_destroy, 3441).
--define(wxBitmapDataObject_new_1_1, 3442).
--define(wxBitmapDataObject_new_1_0, 3443).
--define(wxBitmapDataObject_GetBitmap, 3444).
--define(wxBitmapDataObject_SetBitmap, 3445).
--define(wxBitmapDataObject_destroy, 3446).
--define(wxClipboard_new, 3448).
--define(wxClipboard_destruct, 3449).
--define(wxClipboard_AddData, 3450).
--define(wxClipboard_Clear, 3451).
--define(wxClipboard_Close, 3452).
--define(wxClipboard_Flush, 3453).
--define(wxClipboard_GetData, 3454).
--define(wxClipboard_IsOpened, 3455).
--define(wxClipboard_Open, 3456).
--define(wxClipboard_SetData, 3457).
--define(wxClipboard_UsePrimarySelection, 3459).
--define(wxClipboard_IsSupported, 3460).
--define(wxClipboard_Get, 3461).
--define(wxSpinEvent_GetPosition, 3462).
--define(wxSpinEvent_SetPosition, 3463).
--define(wxSplitterWindow_new_0, 3464).
--define(wxSplitterWindow_new_2, 3465).
--define(wxSplitterWindow_destruct, 3466).
--define(wxSplitterWindow_Create, 3467).
--define(wxSplitterWindow_GetMinimumPaneSize, 3468).
--define(wxSplitterWindow_GetSashGravity, 3469).
--define(wxSplitterWindow_GetSashPosition, 3470).
--define(wxSplitterWindow_GetSplitMode, 3471).
--define(wxSplitterWindow_GetWindow1, 3472).
--define(wxSplitterWindow_GetWindow2, 3473).
--define(wxSplitterWindow_Initialize, 3474).
--define(wxSplitterWindow_IsSplit, 3475).
--define(wxSplitterWindow_ReplaceWindow, 3476).
--define(wxSplitterWindow_SetSashGravity, 3477).
--define(wxSplitterWindow_SetSashPosition, 3478).
--define(wxSplitterWindow_SetSashSize, 3479).
--define(wxSplitterWindow_SetMinimumPaneSize, 3480).
--define(wxSplitterWindow_SetSplitMode, 3481).
--define(wxSplitterWindow_SplitHorizontally, 3482).
--define(wxSplitterWindow_SplitVertically, 3483).
--define(wxSplitterWindow_Unsplit, 3484).
--define(wxSplitterWindow_UpdateSize, 3485).
--define(wxSplitterEvent_GetSashPosition, 3486).
--define(wxSplitterEvent_GetX, 3487).
--define(wxSplitterEvent_GetY, 3488).
--define(wxSplitterEvent_GetWindowBeingRemoved, 3489).
--define(wxSplitterEvent_SetSashPosition, 3490).
--define(wxHtmlWindow_new_0, 3491).
--define(wxHtmlWindow_new_2, 3492).
--define(wxHtmlWindow_AppendToPage, 3493).
--define(wxHtmlWindow_GetOpenedAnchor, 3494).
--define(wxHtmlWindow_GetOpenedPage, 3495).
--define(wxHtmlWindow_GetOpenedPageTitle, 3496).
--define(wxHtmlWindow_GetRelatedFrame, 3497).
--define(wxHtmlWindow_HistoryBack, 3498).
--define(wxHtmlWindow_HistoryCanBack, 3499).
--define(wxHtmlWindow_HistoryCanForward, 3500).
--define(wxHtmlWindow_HistoryClear, 3501).
--define(wxHtmlWindow_HistoryForward, 3502).
--define(wxHtmlWindow_LoadFile, 3503).
--define(wxHtmlWindow_LoadPage, 3504).
--define(wxHtmlWindow_SelectAll, 3505).
--define(wxHtmlWindow_SelectionToText, 3506).
--define(wxHtmlWindow_SelectLine, 3507).
--define(wxHtmlWindow_SelectWord, 3508).
--define(wxHtmlWindow_SetBorders, 3509).
--define(wxHtmlWindow_SetFonts, 3510).
--define(wxHtmlWindow_SetPage, 3511).
--define(wxHtmlWindow_SetRelatedFrame, 3512).
--define(wxHtmlWindow_SetRelatedStatusBar, 3513).
--define(wxHtmlWindow_ToText, 3514).
--define(wxHtmlWindow_destroy, 3515).
--define(wxHtmlLinkEvent_GetLinkInfo, 3516).
--define(wxSystemSettings_GetColour, 3517).
--define(wxSystemSettings_GetFont, 3518).
--define(wxSystemSettings_GetMetric, 3519).
--define(wxSystemSettings_GetScreenType, 3520).
--define(wxSystemOptions_GetOption, 3521).
--define(wxSystemOptions_GetOptionInt, 3522).
--define(wxSystemOptions_HasOption, 3523).
--define(wxSystemOptions_IsFalse, 3524).
--define(wxSystemOptions_SetOption_2_1, 3525).
--define(wxSystemOptions_SetOption_2_0, 3526).
--define(wxAuiNotebookEvent_SetSelection, 3527).
--define(wxAuiNotebookEvent_GetSelection, 3528).
--define(wxAuiNotebookEvent_SetOldSelection, 3529).
--define(wxAuiNotebookEvent_GetOldSelection, 3530).
--define(wxAuiNotebookEvent_SetDragSource, 3531).
--define(wxAuiNotebookEvent_GetDragSource, 3532).
--define(wxAuiManagerEvent_SetManager, 3533).
--define(wxAuiManagerEvent_GetManager, 3534).
--define(wxAuiManagerEvent_SetPane, 3535).
--define(wxAuiManagerEvent_GetPane, 3536).
--define(wxAuiManagerEvent_SetButton, 3537).
--define(wxAuiManagerEvent_GetButton, 3538).
--define(wxAuiManagerEvent_SetDC, 3539).
--define(wxAuiManagerEvent_GetDC, 3540).
--define(wxAuiManagerEvent_Veto, 3541).
--define(wxAuiManagerEvent_GetVeto, 3542).
--define(wxAuiManagerEvent_SetCanVeto, 3543).
--define(wxAuiManagerEvent_CanVeto, 3544).
--define(wxLogNull_new, 3545).
--define(wxLogNull_destroy, 3546).
--define(wxTaskBarIcon_new, 3547).
--define(wxTaskBarIcon_destruct, 3548).
--define(wxTaskBarIcon_PopupMenu, 3549).
--define(wxTaskBarIcon_RemoveIcon, 3550).
--define(wxTaskBarIcon_SetIcon, 3551).
--define(wxLocale_new_0, 3552).
--define(wxLocale_new_2, 3554).
--define(wxLocale_destruct, 3555).
--define(wxLocale_Init, 3557).
--define(wxLocale_AddCatalog_1, 3558).
--define(wxLocale_AddCatalog_3, 3559).
--define(wxLocale_AddCatalogLookupPathPrefix, 3560).
--define(wxLocale_GetCanonicalName, 3561).
--define(wxLocale_GetLanguage, 3562).
--define(wxLocale_GetLanguageName, 3563).
--define(wxLocale_GetLocale, 3564).
--define(wxLocale_GetName, 3565).
--define(wxLocale_GetString_2, 3566).
--define(wxLocale_GetString_4, 3567).
--define(wxLocale_GetHeaderValue, 3568).
--define(wxLocale_GetSysName, 3569).
--define(wxLocale_GetSystemEncoding, 3570).
--define(wxLocale_GetSystemEncodingName, 3571).
--define(wxLocale_GetSystemLanguage, 3572).
--define(wxLocale_IsLoaded, 3573).
--define(wxLocale_IsOk, 3574).
--define(wxActivateEvent_GetActive, 3575).
--define(wxPopupWindow_new_2, 3577).
--define(wxPopupWindow_new_0, 3578).
--define(wxPopupWindow_destruct, 3580).
--define(wxPopupWindow_Create, 3581).
--define(wxPopupWindow_Position, 3582).
--define(wxPopupTransientWindow_new_0, 3583).
--define(wxPopupTransientWindow_new_2, 3584).
--define(wxPopupTransientWindow_destruct, 3585).
--define(wxPopupTransientWindow_Popup, 3586).
--define(wxPopupTransientWindow_Dismiss, 3587).
--define(wxOverlay_new, 3588).
--define(wxOverlay_destruct, 3589).
--define(wxOverlay_Reset, 3590).
--define(wxDCOverlay_new_6, 3591).
--define(wxDCOverlay_new_2, 3592).
--define(wxDCOverlay_destruct, 3593).
--define(wxDCOverlay_Clear, 3594).
+-define(wxWindow_DragAcceptFiles, 126).
+-define(wxWindow_Enable, 127).
+-define(wxWindow_FindFocus, 128).
+-define(wxWindow_FindWindow_1_0, 129).
+-define(wxWindow_FindWindow_1_1, 130).
+-define(wxWindow_FindWindowById, 131).
+-define(wxWindow_FindWindowByName, 132).
+-define(wxWindow_FindWindowByLabel, 133).
+-define(wxWindow_Fit, 134).
+-define(wxWindow_FitInside, 135).
+-define(wxWindow_Freeze, 136).
+-define(wxWindow_GetAcceleratorTable, 137).
+-define(wxWindow_GetBackgroundColour, 138).
+-define(wxWindow_GetBackgroundStyle, 139).
+-define(wxWindow_GetBestSize, 140).
+-define(wxWindow_GetCaret, 142).
+-define(wxWindow_GetCapture, 143).
+-define(wxWindow_GetCharHeight, 144).
+-define(wxWindow_GetCharWidth, 145).
+-define(wxWindow_GetChildren, 146).
+-define(wxWindow_GetClientSize, 149).
+-define(wxWindow_GetContainingSizer, 150).
+-define(wxWindow_GetCursor, 151).
+-define(wxWindow_GetDropTarget, 152).
+-define(wxWindow_GetEventHandler, 153).
+-define(wxWindow_GetExtraStyle, 154).
+-define(wxWindow_GetFont, 155).
+-define(wxWindow_GetForegroundColour, 156).
+-define(wxWindow_GetGrandParent, 157).
+-define(wxWindow_GetHandle, 158).
+-define(wxWindow_GetHelpText, 159).
+-define(wxWindow_GetId, 160).
+-define(wxWindow_GetLabel, 161).
+-define(wxWindow_GetMaxSize, 162).
+-define(wxWindow_GetMinSize, 163).
+-define(wxWindow_GetName, 164).
+-define(wxWindow_GetParent, 165).
+-define(wxWindow_GetPosition, 167).
+-define(wxWindow_GetRect, 168).
+-define(wxWindow_GetScreenPosition, 170).
+-define(wxWindow_GetScreenRect, 171).
+-define(wxWindow_GetScrollPos, 172).
+-define(wxWindow_GetScrollRange, 173).
+-define(wxWindow_GetScrollThumb, 174).
+-define(wxWindow_GetSize, 176).
+-define(wxWindow_GetSizer, 177).
+-define(wxWindow_GetTextExtent, 178).
+-define(wxWindow_GetToolTip, 179).
+-define(wxWindow_GetUpdateRegion, 180).
+-define(wxWindow_GetVirtualSize, 182).
+-define(wxWindow_GetWindowStyleFlag, 184).
+-define(wxWindow_GetWindowVariant, 185).
+-define(wxWindow_HasCapture, 186).
+-define(wxWindow_HasScrollbar, 187).
+-define(wxWindow_HasTransparentBackground, 188).
+-define(wxWindow_Hide, 189).
+-define(wxWindow_InheritAttributes, 190).
+-define(wxWindow_InitDialog, 191).
+-define(wxWindow_InvalidateBestSize, 192).
+-define(wxWindow_IsEnabled, 193).
+-define(wxWindow_IsExposed_2, 194).
+-define(wxWindow_IsExposed_4, 195).
+-define(wxWindow_IsExposed_1_0, 196).
+-define(wxWindow_IsExposed_1_1, 197).
+-define(wxWindow_IsRetained, 198).
+-define(wxWindow_IsShown, 199).
+-define(wxWindow_IsTopLevel, 200).
+-define(wxWindow_Layout, 201).
+-define(wxWindow_LineDown, 202).
+-define(wxWindow_LineUp, 203).
+-define(wxWindow_Lower, 204).
+-define(wxWindow_MakeModal, 205).
+-define(wxWindow_Move_3, 206).
+-define(wxWindow_Move_2, 207).
+-define(wxWindow_MoveAfterInTabOrder, 208).
+-define(wxWindow_MoveBeforeInTabOrder, 209).
+-define(wxWindow_Navigate, 210).
+-define(wxWindow_PageDown, 211).
+-define(wxWindow_PageUp, 212).
+-define(wxWindow_PopEventHandler, 213).
+-define(wxWindow_PopupMenu_2, 214).
+-define(wxWindow_PopupMenu_3, 215).
+-define(wxWindow_Raise, 216).
+-define(wxWindow_Refresh, 217).
+-define(wxWindow_RefreshRect, 218).
+-define(wxWindow_ReleaseMouse, 219).
+-define(wxWindow_RemoveChild, 220).
+-define(wxWindow_Reparent, 221).
+-define(wxWindow_ScreenToClient_2, 222).
+-define(wxWindow_ScreenToClient_1, 223).
+-define(wxWindow_ScrollLines, 225).
+-define(wxWindow_ScrollPages, 227).
+-define(wxWindow_ScrollWindow, 228).
+-define(wxWindow_SetAcceleratorTable, 229).
+-define(wxWindow_SetAutoLayout, 230).
+-define(wxWindow_SetBackgroundColour, 231).
+-define(wxWindow_SetBackgroundStyle, 232).
+-define(wxWindow_SetCaret, 233).
+-define(wxWindow_SetClientSize_2, 234).
+-define(wxWindow_SetClientSize_1_0, 235).
+-define(wxWindow_SetClientSize_1_1, 236).
+-define(wxWindow_SetContainingSizer, 237).
+-define(wxWindow_SetCursor, 238).
+-define(wxWindow_SetMaxSize, 239).
+-define(wxWindow_SetMinSize, 240).
+-define(wxWindow_SetOwnBackgroundColour, 241).
+-define(wxWindow_SetOwnFont, 242).
+-define(wxWindow_SetOwnForegroundColour, 243).
+-define(wxWindow_SetDropTarget, 244).
+-define(wxWindow_SetExtraStyle, 245).
+-define(wxWindow_SetFocus, 246).
+-define(wxWindow_SetFocusFromKbd, 247).
+-define(wxWindow_SetFont, 248).
+-define(wxWindow_SetForegroundColour, 249).
+-define(wxWindow_SetHelpText, 250).
+-define(wxWindow_SetId, 251).
+-define(wxWindow_SetLabel, 253).
+-define(wxWindow_SetName, 254).
+-define(wxWindow_SetPalette, 255).
+-define(wxWindow_SetScrollbar, 256).
+-define(wxWindow_SetScrollPos, 257).
+-define(wxWindow_SetSize_5, 258).
+-define(wxWindow_SetSize_2_0, 259).
+-define(wxWindow_SetSize_1, 260).
+-define(wxWindow_SetSize_2_1, 261).
+-define(wxWindow_SetSizeHints_3, 262).
+-define(wxWindow_SetSizeHints_2, 263).
+-define(wxWindow_SetSizer, 264).
+-define(wxWindow_SetSizerAndFit, 265).
+-define(wxWindow_SetThemeEnabled, 266).
+-define(wxWindow_SetToolTip_1_0, 267).
+-define(wxWindow_SetToolTip_1_1, 268).
+-define(wxWindow_SetVirtualSize_1, 269).
+-define(wxWindow_SetVirtualSize_2, 270).
+-define(wxWindow_SetVirtualSizeHints_3, 271).
+-define(wxWindow_SetVirtualSizeHints_2, 272).
+-define(wxWindow_SetWindowStyle, 273).
+-define(wxWindow_SetWindowStyleFlag, 274).
+-define(wxWindow_SetWindowVariant, 275).
+-define(wxWindow_ShouldInheritColours, 276).
+-define(wxWindow_Show, 277).
+-define(wxWindow_Thaw, 278).
+-define(wxWindow_TransferDataFromWindow, 279).
+-define(wxWindow_TransferDataToWindow, 280).
+-define(wxWindow_Update, 281).
+-define(wxWindow_UpdateWindowUI, 282).
+-define(wxWindow_Validate, 283).
+-define(wxWindow_WarpPointer, 284).
+-define(wxWindow_SetTransparent, 285).
+-define(wxWindow_CanSetTransparent, 286).
+-define(wxWindow_IsDoubleBuffered, 287).
+-define(wxWindow_SetDoubleBuffered, 288).
+-define(wxWindow_GetContentScaleFactor, 289).
+-define(wxTopLevelWindow_GetIcon, 290).
+-define(wxTopLevelWindow_GetIcons, 291).
+-define(wxTopLevelWindow_GetTitle, 292).
+-define(wxTopLevelWindow_IsActive, 293).
+-define(wxTopLevelWindow_Iconize, 294).
+-define(wxTopLevelWindow_IsFullScreen, 295).
+-define(wxTopLevelWindow_IsIconized, 296).
+-define(wxTopLevelWindow_IsMaximized, 297).
+-define(wxTopLevelWindow_Maximize, 298).
+-define(wxTopLevelWindow_RequestUserAttention, 299).
+-define(wxTopLevelWindow_SetIcon, 300).
+-define(wxTopLevelWindow_SetIcons, 301).
+-define(wxTopLevelWindow_CenterOnScreen, 302).
+-define(wxTopLevelWindow_CentreOnScreen, 303).
+-define(wxTopLevelWindow_SetShape, 305).
+-define(wxTopLevelWindow_SetTitle, 306).
+-define(wxTopLevelWindow_ShowFullScreen, 307).
+-define(wxFrame_new_4, 309).
+-define(wxFrame_new_0, 310).
+-define(wxFrame_destruct, 312).
+-define(wxFrame_Create, 313).
+-define(wxFrame_CreateStatusBar, 314).
+-define(wxFrame_CreateToolBar, 315).
+-define(wxFrame_GetClientAreaOrigin, 316).
+-define(wxFrame_GetMenuBar, 317).
+-define(wxFrame_GetStatusBar, 318).
+-define(wxFrame_GetStatusBarPane, 319).
+-define(wxFrame_GetToolBar, 320).
+-define(wxFrame_ProcessCommand, 321).
+-define(wxFrame_SendSizeEvent, 322).
+-define(wxFrame_SetMenuBar, 323).
+-define(wxFrame_SetStatusBar, 324).
+-define(wxFrame_SetStatusBarPane, 325).
+-define(wxFrame_SetStatusText, 326).
+-define(wxFrame_SetStatusWidths, 327).
+-define(wxFrame_SetToolBar, 328).
+-define(wxMiniFrame_new_0, 329).
+-define(wxMiniFrame_new_4, 330).
+-define(wxMiniFrame_Create, 331).
+-define(wxMiniFrame_destroy, 332).
+-define(wxSplashScreen_new_0, 333).
+-define(wxSplashScreen_new_6, 334).
+-define(wxSplashScreen_destruct, 335).
+-define(wxSplashScreen_GetSplashStyle, 336).
+-define(wxSplashScreen_GetTimeout, 337).
+-define(wxPanel_new_0, 338).
+-define(wxPanel_new_6, 339).
+-define(wxPanel_new_2, 340).
+-define(wxPanel_destruct, 341).
+-define(wxPanel_InitDialog, 342).
+-define(wxPanel_SetFocusIgnoringChildren, 343).
+-define(wxScrolledWindow_new_0, 344).
+-define(wxScrolledWindow_new_2, 345).
+-define(wxScrolledWindow_destruct, 346).
+-define(wxScrolledWindow_CalcScrolledPosition_4, 347).
+-define(wxScrolledWindow_CalcScrolledPosition_1, 348).
+-define(wxScrolledWindow_CalcUnscrolledPosition_4, 349).
+-define(wxScrolledWindow_CalcUnscrolledPosition_1, 350).
+-define(wxScrolledWindow_EnableScrolling, 351).
+-define(wxScrolledWindow_GetScrollPixelsPerUnit, 352).
+-define(wxScrolledWindow_GetViewStart, 353).
+-define(wxScrolledWindow_DoPrepareDC, 354).
+-define(wxScrolledWindow_PrepareDC, 355).
+-define(wxScrolledWindow_Scroll, 356).
+-define(wxScrolledWindow_SetScrollbars, 357).
+-define(wxScrolledWindow_SetScrollRate, 358).
+-define(wxScrolledWindow_SetTargetWindow, 359).
+-define(wxSashWindow_new_0, 360).
+-define(wxSashWindow_new_2, 361).
+-define(wxSashWindow_destruct, 362).
+-define(wxSashWindow_GetSashVisible, 363).
+-define(wxSashWindow_GetMaximumSizeX, 364).
+-define(wxSashWindow_GetMaximumSizeY, 365).
+-define(wxSashWindow_GetMinimumSizeX, 366).
+-define(wxSashWindow_GetMinimumSizeY, 367).
+-define(wxSashWindow_SetMaximumSizeX, 368).
+-define(wxSashWindow_SetMaximumSizeY, 369).
+-define(wxSashWindow_SetMinimumSizeX, 370).
+-define(wxSashWindow_SetMinimumSizeY, 371).
+-define(wxSashWindow_SetSashVisible, 372).
+-define(wxSashLayoutWindow_new_0, 373).
+-define(wxSashLayoutWindow_new_2, 374).
+-define(wxSashLayoutWindow_Create, 375).
+-define(wxSashLayoutWindow_GetAlignment, 376).
+-define(wxSashLayoutWindow_GetOrientation, 377).
+-define(wxSashLayoutWindow_SetAlignment, 378).
+-define(wxSashLayoutWindow_SetDefaultSize, 379).
+-define(wxSashLayoutWindow_SetOrientation, 380).
+-define(wxSashLayoutWindow_destroy, 381).
+-define(wxGrid_new_0, 382).
+-define(wxGrid_new_3, 383).
+-define(wxGrid_new_4, 384).
+-define(wxGrid_destruct, 385).
+-define(wxGrid_AppendCols, 386).
+-define(wxGrid_AppendRows, 387).
+-define(wxGrid_AutoSize, 388).
+-define(wxGrid_AutoSizeColumn, 389).
+-define(wxGrid_AutoSizeColumns, 390).
+-define(wxGrid_AutoSizeRow, 391).
+-define(wxGrid_AutoSizeRows, 392).
+-define(wxGrid_BeginBatch, 393).
+-define(wxGrid_BlockToDeviceRect, 394).
+-define(wxGrid_CanDragColSize, 395).
+-define(wxGrid_CanDragRowSize, 396).
+-define(wxGrid_CanDragGridSize, 397).
+-define(wxGrid_CanEnableCellControl, 398).
+-define(wxGrid_CellToRect_2, 399).
+-define(wxGrid_CellToRect_1, 400).
+-define(wxGrid_ClearGrid, 401).
+-define(wxGrid_ClearSelection, 402).
+-define(wxGrid_CreateGrid, 403).
+-define(wxGrid_DeleteCols, 404).
+-define(wxGrid_DeleteRows, 405).
+-define(wxGrid_DisableCellEditControl, 406).
+-define(wxGrid_DisableDragColSize, 407).
+-define(wxGrid_DisableDragGridSize, 408).
+-define(wxGrid_DisableDragRowSize, 409).
+-define(wxGrid_EnableCellEditControl, 410).
+-define(wxGrid_EnableDragColSize, 411).
+-define(wxGrid_EnableDragGridSize, 412).
+-define(wxGrid_EnableDragRowSize, 413).
+-define(wxGrid_EnableEditing, 414).
+-define(wxGrid_EnableGridLines, 415).
+-define(wxGrid_EndBatch, 416).
+-define(wxGrid_Fit, 417).
+-define(wxGrid_ForceRefresh, 418).
+-define(wxGrid_GetBatchCount, 419).
+-define(wxGrid_GetCellAlignment, 420).
+-define(wxGrid_GetCellBackgroundColour, 421).
+-define(wxGrid_GetCellEditor, 422).
+-define(wxGrid_GetCellFont, 423).
+-define(wxGrid_GetCellRenderer, 424).
+-define(wxGrid_GetCellTextColour, 425).
+-define(wxGrid_GetCellValue_2, 426).
+-define(wxGrid_GetCellValue_1, 427).
+-define(wxGrid_GetColLabelAlignment, 428).
+-define(wxGrid_GetColLabelSize, 429).
+-define(wxGrid_GetColLabelValue, 430).
+-define(wxGrid_GetColMinimalAcceptableWidth, 431).
+-define(wxGrid_GetDefaultCellAlignment, 432).
+-define(wxGrid_GetDefaultCellBackgroundColour, 433).
+-define(wxGrid_GetDefaultCellFont, 434).
+-define(wxGrid_GetDefaultCellTextColour, 435).
+-define(wxGrid_GetDefaultColLabelSize, 436).
+-define(wxGrid_GetDefaultColSize, 437).
+-define(wxGrid_GetDefaultEditor, 438).
+-define(wxGrid_GetDefaultEditorForCell_2, 439).
+-define(wxGrid_GetDefaultEditorForCell_1, 440).
+-define(wxGrid_GetDefaultEditorForType, 441).
+-define(wxGrid_GetDefaultRenderer, 442).
+-define(wxGrid_GetDefaultRendererForCell, 443).
+-define(wxGrid_GetDefaultRendererForType, 444).
+-define(wxGrid_GetDefaultRowLabelSize, 445).
+-define(wxGrid_GetDefaultRowSize, 446).
+-define(wxGrid_GetGridCursorCol, 447).
+-define(wxGrid_GetGridCursorRow, 448).
+-define(wxGrid_GetGridLineColour, 449).
+-define(wxGrid_GridLinesEnabled, 450).
+-define(wxGrid_GetLabelBackgroundColour, 451).
+-define(wxGrid_GetLabelFont, 452).
+-define(wxGrid_GetLabelTextColour, 453).
+-define(wxGrid_GetNumberCols, 454).
+-define(wxGrid_GetNumberRows, 455).
+-define(wxGrid_GetOrCreateCellAttr, 456).
+-define(wxGrid_GetRowMinimalAcceptableHeight, 457).
+-define(wxGrid_GetRowLabelAlignment, 458).
+-define(wxGrid_GetRowLabelSize, 459).
+-define(wxGrid_GetRowLabelValue, 460).
+-define(wxGrid_GetRowSize, 461).
+-define(wxGrid_GetScrollLineX, 462).
+-define(wxGrid_GetScrollLineY, 463).
+-define(wxGrid_GetSelectedCells, 464).
+-define(wxGrid_GetSelectedCols, 465).
+-define(wxGrid_GetSelectedRows, 466).
+-define(wxGrid_GetSelectionBackground, 467).
+-define(wxGrid_GetSelectionBlockTopLeft, 468).
+-define(wxGrid_GetSelectionBlockBottomRight, 469).
+-define(wxGrid_GetSelectionForeground, 470).
+-define(wxGrid_GetViewWidth, 471).
+-define(wxGrid_GetGridWindow, 472).
+-define(wxGrid_GetGridRowLabelWindow, 473).
+-define(wxGrid_GetGridColLabelWindow, 474).
+-define(wxGrid_GetGridCornerLabelWindow, 475).
+-define(wxGrid_HideCellEditControl, 476).
+-define(wxGrid_InsertCols, 477).
+-define(wxGrid_InsertRows, 478).
+-define(wxGrid_IsCellEditControlEnabled, 479).
+-define(wxGrid_IsCurrentCellReadOnly, 480).
+-define(wxGrid_IsEditable, 481).
+-define(wxGrid_IsInSelection_2, 482).
+-define(wxGrid_IsInSelection_1, 483).
+-define(wxGrid_IsReadOnly, 484).
+-define(wxGrid_IsSelection, 485).
+-define(wxGrid_IsVisible_3, 486).
+-define(wxGrid_IsVisible_2, 487).
+-define(wxGrid_MakeCellVisible_2, 488).
+-define(wxGrid_MakeCellVisible_1, 489).
+-define(wxGrid_MoveCursorDown, 490).
+-define(wxGrid_MoveCursorLeft, 491).
+-define(wxGrid_MoveCursorRight, 492).
+-define(wxGrid_MoveCursorUp, 493).
+-define(wxGrid_MoveCursorDownBlock, 494).
+-define(wxGrid_MoveCursorLeftBlock, 495).
+-define(wxGrid_MoveCursorRightBlock, 496).
+-define(wxGrid_MoveCursorUpBlock, 497).
+-define(wxGrid_MovePageDown, 498).
+-define(wxGrid_MovePageUp, 499).
+-define(wxGrid_RegisterDataType, 500).
+-define(wxGrid_SaveEditControlValue, 501).
+-define(wxGrid_SelectAll, 502).
+-define(wxGrid_SelectBlock_5, 503).
+-define(wxGrid_SelectBlock_3, 504).
+-define(wxGrid_SelectCol, 505).
+-define(wxGrid_SelectRow, 506).
+-define(wxGrid_SetCellAlignment_4, 507).
+-define(wxGrid_SetCellAlignment_3, 508).
+-define(wxGrid_SetCellAlignment_1, 509).
+-define(wxGrid_SetCellBackgroundColour_3_0, 510).
+-define(wxGrid_SetCellBackgroundColour_1, 511).
+-define(wxGrid_SetCellBackgroundColour_3_1, 512).
+-define(wxGrid_SetCellEditor, 513).
+-define(wxGrid_SetCellFont, 514).
+-define(wxGrid_SetCellRenderer, 515).
+-define(wxGrid_SetCellTextColour_3_0, 516).
+-define(wxGrid_SetCellTextColour_3_1, 517).
+-define(wxGrid_SetCellTextColour_1, 518).
+-define(wxGrid_SetCellValue_3_0, 519).
+-define(wxGrid_SetCellValue_2, 520).
+-define(wxGrid_SetCellValue_3_1, 521).
+-define(wxGrid_SetColAttr, 522).
+-define(wxGrid_SetColFormatBool, 523).
+-define(wxGrid_SetColFormatNumber, 524).
+-define(wxGrid_SetColFormatFloat, 525).
+-define(wxGrid_SetColFormatCustom, 526).
+-define(wxGrid_SetColLabelAlignment, 527).
+-define(wxGrid_SetColLabelSize, 528).
+-define(wxGrid_SetColLabelValue, 529).
+-define(wxGrid_SetColMinimalWidth, 530).
+-define(wxGrid_SetColMinimalAcceptableWidth, 531).
+-define(wxGrid_SetColSize, 532).
+-define(wxGrid_SetDefaultCellAlignment, 533).
+-define(wxGrid_SetDefaultCellBackgroundColour, 534).
+-define(wxGrid_SetDefaultCellFont, 535).
+-define(wxGrid_SetDefaultCellTextColour, 536).
+-define(wxGrid_SetDefaultEditor, 537).
+-define(wxGrid_SetDefaultRenderer, 538).
+-define(wxGrid_SetDefaultColSize, 539).
+-define(wxGrid_SetDefaultRowSize, 540).
+-define(wxGrid_SetGridCursor, 541).
+-define(wxGrid_SetGridLineColour, 542).
+-define(wxGrid_SetLabelBackgroundColour, 543).
+-define(wxGrid_SetLabelFont, 544).
+-define(wxGrid_SetLabelTextColour, 545).
+-define(wxGrid_SetMargins, 546).
+-define(wxGrid_SetReadOnly, 547).
+-define(wxGrid_SetRowAttr, 548).
+-define(wxGrid_SetRowLabelAlignment, 549).
+-define(wxGrid_SetRowLabelSize, 550).
+-define(wxGrid_SetRowLabelValue, 551).
+-define(wxGrid_SetRowMinimalHeight, 552).
+-define(wxGrid_SetRowMinimalAcceptableHeight, 553).
+-define(wxGrid_SetRowSize, 554).
+-define(wxGrid_SetScrollLineX, 555).
+-define(wxGrid_SetScrollLineY, 556).
+-define(wxGrid_SetSelectionBackground, 557).
+-define(wxGrid_SetSelectionForeground, 558).
+-define(wxGrid_SetSelectionMode, 559).
+-define(wxGrid_ShowCellEditControl, 560).
+-define(wxGrid_XToCol, 561).
+-define(wxGrid_XToEdgeOfCol, 562).
+-define(wxGrid_YToEdgeOfRow, 563).
+-define(wxGrid_YToRow, 564).
+-define(wxGridCellRenderer_Draw, 565).
+-define(wxGridCellRenderer_GetBestSize, 566).
+-define(wxGridCellEditor_Create, 567).
+-define(wxGridCellEditor_IsCreated, 568).
+-define(wxGridCellEditor_SetSize, 569).
+-define(wxGridCellEditor_Show, 570).
+-define(wxGridCellEditor_PaintBackground, 571).
+-define(wxGridCellEditor_BeginEdit, 572).
+-define(wxGridCellEditor_EndEdit, 573).
+-define(wxGridCellEditor_Reset, 574).
+-define(wxGridCellEditor_StartingKey, 575).
+-define(wxGridCellEditor_StartingClick, 576).
+-define(wxGridCellEditor_HandleReturn, 577).
+-define(wxGridCellBoolRenderer_new, 578).
+-define(wxGridCellBoolRenderer_destroy, 579).
+-define(wxGridCellBoolEditor_new, 580).
+-define(wxGridCellBoolEditor_IsTrueValue, 581).
+-define(wxGridCellBoolEditor_UseStringValues, 582).
+-define(wxGridCellBoolEditor_destroy, 583).
+-define(wxGridCellFloatRenderer_new, 584).
+-define(wxGridCellFloatRenderer_GetPrecision, 585).
+-define(wxGridCellFloatRenderer_GetWidth, 586).
+-define(wxGridCellFloatRenderer_SetParameters, 587).
+-define(wxGridCellFloatRenderer_SetPrecision, 588).
+-define(wxGridCellFloatRenderer_SetWidth, 589).
+-define(wxGridCellFloatRenderer_destroy, 590).
+-define(wxGridCellFloatEditor_new, 591).
+-define(wxGridCellFloatEditor_SetParameters, 592).
+-define(wxGridCellFloatEditor_destroy, 593).
+-define(wxGridCellStringRenderer_new, 594).
+-define(wxGridCellStringRenderer_destroy, 595).
+-define(wxGridCellTextEditor_new, 596).
+-define(wxGridCellTextEditor_SetParameters, 597).
+-define(wxGridCellTextEditor_destroy, 598).
+-define(wxGridCellChoiceEditor_new, 600).
+-define(wxGridCellChoiceEditor_SetParameters, 601).
+-define(wxGridCellChoiceEditor_destroy, 602).
+-define(wxGridCellNumberRenderer_new, 603).
+-define(wxGridCellNumberRenderer_destroy, 604).
+-define(wxGridCellNumberEditor_new, 605).
+-define(wxGridCellNumberEditor_GetValue, 606).
+-define(wxGridCellNumberEditor_SetParameters, 607).
+-define(wxGridCellNumberEditor_destroy, 608).
+-define(wxGridCellAttr_SetTextColour, 609).
+-define(wxGridCellAttr_SetBackgroundColour, 610).
+-define(wxGridCellAttr_SetFont, 611).
+-define(wxGridCellAttr_SetAlignment, 612).
+-define(wxGridCellAttr_SetReadOnly, 613).
+-define(wxGridCellAttr_SetRenderer, 614).
+-define(wxGridCellAttr_SetEditor, 615).
+-define(wxGridCellAttr_HasTextColour, 616).
+-define(wxGridCellAttr_HasBackgroundColour, 617).
+-define(wxGridCellAttr_HasFont, 618).
+-define(wxGridCellAttr_HasAlignment, 619).
+-define(wxGridCellAttr_HasRenderer, 620).
+-define(wxGridCellAttr_HasEditor, 621).
+-define(wxGridCellAttr_GetTextColour, 622).
+-define(wxGridCellAttr_GetBackgroundColour, 623).
+-define(wxGridCellAttr_GetFont, 624).
+-define(wxGridCellAttr_GetAlignment, 625).
+-define(wxGridCellAttr_GetRenderer, 626).
+-define(wxGridCellAttr_GetEditor, 627).
+-define(wxGridCellAttr_IsReadOnly, 628).
+-define(wxGridCellAttr_SetDefAttr, 629).
+-define(wxDC_Blit, 630).
+-define(wxDC_CalcBoundingBox, 631).
+-define(wxDC_Clear, 632).
+-define(wxDC_ComputeScaleAndOrigin, 633).
+-define(wxDC_CrossHair, 634).
+-define(wxDC_DestroyClippingRegion, 635).
+-define(wxDC_DeviceToLogicalX, 636).
+-define(wxDC_DeviceToLogicalXRel, 637).
+-define(wxDC_DeviceToLogicalY, 638).
+-define(wxDC_DeviceToLogicalYRel, 639).
+-define(wxDC_DrawArc, 640).
+-define(wxDC_DrawBitmap, 641).
+-define(wxDC_DrawCheckMark, 642).
+-define(wxDC_DrawCircle, 643).
+-define(wxDC_DrawEllipse_2, 645).
+-define(wxDC_DrawEllipse_1, 646).
+-define(wxDC_DrawEllipticArc, 647).
+-define(wxDC_DrawIcon, 648).
+-define(wxDC_DrawLabel, 649).
+-define(wxDC_DrawLine, 650).
+-define(wxDC_DrawLines, 651).
+-define(wxDC_DrawPolygon, 653).
+-define(wxDC_DrawPoint, 655).
+-define(wxDC_DrawRectangle_2, 657).
+-define(wxDC_DrawRectangle_1, 658).
+-define(wxDC_DrawRotatedText, 659).
+-define(wxDC_DrawRoundedRectangle_3, 661).
+-define(wxDC_DrawRoundedRectangle_2, 662).
+-define(wxDC_DrawText, 663).
+-define(wxDC_EndDoc, 664).
+-define(wxDC_EndPage, 665).
+-define(wxDC_FloodFill, 666).
+-define(wxDC_GetBackground, 667).
+-define(wxDC_GetBackgroundMode, 668).
+-define(wxDC_GetBrush, 669).
+-define(wxDC_GetCharHeight, 670).
+-define(wxDC_GetCharWidth, 671).
+-define(wxDC_GetClippingBox, 672).
+-define(wxDC_GetFont, 674).
+-define(wxDC_GetLayoutDirection, 675).
+-define(wxDC_GetLogicalFunction, 676).
+-define(wxDC_GetMapMode, 677).
+-define(wxDC_GetMultiLineTextExtent_4, 678).
+-define(wxDC_GetMultiLineTextExtent_1, 679).
+-define(wxDC_GetPartialTextExtents, 680).
+-define(wxDC_GetPen, 681).
+-define(wxDC_GetPixel, 682).
+-define(wxDC_GetPPI, 683).
+-define(wxDC_GetSize, 685).
+-define(wxDC_GetSizeMM, 687).
+-define(wxDC_GetTextBackground, 688).
+-define(wxDC_GetTextExtent_4, 689).
+-define(wxDC_GetTextExtent_1, 690).
+-define(wxDC_GetTextForeground, 692).
+-define(wxDC_GetUserScale, 693).
+-define(wxDC_GradientFillConcentric_3, 694).
+-define(wxDC_GradientFillConcentric_4, 695).
+-define(wxDC_GradientFillLinear, 696).
+-define(wxDC_LogicalToDeviceX, 697).
+-define(wxDC_LogicalToDeviceXRel, 698).
+-define(wxDC_LogicalToDeviceY, 699).
+-define(wxDC_LogicalToDeviceYRel, 700).
+-define(wxDC_MaxX, 701).
+-define(wxDC_MaxY, 702).
+-define(wxDC_MinX, 703).
+-define(wxDC_MinY, 704).
+-define(wxDC_IsOk, 705).
+-define(wxDC_ResetBoundingBox, 706).
+-define(wxDC_SetAxisOrientation, 707).
+-define(wxDC_SetBackground, 708).
+-define(wxDC_SetBackgroundMode, 709).
+-define(wxDC_SetBrush, 710).
+-define(wxDC_SetClippingRegion_2, 712).
+-define(wxDC_SetClippingRegion_1_1, 713).
+-define(wxDC_SetClippingRegion_1_0, 714).
+-define(wxDC_SetDeviceOrigin, 715).
+-define(wxDC_SetFont, 716).
+-define(wxDC_SetLayoutDirection, 717).
+-define(wxDC_SetLogicalFunction, 718).
+-define(wxDC_SetMapMode, 719).
+-define(wxDC_SetPalette, 720).
+-define(wxDC_SetPen, 721).
+-define(wxDC_SetTextBackground, 722).
+-define(wxDC_SetTextForeground, 723).
+-define(wxDC_SetUserScale, 724).
+-define(wxDC_StartDoc, 725).
+-define(wxDC_StartPage, 726).
+-define(wxMirrorDC_new, 727).
+-define(wxMirrorDC_destroy, 728).
+-define(wxScreenDC_new, 729).
+-define(wxScreenDC_destruct, 730).
+-define(wxPostScriptDC_new_0, 731).
+-define(wxPostScriptDC_new_1, 732).
+-define(wxPostScriptDC_destruct, 733).
+-define(wxPostScriptDC_SetResolution, 734).
+-define(wxPostScriptDC_GetResolution, 735).
+-define(wxWindowDC_new_0, 736).
+-define(wxWindowDC_new_1, 737).
+-define(wxWindowDC_destruct, 738).
+-define(wxClientDC_new_0, 739).
+-define(wxClientDC_new_1, 740).
+-define(wxClientDC_destroy, 741).
+-define(wxPaintDC_new_0, 742).
+-define(wxPaintDC_new_1, 743).
+-define(wxPaintDC_destroy, 744).
+-define(wxMemoryDC_new_1_0, 746).
+-define(wxMemoryDC_new_1_1, 747).
+-define(wxMemoryDC_new_0, 748).
+-define(wxMemoryDC_destruct, 750).
+-define(wxMemoryDC_SelectObject, 751).
+-define(wxMemoryDC_SelectObjectAsSource, 752).
+-define(wxBufferedDC_new_0, 753).
+-define(wxBufferedDC_new_2, 754).
+-define(wxBufferedDC_new_3, 755).
+-define(wxBufferedDC_destruct, 756).
+-define(wxBufferedDC_Init_2, 757).
+-define(wxBufferedDC_Init_3, 758).
+-define(wxBufferedPaintDC_new_3, 759).
+-define(wxBufferedPaintDC_new_2, 760).
+-define(wxBufferedPaintDC_destruct, 761).
+-define(wxGraphicsObject_destruct, 762).
+-define(wxGraphicsObject_GetRenderer, 763).
+-define(wxGraphicsObject_IsNull, 764).
+-define(wxGraphicsContext_destruct, 765).
+-define(wxGraphicsContext_Create_1_1, 766).
+-define(wxGraphicsContext_Create_1_0, 767).
+-define(wxGraphicsContext_Create_0, 768).
+-define(wxGraphicsContext_CreatePen, 769).
+-define(wxGraphicsContext_CreateBrush, 770).
+-define(wxGraphicsContext_CreateRadialGradientBrush, 771).
+-define(wxGraphicsContext_CreateLinearGradientBrush, 772).
+-define(wxGraphicsContext_CreateFont, 773).
+-define(wxGraphicsContext_CreateMatrix, 774).
+-define(wxGraphicsContext_CreatePath, 775).
+-define(wxGraphicsContext_Clip_1, 776).
+-define(wxGraphicsContext_Clip_4, 777).
+-define(wxGraphicsContext_ResetClip, 778).
+-define(wxGraphicsContext_DrawBitmap, 779).
+-define(wxGraphicsContext_DrawEllipse, 780).
+-define(wxGraphicsContext_DrawIcon, 781).
+-define(wxGraphicsContext_DrawLines, 782).
+-define(wxGraphicsContext_DrawPath, 783).
+-define(wxGraphicsContext_DrawRectangle, 784).
+-define(wxGraphicsContext_DrawRoundedRectangle, 785).
+-define(wxGraphicsContext_DrawText_3, 786).
+-define(wxGraphicsContext_DrawText_4_0, 787).
+-define(wxGraphicsContext_DrawText_4_1, 788).
+-define(wxGraphicsContext_DrawText_5, 789).
+-define(wxGraphicsContext_FillPath, 790).
+-define(wxGraphicsContext_StrokePath, 791).
+-define(wxGraphicsContext_GetPartialTextExtents, 792).
+-define(wxGraphicsContext_GetTextExtent, 793).
+-define(wxGraphicsContext_Rotate, 794).
+-define(wxGraphicsContext_Scale, 795).
+-define(wxGraphicsContext_Translate, 796).
+-define(wxGraphicsContext_GetTransform, 797).
+-define(wxGraphicsContext_SetTransform, 798).
+-define(wxGraphicsContext_ConcatTransform, 799).
+-define(wxGraphicsContext_SetBrush_1_1, 800).
+-define(wxGraphicsContext_SetBrush_1_0, 801).
+-define(wxGraphicsContext_SetFont_1, 802).
+-define(wxGraphicsContext_SetFont_2, 803).
+-define(wxGraphicsContext_SetPen_1_0, 804).
+-define(wxGraphicsContext_SetPen_1_1, 805).
+-define(wxGraphicsContext_StrokeLine, 806).
+-define(wxGraphicsContext_StrokeLines, 807).
+-define(wxGraphicsMatrix_Concat, 809).
+-define(wxGraphicsMatrix_Get, 811).
+-define(wxGraphicsMatrix_Invert, 812).
+-define(wxGraphicsMatrix_IsEqual, 813).
+-define(wxGraphicsMatrix_IsIdentity, 815).
+-define(wxGraphicsMatrix_Rotate, 816).
+-define(wxGraphicsMatrix_Scale, 817).
+-define(wxGraphicsMatrix_Translate, 818).
+-define(wxGraphicsMatrix_Set, 819).
+-define(wxGraphicsMatrix_TransformPoint, 820).
+-define(wxGraphicsMatrix_TransformDistance, 821).
+-define(wxGraphicsPath_MoveToPoint_2, 822).
+-define(wxGraphicsPath_MoveToPoint_1, 823).
+-define(wxGraphicsPath_AddArc_6, 824).
+-define(wxGraphicsPath_AddArc_5, 825).
+-define(wxGraphicsPath_AddArcToPoint, 826).
+-define(wxGraphicsPath_AddCircle, 827).
+-define(wxGraphicsPath_AddCurveToPoint_6, 828).
+-define(wxGraphicsPath_AddCurveToPoint_3, 829).
+-define(wxGraphicsPath_AddEllipse, 830).
+-define(wxGraphicsPath_AddLineToPoint_2, 831).
+-define(wxGraphicsPath_AddLineToPoint_1, 832).
+-define(wxGraphicsPath_AddPath, 833).
+-define(wxGraphicsPath_AddQuadCurveToPoint, 834).
+-define(wxGraphicsPath_AddRectangle, 835).
+-define(wxGraphicsPath_AddRoundedRectangle, 836).
+-define(wxGraphicsPath_CloseSubpath, 837).
+-define(wxGraphicsPath_Contains_3, 838).
+-define(wxGraphicsPath_Contains_2, 839).
+-define(wxGraphicsPath_GetBox, 841).
+-define(wxGraphicsPath_GetCurrentPoint, 843).
+-define(wxGraphicsPath_Transform, 844).
+-define(wxGraphicsRenderer_GetDefaultRenderer, 845).
+-define(wxGraphicsRenderer_CreateContext_1_1, 846).
+-define(wxGraphicsRenderer_CreateContext_1_0, 847).
+-define(wxGraphicsRenderer_CreatePen, 848).
+-define(wxGraphicsRenderer_CreateBrush, 849).
+-define(wxGraphicsRenderer_CreateLinearGradientBrush, 850).
+-define(wxGraphicsRenderer_CreateRadialGradientBrush, 851).
+-define(wxGraphicsRenderer_CreateFont, 852).
+-define(wxGraphicsRenderer_CreateMatrix, 853).
+-define(wxGraphicsRenderer_CreatePath, 854).
+-define(wxMenuBar_new_1, 856).
+-define(wxMenuBar_new_0, 858).
+-define(wxMenuBar_destruct, 860).
+-define(wxMenuBar_Append, 861).
+-define(wxMenuBar_Check, 862).
+-define(wxMenuBar_Enable_2, 863).
+-define(wxMenuBar_Enable_1, 864).
+-define(wxMenuBar_EnableTop, 865).
+-define(wxMenuBar_FindMenu, 866).
+-define(wxMenuBar_FindMenuItem, 867).
+-define(wxMenuBar_FindItem, 868).
+-define(wxMenuBar_GetHelpString, 869).
+-define(wxMenuBar_GetLabel_1, 870).
+-define(wxMenuBar_GetLabel_0, 871).
+-define(wxMenuBar_GetLabelTop, 872).
+-define(wxMenuBar_GetMenu, 873).
+-define(wxMenuBar_GetMenuCount, 874).
+-define(wxMenuBar_Insert, 875).
+-define(wxMenuBar_IsChecked, 876).
+-define(wxMenuBar_IsEnabled_1, 877).
+-define(wxMenuBar_IsEnabled_0, 878).
+-define(wxMenuBar_Remove, 879).
+-define(wxMenuBar_Replace, 880).
+-define(wxMenuBar_SetHelpString, 881).
+-define(wxMenuBar_SetLabel_2, 882).
+-define(wxMenuBar_SetLabel_1, 883).
+-define(wxMenuBar_SetLabelTop, 884).
+-define(wxControl_GetLabel, 885).
+-define(wxControl_SetLabel, 886).
+-define(wxControlWithItems_Append_1, 887).
+-define(wxControlWithItems_Append_2, 888).
+-define(wxControlWithItems_appendStrings_1, 889).
+-define(wxControlWithItems_Clear, 890).
+-define(wxControlWithItems_Delete, 891).
+-define(wxControlWithItems_FindString, 892).
+-define(wxControlWithItems_getClientData, 893).
+-define(wxControlWithItems_setClientData, 894).
+-define(wxControlWithItems_GetCount, 895).
+-define(wxControlWithItems_GetSelection, 896).
+-define(wxControlWithItems_GetString, 897).
+-define(wxControlWithItems_GetStringSelection, 898).
+-define(wxControlWithItems_Insert_2, 899).
+-define(wxControlWithItems_Insert_3, 900).
+-define(wxControlWithItems_IsEmpty, 901).
+-define(wxControlWithItems_Select, 902).
+-define(wxControlWithItems_SetSelection, 903).
+-define(wxControlWithItems_SetString, 904).
+-define(wxControlWithItems_SetStringSelection, 905).
+-define(wxMenu_new_2, 908).
+-define(wxMenu_new_1, 909).
+-define(wxMenu_destruct, 911).
+-define(wxMenu_Append_3, 912).
+-define(wxMenu_Append_1, 913).
+-define(wxMenu_Append_4_0, 914).
+-define(wxMenu_Append_4_1, 915).
+-define(wxMenu_AppendCheckItem, 916).
+-define(wxMenu_AppendRadioItem, 917).
+-define(wxMenu_AppendSeparator, 918).
+-define(wxMenu_Break, 919).
+-define(wxMenu_Check, 920).
+-define(wxMenu_Delete_1_0, 921).
+-define(wxMenu_Delete_1_1, 922).
+-define(wxMenu_Destroy_1_0, 923).
+-define(wxMenu_Destroy_1_1, 924).
+-define(wxMenu_Enable, 925).
+-define(wxMenu_FindItem_1, 926).
+-define(wxMenu_FindItem_2, 927).
+-define(wxMenu_FindItemByPosition, 928).
+-define(wxMenu_GetHelpString, 929).
+-define(wxMenu_GetLabel, 930).
+-define(wxMenu_GetMenuItemCount, 931).
+-define(wxMenu_GetMenuItems, 932).
+-define(wxMenu_GetTitle, 934).
+-define(wxMenu_Insert_2, 935).
+-define(wxMenu_Insert_3, 936).
+-define(wxMenu_Insert_5_1, 937).
+-define(wxMenu_Insert_5_0, 938).
+-define(wxMenu_InsertCheckItem, 939).
+-define(wxMenu_InsertRadioItem, 940).
+-define(wxMenu_InsertSeparator, 941).
+-define(wxMenu_IsChecked, 942).
+-define(wxMenu_IsEnabled, 943).
+-define(wxMenu_Prepend_1, 944).
+-define(wxMenu_Prepend_2, 945).
+-define(wxMenu_Prepend_4_1, 946).
+-define(wxMenu_Prepend_4_0, 947).
+-define(wxMenu_PrependCheckItem, 948).
+-define(wxMenu_PrependRadioItem, 949).
+-define(wxMenu_PrependSeparator, 950).
+-define(wxMenu_Remove_1_0, 951).
+-define(wxMenu_Remove_1_1, 952).
+-define(wxMenu_SetHelpString, 953).
+-define(wxMenu_SetLabel, 954).
+-define(wxMenu_SetTitle, 955).
+-define(wxMenuItem_new, 956).
+-define(wxMenuItem_destruct, 958).
+-define(wxMenuItem_Check, 959).
+-define(wxMenuItem_Enable, 960).
+-define(wxMenuItem_GetBitmap, 961).
+-define(wxMenuItem_GetHelp, 962).
+-define(wxMenuItem_GetId, 963).
+-define(wxMenuItem_GetKind, 964).
+-define(wxMenuItem_GetLabel, 965).
+-define(wxMenuItem_GetLabelFromText, 966).
+-define(wxMenuItem_GetMenu, 967).
+-define(wxMenuItem_GetText, 968).
+-define(wxMenuItem_GetSubMenu, 969).
+-define(wxMenuItem_IsCheckable, 970).
+-define(wxMenuItem_IsChecked, 971).
+-define(wxMenuItem_IsEnabled, 972).
+-define(wxMenuItem_IsSeparator, 973).
+-define(wxMenuItem_IsSubMenu, 974).
+-define(wxMenuItem_SetBitmap, 975).
+-define(wxMenuItem_SetHelp, 976).
+-define(wxMenuItem_SetMenu, 977).
+-define(wxMenuItem_SetSubMenu, 978).
+-define(wxMenuItem_SetText, 979).
+-define(wxToolBar_AddControl, 980).
+-define(wxToolBar_AddSeparator, 981).
+-define(wxToolBar_AddTool_5, 982).
+-define(wxToolBar_AddTool_4_0, 983).
+-define(wxToolBar_AddTool_1, 984).
+-define(wxToolBar_AddTool_4_1, 985).
+-define(wxToolBar_AddTool_3, 986).
+-define(wxToolBar_AddTool_6, 987).
+-define(wxToolBar_AddCheckTool, 988).
+-define(wxToolBar_AddRadioTool, 989).
+-define(wxToolBar_AddStretchableSpace, 990).
+-define(wxToolBar_InsertStretchableSpace, 991).
+-define(wxToolBar_DeleteTool, 992).
+-define(wxToolBar_DeleteToolByPos, 993).
+-define(wxToolBar_EnableTool, 994).
+-define(wxToolBar_FindById, 995).
+-define(wxToolBar_FindControl, 996).
+-define(wxToolBar_FindToolForPosition, 997).
+-define(wxToolBar_GetToolSize, 998).
+-define(wxToolBar_GetToolBitmapSize, 999).
+-define(wxToolBar_GetMargins, 1000).
+-define(wxToolBar_GetToolEnabled, 1001).
+-define(wxToolBar_GetToolLongHelp, 1002).
+-define(wxToolBar_GetToolPacking, 1003).
+-define(wxToolBar_GetToolPos, 1004).
+-define(wxToolBar_GetToolSeparation, 1005).
+-define(wxToolBar_GetToolShortHelp, 1006).
+-define(wxToolBar_GetToolState, 1007).
+-define(wxToolBar_InsertControl, 1008).
+-define(wxToolBar_InsertSeparator, 1009).
+-define(wxToolBar_InsertTool_5, 1010).
+-define(wxToolBar_InsertTool_2, 1011).
+-define(wxToolBar_InsertTool_4, 1012).
+-define(wxToolBar_Realize, 1013).
+-define(wxToolBar_RemoveTool, 1014).
+-define(wxToolBar_SetMargins, 1015).
+-define(wxToolBar_SetToolBitmapSize, 1016).
+-define(wxToolBar_SetToolLongHelp, 1017).
+-define(wxToolBar_SetToolPacking, 1018).
+-define(wxToolBar_SetToolShortHelp, 1019).
+-define(wxToolBar_SetToolSeparation, 1020).
+-define(wxToolBar_ToggleTool, 1021).
+-define(wxStatusBar_new_0, 1023).
+-define(wxStatusBar_new_2, 1024).
+-define(wxStatusBar_destruct, 1026).
+-define(wxStatusBar_Create, 1027).
+-define(wxStatusBar_GetFieldRect, 1028).
+-define(wxStatusBar_GetFieldsCount, 1029).
+-define(wxStatusBar_GetStatusText, 1030).
+-define(wxStatusBar_PopStatusText, 1031).
+-define(wxStatusBar_PushStatusText, 1032).
+-define(wxStatusBar_SetFieldsCount, 1033).
+-define(wxStatusBar_SetMinHeight, 1034).
+-define(wxStatusBar_SetStatusText, 1035).
+-define(wxStatusBar_SetStatusWidths, 1036).
+-define(wxStatusBar_SetStatusStyles, 1037).
+-define(wxBitmap_new_0, 1038).
+-define(wxBitmap_new_3, 1039).
+-define(wxBitmap_new_4, 1040).
+-define(wxBitmap_new_2_0, 1041).
+-define(wxBitmap_new_2_1, 1042).
+-define(wxBitmap_destruct, 1043).
+-define(wxBitmap_ConvertToImage, 1044).
+-define(wxBitmap_CopyFromIcon, 1045).
+-define(wxBitmap_Create, 1046).
+-define(wxBitmap_GetDepth, 1047).
+-define(wxBitmap_GetHeight, 1048).
+-define(wxBitmap_GetPalette, 1049).
+-define(wxBitmap_GetMask, 1050).
+-define(wxBitmap_GetWidth, 1051).
+-define(wxBitmap_GetSubBitmap, 1052).
+-define(wxBitmap_LoadFile, 1053).
+-define(wxBitmap_Ok, 1054).
+-define(wxBitmap_SaveFile, 1055).
+-define(wxBitmap_SetDepth, 1056).
+-define(wxBitmap_SetHeight, 1057).
+-define(wxBitmap_SetMask, 1058).
+-define(wxBitmap_SetPalette, 1059).
+-define(wxBitmap_SetWidth, 1060).
+-define(wxIcon_new_0, 1061).
+-define(wxIcon_new_2, 1062).
+-define(wxIcon_new_1, 1063).
+-define(wxIcon_CopyFromBitmap, 1064).
+-define(wxIcon_destroy, 1065).
+-define(wxIconBundle_new_0, 1066).
+-define(wxIconBundle_new_2, 1067).
+-define(wxIconBundle_new_1_0, 1068).
+-define(wxIconBundle_new_1_1, 1069).
+-define(wxIconBundle_destruct, 1070).
+-define(wxIconBundle_AddIcon_2, 1071).
+-define(wxIconBundle_AddIcon_1, 1072).
+-define(wxIconBundle_GetIcon_1_1, 1073).
+-define(wxIconBundle_GetIcon_1_0, 1074).
+-define(wxCursor_new_0, 1075).
+-define(wxCursor_new_1_0, 1076).
+-define(wxCursor_new_1_1, 1077).
+-define(wxCursor_new_4, 1078).
+-define(wxCursor_destruct, 1079).
+-define(wxCursor_Ok, 1080).
+-define(wxMask_new_0, 1081).
+-define(wxMask_new_2_1, 1082).
+-define(wxMask_new_2_0, 1083).
+-define(wxMask_new_1, 1084).
+-define(wxMask_destruct, 1085).
+-define(wxMask_Create_2_1, 1086).
+-define(wxMask_Create_2_0, 1087).
+-define(wxMask_Create_1, 1088).
+-define(wxImage_new_0, 1089).
+-define(wxImage_new_3_0, 1090).
+-define(wxImage_new_4, 1091).
+-define(wxImage_new_5, 1092).
+-define(wxImage_new_2, 1093).
+-define(wxImage_new_3_1, 1094).
+-define(wxImage_Blur, 1095).
+-define(wxImage_BlurHorizontal, 1096).
+-define(wxImage_BlurVertical, 1097).
+-define(wxImage_ConvertAlphaToMask, 1098).
+-define(wxImage_ConvertToGreyscale, 1099).
+-define(wxImage_ConvertToMono, 1100).
+-define(wxImage_Copy, 1101).
+-define(wxImage_Create_3, 1102).
+-define(wxImage_Create_4, 1103).
+-define(wxImage_Create_5, 1104).
+-define(wxImage_Destroy, 1105).
+-define(wxImage_FindFirstUnusedColour, 1106).
+-define(wxImage_GetImageExtWildcard, 1107).
+-define(wxImage_GetAlpha_2, 1108).
+-define(wxImage_GetAlpha_0, 1109).
+-define(wxImage_GetBlue, 1110).
+-define(wxImage_GetData, 1111).
+-define(wxImage_GetGreen, 1112).
+-define(wxImage_GetImageCount, 1113).
+-define(wxImage_GetHeight, 1114).
+-define(wxImage_GetMaskBlue, 1115).
+-define(wxImage_GetMaskGreen, 1116).
+-define(wxImage_GetMaskRed, 1117).
+-define(wxImage_GetOrFindMaskColour, 1118).
+-define(wxImage_GetPalette, 1119).
+-define(wxImage_GetRed, 1120).
+-define(wxImage_GetSubImage, 1121).
+-define(wxImage_GetWidth, 1122).
+-define(wxImage_HasAlpha, 1123).
+-define(wxImage_HasMask, 1124).
+-define(wxImage_GetOption, 1125).
+-define(wxImage_GetOptionInt, 1126).
+-define(wxImage_HasOption, 1127).
+-define(wxImage_InitAlpha, 1128).
+-define(wxImage_InitStandardHandlers, 1129).
+-define(wxImage_IsTransparent, 1130).
+-define(wxImage_LoadFile_2, 1131).
+-define(wxImage_LoadFile_3, 1132).
+-define(wxImage_Ok, 1133).
+-define(wxImage_RemoveHandler, 1134).
+-define(wxImage_Mirror, 1135).
+-define(wxImage_Replace, 1136).
+-define(wxImage_Rescale, 1137).
+-define(wxImage_Resize, 1138).
+-define(wxImage_Rotate, 1139).
+-define(wxImage_RotateHue, 1140).
+-define(wxImage_Rotate90, 1141).
+-define(wxImage_SaveFile_1, 1142).
+-define(wxImage_SaveFile_2_0, 1143).
+-define(wxImage_SaveFile_2_1, 1144).
+-define(wxImage_Scale, 1145).
+-define(wxImage_Size, 1146).
+-define(wxImage_SetAlpha_3, 1147).
+-define(wxImage_SetAlpha_2, 1148).
+-define(wxImage_SetData_2, 1149).
+-define(wxImage_SetData_4, 1150).
+-define(wxImage_SetMask, 1151).
+-define(wxImage_SetMaskColour, 1152).
+-define(wxImage_SetMaskFromImage, 1153).
+-define(wxImage_SetOption_2_1, 1154).
+-define(wxImage_SetOption_2_0, 1155).
+-define(wxImage_SetPalette, 1156).
+-define(wxImage_SetRGB_5, 1157).
+-define(wxImage_SetRGB_4, 1158).
+-define(wxImage_destroy, 1159).
+-define(wxBrush_new_0, 1160).
+-define(wxBrush_new_2, 1161).
+-define(wxBrush_new_1, 1162).
+-define(wxBrush_destruct, 1164).
+-define(wxBrush_GetColour, 1165).
+-define(wxBrush_GetStipple, 1166).
+-define(wxBrush_GetStyle, 1167).
+-define(wxBrush_IsHatch, 1168).
+-define(wxBrush_IsOk, 1169).
+-define(wxBrush_SetColour_1, 1170).
+-define(wxBrush_SetColour_3, 1171).
+-define(wxBrush_SetStipple, 1172).
+-define(wxBrush_SetStyle, 1173).
+-define(wxPen_new_0, 1174).
+-define(wxPen_new_2, 1175).
+-define(wxPen_destruct, 1176).
+-define(wxPen_GetCap, 1177).
+-define(wxPen_GetColour, 1178).
+-define(wxPen_GetJoin, 1179).
+-define(wxPen_GetStyle, 1180).
+-define(wxPen_GetWidth, 1181).
+-define(wxPen_IsOk, 1182).
+-define(wxPen_SetCap, 1183).
+-define(wxPen_SetColour_1, 1184).
+-define(wxPen_SetColour_3, 1185).
+-define(wxPen_SetJoin, 1186).
+-define(wxPen_SetStyle, 1187).
+-define(wxPen_SetWidth, 1188).
+-define(wxRegion_new_0, 1189).
+-define(wxRegion_new_4, 1190).
+-define(wxRegion_new_2, 1191).
+-define(wxRegion_new_1_1, 1192).
+-define(wxRegion_new_1_0, 1194).
+-define(wxRegion_destruct, 1196).
+-define(wxRegion_Clear, 1197).
+-define(wxRegion_Contains_2, 1198).
+-define(wxRegion_Contains_1_0, 1199).
+-define(wxRegion_Contains_4, 1200).
+-define(wxRegion_Contains_1_1, 1201).
+-define(wxRegion_ConvertToBitmap, 1202).
+-define(wxRegion_GetBox, 1203).
+-define(wxRegion_Intersect_4, 1204).
+-define(wxRegion_Intersect_1_1, 1205).
+-define(wxRegion_Intersect_1_0, 1206).
+-define(wxRegion_IsEmpty, 1207).
+-define(wxRegion_Subtract_4, 1208).
+-define(wxRegion_Subtract_1_1, 1209).
+-define(wxRegion_Subtract_1_0, 1210).
+-define(wxRegion_Offset_2, 1211).
+-define(wxRegion_Offset_1, 1212).
+-define(wxRegion_Union_4, 1213).
+-define(wxRegion_Union_1_2, 1214).
+-define(wxRegion_Union_1_1, 1215).
+-define(wxRegion_Union_1_0, 1216).
+-define(wxRegion_Union_3, 1217).
+-define(wxRegion_Xor_4, 1218).
+-define(wxRegion_Xor_1_1, 1219).
+-define(wxRegion_Xor_1_0, 1220).
+-define(wxAcceleratorTable_new_0, 1221).
+-define(wxAcceleratorTable_new_2, 1222).
+-define(wxAcceleratorTable_destruct, 1223).
+-define(wxAcceleratorTable_Ok, 1224).
+-define(wxAcceleratorEntry_new_1_0, 1225).
+-define(wxAcceleratorEntry_new_1_1, 1226).
+-define(wxAcceleratorEntry_GetCommand, 1227).
+-define(wxAcceleratorEntry_GetFlags, 1228).
+-define(wxAcceleratorEntry_GetKeyCode, 1229).
+-define(wxAcceleratorEntry_Set, 1230).
+-define(wxAcceleratorEntry_destroy, 1231).
+-define(wxCaret_new_3, 1236).
+-define(wxCaret_new_2, 1237).
+-define(wxCaret_destruct, 1239).
+-define(wxCaret_Create_3, 1240).
+-define(wxCaret_Create_2, 1241).
+-define(wxCaret_GetBlinkTime, 1242).
+-define(wxCaret_GetPosition, 1244).
+-define(wxCaret_GetSize, 1246).
+-define(wxCaret_GetWindow, 1247).
+-define(wxCaret_Hide, 1248).
+-define(wxCaret_IsOk, 1249).
+-define(wxCaret_IsVisible, 1250).
+-define(wxCaret_Move_2, 1251).
+-define(wxCaret_Move_1, 1252).
+-define(wxCaret_SetBlinkTime, 1253).
+-define(wxCaret_SetSize_2, 1254).
+-define(wxCaret_SetSize_1, 1255).
+-define(wxCaret_Show, 1256).
+-define(wxSizer_Add_2_1, 1257).
+-define(wxSizer_Add_2_0, 1258).
+-define(wxSizer_Add_3, 1259).
+-define(wxSizer_Add_2_3, 1260).
+-define(wxSizer_Add_2_2, 1261).
+-define(wxSizer_AddSpacer, 1262).
+-define(wxSizer_AddStretchSpacer, 1263).
+-define(wxSizer_CalcMin, 1264).
+-define(wxSizer_Clear, 1265).
+-define(wxSizer_Detach_1_2, 1266).
+-define(wxSizer_Detach_1_1, 1267).
+-define(wxSizer_Detach_1_0, 1268).
+-define(wxSizer_Fit, 1269).
+-define(wxSizer_FitInside, 1270).
+-define(wxSizer_GetChildren, 1271).
+-define(wxSizer_GetItem_2_1, 1272).
+-define(wxSizer_GetItem_2_0, 1273).
+-define(wxSizer_GetItem_1, 1274).
+-define(wxSizer_GetSize, 1275).
+-define(wxSizer_GetPosition, 1276).
+-define(wxSizer_GetMinSize, 1277).
+-define(wxSizer_Hide_2_0, 1278).
+-define(wxSizer_Hide_2_1, 1279).
+-define(wxSizer_Hide_1, 1280).
+-define(wxSizer_Insert_3_1, 1281).
+-define(wxSizer_Insert_3_0, 1282).
+-define(wxSizer_Insert_4, 1283).
+-define(wxSizer_Insert_3_3, 1284).
+-define(wxSizer_Insert_3_2, 1285).
+-define(wxSizer_Insert_2, 1286).
+-define(wxSizer_InsertSpacer, 1287).
+-define(wxSizer_InsertStretchSpacer, 1288).
+-define(wxSizer_IsShown_1_2, 1289).
+-define(wxSizer_IsShown_1_1, 1290).
+-define(wxSizer_IsShown_1_0, 1291).
+-define(wxSizer_Layout, 1292).
+-define(wxSizer_Prepend_2_1, 1293).
+-define(wxSizer_Prepend_2_0, 1294).
+-define(wxSizer_Prepend_3, 1295).
+-define(wxSizer_Prepend_2_3, 1296).
+-define(wxSizer_Prepend_2_2, 1297).
+-define(wxSizer_Prepend_1, 1298).
+-define(wxSizer_PrependSpacer, 1299).
+-define(wxSizer_PrependStretchSpacer, 1300).
+-define(wxSizer_RecalcSizes, 1301).
+-define(wxSizer_Remove_1_1, 1302).
+-define(wxSizer_Remove_1_0, 1303).
+-define(wxSizer_Replace_3_1, 1304).
+-define(wxSizer_Replace_3_0, 1305).
+-define(wxSizer_Replace_2, 1306).
+-define(wxSizer_SetDimension, 1307).
+-define(wxSizer_SetMinSize_2, 1308).
+-define(wxSizer_SetMinSize_1, 1309).
+-define(wxSizer_SetItemMinSize_3_2, 1310).
+-define(wxSizer_SetItemMinSize_2_2, 1311).
+-define(wxSizer_SetItemMinSize_3_1, 1312).
+-define(wxSizer_SetItemMinSize_2_1, 1313).
+-define(wxSizer_SetItemMinSize_3_0, 1314).
+-define(wxSizer_SetItemMinSize_2_0, 1315).
+-define(wxSizer_SetSizeHints, 1316).
+-define(wxSizer_SetVirtualSizeHints, 1317).
+-define(wxSizer_Show_2_2, 1318).
+-define(wxSizer_Show_2_1, 1319).
+-define(wxSizer_Show_2_0, 1320).
+-define(wxSizer_Show_1, 1321).
+-define(wxSizerFlags_new, 1322).
+-define(wxSizerFlags_Align, 1323).
+-define(wxSizerFlags_Border_2, 1324).
+-define(wxSizerFlags_Border_1, 1325).
+-define(wxSizerFlags_Center, 1326).
+-define(wxSizerFlags_Centre, 1327).
+-define(wxSizerFlags_Expand, 1328).
+-define(wxSizerFlags_Left, 1329).
+-define(wxSizerFlags_Proportion, 1330).
+-define(wxSizerFlags_Right, 1331).
+-define(wxSizerFlags_destroy, 1332).
+-define(wxSizerItem_new_5_1, 1333).
+-define(wxSizerItem_new_2_1, 1334).
+-define(wxSizerItem_new_5_0, 1335).
+-define(wxSizerItem_new_2_0, 1336).
+-define(wxSizerItem_new_6, 1337).
+-define(wxSizerItem_new_3, 1338).
+-define(wxSizerItem_new_0, 1339).
+-define(wxSizerItem_destruct, 1340).
+-define(wxSizerItem_CalcMin, 1341).
+-define(wxSizerItem_DeleteWindows, 1342).
+-define(wxSizerItem_DetachSizer, 1343).
+-define(wxSizerItem_GetBorder, 1344).
+-define(wxSizerItem_GetFlag, 1345).
+-define(wxSizerItem_GetMinSize, 1346).
+-define(wxSizerItem_GetPosition, 1347).
+-define(wxSizerItem_GetProportion, 1348).
+-define(wxSizerItem_GetRatio, 1349).
+-define(wxSizerItem_GetRect, 1350).
+-define(wxSizerItem_GetSize, 1351).
+-define(wxSizerItem_GetSizer, 1352).
+-define(wxSizerItem_GetSpacer, 1353).
+-define(wxSizerItem_GetUserData, 1354).
+-define(wxSizerItem_GetWindow, 1355).
+-define(wxSizerItem_IsSizer, 1356).
+-define(wxSizerItem_IsShown, 1357).
+-define(wxSizerItem_IsSpacer, 1358).
+-define(wxSizerItem_IsWindow, 1359).
+-define(wxSizerItem_SetBorder, 1360).
+-define(wxSizerItem_SetDimension, 1361).
+-define(wxSizerItem_SetFlag, 1362).
+-define(wxSizerItem_SetInitSize, 1363).
+-define(wxSizerItem_SetMinSize_1, 1364).
+-define(wxSizerItem_SetMinSize_2, 1365).
+-define(wxSizerItem_SetProportion, 1366).
+-define(wxSizerItem_SetRatio_2, 1367).
+-define(wxSizerItem_SetRatio_1_1, 1368).
+-define(wxSizerItem_SetRatio_1_0, 1369).
+-define(wxSizerItem_SetSizer, 1370).
+-define(wxSizerItem_SetSpacer_1, 1371).
+-define(wxSizerItem_SetSpacer_2, 1372).
+-define(wxSizerItem_SetWindow, 1373).
+-define(wxSizerItem_Show, 1374).
+-define(wxBoxSizer_new, 1375).
+-define(wxBoxSizer_GetOrientation, 1376).
+-define(wxBoxSizer_destroy, 1377).
+-define(wxStaticBoxSizer_new_2, 1378).
+-define(wxStaticBoxSizer_new_3, 1379).
+-define(wxStaticBoxSizer_GetStaticBox, 1380).
+-define(wxStaticBoxSizer_destroy, 1381).
+-define(wxGridSizer_new_4, 1382).
+-define(wxGridSizer_new_2, 1383).
+-define(wxGridSizer_GetCols, 1384).
+-define(wxGridSizer_GetHGap, 1385).
+-define(wxGridSizer_GetRows, 1386).
+-define(wxGridSizer_GetVGap, 1387).
+-define(wxGridSizer_SetCols, 1388).
+-define(wxGridSizer_SetHGap, 1389).
+-define(wxGridSizer_SetRows, 1390).
+-define(wxGridSizer_SetVGap, 1391).
+-define(wxGridSizer_destroy, 1392).
+-define(wxFlexGridSizer_new_4, 1393).
+-define(wxFlexGridSizer_new_2, 1394).
+-define(wxFlexGridSizer_AddGrowableCol, 1395).
+-define(wxFlexGridSizer_AddGrowableRow, 1396).
+-define(wxFlexGridSizer_GetFlexibleDirection, 1397).
+-define(wxFlexGridSizer_GetNonFlexibleGrowMode, 1398).
+-define(wxFlexGridSizer_RemoveGrowableCol, 1399).
+-define(wxFlexGridSizer_RemoveGrowableRow, 1400).
+-define(wxFlexGridSizer_SetFlexibleDirection, 1401).
+-define(wxFlexGridSizer_SetNonFlexibleGrowMode, 1402).
+-define(wxFlexGridSizer_destroy, 1403).
+-define(wxGridBagSizer_new, 1404).
+-define(wxGridBagSizer_Add_3_2, 1405).
+-define(wxGridBagSizer_Add_3_1, 1406).
+-define(wxGridBagSizer_Add_4, 1407).
+-define(wxGridBagSizer_Add_1_0, 1408).
+-define(wxGridBagSizer_Add_2_1, 1409).
+-define(wxGridBagSizer_Add_2_0, 1410).
+-define(wxGridBagSizer_Add_3_0, 1411).
+-define(wxGridBagSizer_Add_1_1, 1412).
+-define(wxGridBagSizer_CalcMin, 1413).
+-define(wxGridBagSizer_CheckForIntersection_2, 1414).
+-define(wxGridBagSizer_CheckForIntersection_3, 1415).
+-define(wxGridBagSizer_FindItem_1_1, 1416).
+-define(wxGridBagSizer_FindItem_1_0, 1417).
+-define(wxGridBagSizer_FindItemAtPoint, 1418).
+-define(wxGridBagSizer_FindItemAtPosition, 1419).
+-define(wxGridBagSizer_FindItemWithData, 1420).
+-define(wxGridBagSizer_GetCellSize, 1421).
+-define(wxGridBagSizer_GetEmptyCellSize, 1422).
+-define(wxGridBagSizer_GetItemPosition_1_2, 1423).
+-define(wxGridBagSizer_GetItemPosition_1_1, 1424).
+-define(wxGridBagSizer_GetItemPosition_1_0, 1425).
+-define(wxGridBagSizer_GetItemSpan_1_2, 1426).
+-define(wxGridBagSizer_GetItemSpan_1_1, 1427).
+-define(wxGridBagSizer_GetItemSpan_1_0, 1428).
+-define(wxGridBagSizer_SetEmptyCellSize, 1429).
+-define(wxGridBagSizer_SetItemPosition_2_2, 1430).
+-define(wxGridBagSizer_SetItemPosition_2_1, 1431).
+-define(wxGridBagSizer_SetItemPosition_2_0, 1432).
+-define(wxGridBagSizer_SetItemSpan_2_2, 1433).
+-define(wxGridBagSizer_SetItemSpan_2_1, 1434).
+-define(wxGridBagSizer_SetItemSpan_2_0, 1435).
+-define(wxGridBagSizer_destroy, 1436).
+-define(wxStdDialogButtonSizer_new, 1437).
+-define(wxStdDialogButtonSizer_AddButton, 1438).
+-define(wxStdDialogButtonSizer_Realize, 1439).
+-define(wxStdDialogButtonSizer_SetAffirmativeButton, 1440).
+-define(wxStdDialogButtonSizer_SetCancelButton, 1441).
+-define(wxStdDialogButtonSizer_SetNegativeButton, 1442).
+-define(wxStdDialogButtonSizer_destroy, 1443).
+-define(wxFont_new_0, 1444).
+-define(wxFont_new_1, 1445).
+-define(wxFont_new_5, 1446).
+-define(wxFont_destruct, 1448).
+-define(wxFont_IsFixedWidth, 1449).
+-define(wxFont_GetDefaultEncoding, 1450).
+-define(wxFont_GetFaceName, 1451).
+-define(wxFont_GetFamily, 1452).
+-define(wxFont_GetNativeFontInfoDesc, 1453).
+-define(wxFont_GetNativeFontInfoUserDesc, 1454).
+-define(wxFont_GetPointSize, 1455).
+-define(wxFont_GetStyle, 1456).
+-define(wxFont_GetUnderlined, 1457).
+-define(wxFont_GetWeight, 1458).
+-define(wxFont_Ok, 1459).
+-define(wxFont_SetDefaultEncoding, 1460).
+-define(wxFont_SetFaceName, 1461).
+-define(wxFont_SetFamily, 1462).
+-define(wxFont_SetPointSize, 1463).
+-define(wxFont_SetStyle, 1464).
+-define(wxFont_SetUnderlined, 1465).
+-define(wxFont_SetWeight, 1466).
+-define(wxToolTip_Enable, 1467).
+-define(wxToolTip_SetDelay, 1468).
+-define(wxToolTip_new, 1469).
+-define(wxToolTip_SetTip, 1470).
+-define(wxToolTip_GetTip, 1471).
+-define(wxToolTip_GetWindow, 1472).
+-define(wxToolTip_destroy, 1473).
+-define(wxButton_new_3, 1475).
+-define(wxButton_new_0, 1476).
+-define(wxButton_destruct, 1477).
+-define(wxButton_Create, 1478).
+-define(wxButton_GetDefaultSize, 1479).
+-define(wxButton_SetDefault, 1480).
+-define(wxButton_SetLabel, 1481).
+-define(wxBitmapButton_new_4, 1483).
+-define(wxBitmapButton_new_0, 1484).
+-define(wxBitmapButton_Create, 1485).
+-define(wxBitmapButton_GetBitmapDisabled, 1486).
+-define(wxBitmapButton_GetBitmapFocus, 1488).
+-define(wxBitmapButton_GetBitmapLabel, 1490).
+-define(wxBitmapButton_GetBitmapSelected, 1492).
+-define(wxBitmapButton_SetBitmapDisabled, 1494).
+-define(wxBitmapButton_SetBitmapFocus, 1495).
+-define(wxBitmapButton_SetBitmapLabel, 1496).
+-define(wxBitmapButton_SetBitmapSelected, 1497).
+-define(wxBitmapButton_destroy, 1498).
+-define(wxToggleButton_new_0, 1499).
+-define(wxToggleButton_new_4, 1500).
+-define(wxToggleButton_Create, 1501).
+-define(wxToggleButton_GetValue, 1502).
+-define(wxToggleButton_SetValue, 1503).
+-define(wxToggleButton_destroy, 1504).
+-define(wxCalendarCtrl_new_0, 1505).
+-define(wxCalendarCtrl_new_3, 1506).
+-define(wxCalendarCtrl_Create, 1507).
+-define(wxCalendarCtrl_destruct, 1508).
+-define(wxCalendarCtrl_SetDate, 1509).
+-define(wxCalendarCtrl_GetDate, 1510).
+-define(wxCalendarCtrl_EnableYearChange, 1511).
+-define(wxCalendarCtrl_EnableMonthChange, 1512).
+-define(wxCalendarCtrl_EnableHolidayDisplay, 1513).
+-define(wxCalendarCtrl_SetHeaderColours, 1514).
+-define(wxCalendarCtrl_GetHeaderColourFg, 1515).
+-define(wxCalendarCtrl_GetHeaderColourBg, 1516).
+-define(wxCalendarCtrl_SetHighlightColours, 1517).
+-define(wxCalendarCtrl_GetHighlightColourFg, 1518).
+-define(wxCalendarCtrl_GetHighlightColourBg, 1519).
+-define(wxCalendarCtrl_SetHolidayColours, 1520).
+-define(wxCalendarCtrl_GetHolidayColourFg, 1521).
+-define(wxCalendarCtrl_GetHolidayColourBg, 1522).
+-define(wxCalendarCtrl_GetAttr, 1523).
+-define(wxCalendarCtrl_SetAttr, 1524).
+-define(wxCalendarCtrl_SetHoliday, 1525).
+-define(wxCalendarCtrl_ResetAttr, 1526).
+-define(wxCalendarCtrl_HitTest, 1527).
+-define(wxCalendarDateAttr_new_0, 1528).
+-define(wxCalendarDateAttr_new_2_1, 1529).
+-define(wxCalendarDateAttr_new_2_0, 1530).
+-define(wxCalendarDateAttr_SetTextColour, 1531).
+-define(wxCalendarDateAttr_SetBackgroundColour, 1532).
+-define(wxCalendarDateAttr_SetBorderColour, 1533).
+-define(wxCalendarDateAttr_SetFont, 1534).
+-define(wxCalendarDateAttr_SetBorder, 1535).
+-define(wxCalendarDateAttr_SetHoliday, 1536).
+-define(wxCalendarDateAttr_HasTextColour, 1537).
+-define(wxCalendarDateAttr_HasBackgroundColour, 1538).
+-define(wxCalendarDateAttr_HasBorderColour, 1539).
+-define(wxCalendarDateAttr_HasFont, 1540).
+-define(wxCalendarDateAttr_HasBorder, 1541).
+-define(wxCalendarDateAttr_IsHoliday, 1542).
+-define(wxCalendarDateAttr_GetTextColour, 1543).
+-define(wxCalendarDateAttr_GetBackgroundColour, 1544).
+-define(wxCalendarDateAttr_GetBorderColour, 1545).
+-define(wxCalendarDateAttr_GetFont, 1546).
+-define(wxCalendarDateAttr_GetBorder, 1547).
+-define(wxCalendarDateAttr_destroy, 1548).
+-define(wxCheckBox_new_4, 1550).
+-define(wxCheckBox_new_0, 1551).
+-define(wxCheckBox_Create, 1552).
+-define(wxCheckBox_GetValue, 1553).
+-define(wxCheckBox_Get3StateValue, 1554).
+-define(wxCheckBox_Is3rdStateAllowedForUser, 1555).
+-define(wxCheckBox_Is3State, 1556).
+-define(wxCheckBox_IsChecked, 1557).
+-define(wxCheckBox_SetValue, 1558).
+-define(wxCheckBox_Set3StateValue, 1559).
+-define(wxCheckBox_destroy, 1560).
+-define(wxCheckListBox_new_0, 1561).
+-define(wxCheckListBox_new_3, 1563).
+-define(wxCheckListBox_Check, 1564).
+-define(wxCheckListBox_IsChecked, 1565).
+-define(wxCheckListBox_destroy, 1566).
+-define(wxChoice_new_3, 1569).
+-define(wxChoice_new_0, 1570).
+-define(wxChoice_destruct, 1572).
+-define(wxChoice_Create, 1574).
+-define(wxChoice_Delete, 1575).
+-define(wxChoice_GetColumns, 1576).
+-define(wxChoice_SetColumns, 1577).
+-define(wxComboBox_new_0, 1578).
+-define(wxComboBox_new_3, 1580).
+-define(wxComboBox_destruct, 1581).
+-define(wxComboBox_Create, 1583).
+-define(wxComboBox_CanCopy, 1584).
+-define(wxComboBox_CanCut, 1585).
+-define(wxComboBox_CanPaste, 1586).
+-define(wxComboBox_CanRedo, 1587).
+-define(wxComboBox_CanUndo, 1588).
+-define(wxComboBox_Copy, 1589).
+-define(wxComboBox_Cut, 1590).
+-define(wxComboBox_GetInsertionPoint, 1591).
+-define(wxComboBox_GetLastPosition, 1592).
+-define(wxComboBox_GetValue, 1593).
+-define(wxComboBox_Paste, 1594).
+-define(wxComboBox_Redo, 1595).
+-define(wxComboBox_Replace, 1596).
+-define(wxComboBox_Remove, 1597).
+-define(wxComboBox_SetInsertionPoint, 1598).
+-define(wxComboBox_SetInsertionPointEnd, 1599).
+-define(wxComboBox_SetSelection_1, 1600).
+-define(wxComboBox_SetSelection_2, 1601).
+-define(wxComboBox_SetValue, 1602).
+-define(wxComboBox_Undo, 1603).
+-define(wxGauge_new_0, 1604).
+-define(wxGauge_new_4, 1605).
+-define(wxGauge_Create, 1606).
+-define(wxGauge_GetRange, 1607).
+-define(wxGauge_GetValue, 1608).
+-define(wxGauge_IsVertical, 1609).
+-define(wxGauge_SetRange, 1610).
+-define(wxGauge_SetValue, 1611).
+-define(wxGauge_Pulse, 1612).
+-define(wxGauge_destroy, 1613).
+-define(wxGenericDirCtrl_new_0, 1614).
+-define(wxGenericDirCtrl_new_2, 1615).
+-define(wxGenericDirCtrl_destruct, 1616).
+-define(wxGenericDirCtrl_Create, 1617).
+-define(wxGenericDirCtrl_Init, 1618).
+-define(wxGenericDirCtrl_CollapseTree, 1619).
+-define(wxGenericDirCtrl_ExpandPath, 1620).
+-define(wxGenericDirCtrl_GetDefaultPath, 1621).
+-define(wxGenericDirCtrl_GetPath, 1622).
+-define(wxGenericDirCtrl_GetFilePath, 1623).
+-define(wxGenericDirCtrl_GetFilter, 1624).
+-define(wxGenericDirCtrl_GetFilterIndex, 1625).
+-define(wxGenericDirCtrl_GetRootId, 1626).
+-define(wxGenericDirCtrl_GetTreeCtrl, 1627).
+-define(wxGenericDirCtrl_ReCreateTree, 1628).
+-define(wxGenericDirCtrl_SetDefaultPath, 1629).
+-define(wxGenericDirCtrl_SetFilter, 1630).
+-define(wxGenericDirCtrl_SetFilterIndex, 1631).
+-define(wxGenericDirCtrl_SetPath, 1632).
+-define(wxStaticBox_new_4, 1634).
+-define(wxStaticBox_new_0, 1635).
+-define(wxStaticBox_Create, 1636).
+-define(wxStaticBox_destroy, 1637).
+-define(wxStaticLine_new_2, 1639).
+-define(wxStaticLine_new_0, 1640).
+-define(wxStaticLine_Create, 1641).
+-define(wxStaticLine_IsVertical, 1642).
+-define(wxStaticLine_GetDefaultSize, 1643).
+-define(wxStaticLine_destroy, 1644).
+-define(wxListBox_new_3, 1647).
+-define(wxListBox_new_0, 1648).
+-define(wxListBox_destruct, 1650).
+-define(wxListBox_Create, 1652).
+-define(wxListBox_Deselect, 1653).
+-define(wxListBox_GetSelections, 1654).
+-define(wxListBox_InsertItems, 1655).
+-define(wxListBox_IsSelected, 1656).
+-define(wxListBox_Set, 1657).
+-define(wxListBox_HitTest, 1658).
+-define(wxListBox_SetFirstItem_1_0, 1659).
+-define(wxListBox_SetFirstItem_1_1, 1660).
+-define(wxListCtrl_new_0, 1661).
+-define(wxListCtrl_new_2, 1662).
+-define(wxListCtrl_Arrange, 1663).
+-define(wxListCtrl_AssignImageList, 1664).
+-define(wxListCtrl_ClearAll, 1665).
+-define(wxListCtrl_Create, 1666).
+-define(wxListCtrl_DeleteAllItems, 1667).
+-define(wxListCtrl_DeleteColumn, 1668).
+-define(wxListCtrl_DeleteItem, 1669).
+-define(wxListCtrl_EditLabel, 1670).
+-define(wxListCtrl_EnsureVisible, 1671).
+-define(wxListCtrl_FindItem_3_0, 1672).
+-define(wxListCtrl_FindItem_3_1, 1673).
+-define(wxListCtrl_GetColumn, 1674).
+-define(wxListCtrl_GetColumnCount, 1675).
+-define(wxListCtrl_GetColumnWidth, 1676).
+-define(wxListCtrl_GetCountPerPage, 1677).
+-define(wxListCtrl_GetEditControl, 1678).
+-define(wxListCtrl_GetImageList, 1679).
+-define(wxListCtrl_GetItem, 1680).
+-define(wxListCtrl_GetItemBackgroundColour, 1681).
+-define(wxListCtrl_GetItemCount, 1682).
+-define(wxListCtrl_GetItemData, 1683).
+-define(wxListCtrl_GetItemFont, 1684).
+-define(wxListCtrl_GetItemPosition, 1685).
+-define(wxListCtrl_GetItemRect, 1686).
+-define(wxListCtrl_GetItemSpacing, 1687).
+-define(wxListCtrl_GetItemState, 1688).
+-define(wxListCtrl_GetItemText, 1689).
+-define(wxListCtrl_GetItemTextColour, 1690).
+-define(wxListCtrl_GetNextItem, 1691).
+-define(wxListCtrl_GetSelectedItemCount, 1692).
+-define(wxListCtrl_GetTextColour, 1693).
+-define(wxListCtrl_GetTopItem, 1694).
+-define(wxListCtrl_GetViewRect, 1695).
+-define(wxListCtrl_HitTest, 1696).
+-define(wxListCtrl_InsertColumn_2, 1697).
+-define(wxListCtrl_InsertColumn_3, 1698).
+-define(wxListCtrl_InsertItem_1, 1699).
+-define(wxListCtrl_InsertItem_2_1, 1700).
+-define(wxListCtrl_InsertItem_2_0, 1701).
+-define(wxListCtrl_InsertItem_3, 1702).
+-define(wxListCtrl_RefreshItem, 1703).
+-define(wxListCtrl_RefreshItems, 1704).
+-define(wxListCtrl_ScrollList, 1705).
+-define(wxListCtrl_SetBackgroundColour, 1706).
+-define(wxListCtrl_SetColumn, 1707).
+-define(wxListCtrl_SetColumnWidth, 1708).
+-define(wxListCtrl_SetImageList, 1709).
+-define(wxListCtrl_SetItem_1, 1710).
+-define(wxListCtrl_SetItem_4, 1711).
+-define(wxListCtrl_SetItemBackgroundColour, 1712).
+-define(wxListCtrl_SetItemCount, 1713).
+-define(wxListCtrl_SetItemData, 1714).
+-define(wxListCtrl_SetItemFont, 1715).
+-define(wxListCtrl_SetItemImage, 1716).
+-define(wxListCtrl_SetItemColumnImage, 1717).
+-define(wxListCtrl_SetItemPosition, 1718).
+-define(wxListCtrl_SetItemState, 1719).
+-define(wxListCtrl_SetItemText, 1720).
+-define(wxListCtrl_SetItemTextColour, 1721).
+-define(wxListCtrl_SetSingleStyle, 1722).
+-define(wxListCtrl_SetTextColour, 1723).
+-define(wxListCtrl_SetWindowStyleFlag, 1724).
+-define(wxListCtrl_SortItems, 1725).
+-define(wxListCtrl_destroy, 1726).
+-define(wxListView_ClearColumnImage, 1727).
+-define(wxListView_Focus, 1728).
+-define(wxListView_GetFirstSelected, 1729).
+-define(wxListView_GetFocusedItem, 1730).
+-define(wxListView_GetNextSelected, 1731).
+-define(wxListView_IsSelected, 1732).
+-define(wxListView_Select, 1733).
+-define(wxListView_SetColumnImage, 1734).
+-define(wxListItem_new_0, 1735).
+-define(wxListItem_new_1, 1736).
+-define(wxListItem_destruct, 1737).
+-define(wxListItem_Clear, 1738).
+-define(wxListItem_GetAlign, 1739).
+-define(wxListItem_GetBackgroundColour, 1740).
+-define(wxListItem_GetColumn, 1741).
+-define(wxListItem_GetFont, 1742).
+-define(wxListItem_GetId, 1743).
+-define(wxListItem_GetImage, 1744).
+-define(wxListItem_GetMask, 1745).
+-define(wxListItem_GetState, 1746).
+-define(wxListItem_GetText, 1747).
+-define(wxListItem_GetTextColour, 1748).
+-define(wxListItem_GetWidth, 1749).
+-define(wxListItem_SetAlign, 1750).
+-define(wxListItem_SetBackgroundColour, 1751).
+-define(wxListItem_SetColumn, 1752).
+-define(wxListItem_SetFont, 1753).
+-define(wxListItem_SetId, 1754).
+-define(wxListItem_SetImage, 1755).
+-define(wxListItem_SetMask, 1756).
+-define(wxListItem_SetState, 1757).
+-define(wxListItem_SetStateMask, 1758).
+-define(wxListItem_SetText, 1759).
+-define(wxListItem_SetTextColour, 1760).
+-define(wxListItem_SetWidth, 1761).
+-define(wxListItemAttr_new_0, 1762).
+-define(wxListItemAttr_new_3, 1763).
+-define(wxListItemAttr_GetBackgroundColour, 1764).
+-define(wxListItemAttr_GetFont, 1765).
+-define(wxListItemAttr_GetTextColour, 1766).
+-define(wxListItemAttr_HasBackgroundColour, 1767).
+-define(wxListItemAttr_HasFont, 1768).
+-define(wxListItemAttr_HasTextColour, 1769).
+-define(wxListItemAttr_SetBackgroundColour, 1770).
+-define(wxListItemAttr_SetFont, 1771).
+-define(wxListItemAttr_SetTextColour, 1772).
+-define(wxListItemAttr_destroy, 1773).
+-define(wxImageList_new_0, 1774).
+-define(wxImageList_new_3, 1775).
+-define(wxImageList_Add_1, 1776).
+-define(wxImageList_Add_2_0, 1777).
+-define(wxImageList_Add_2_1, 1778).
+-define(wxImageList_Create, 1779).
+-define(wxImageList_Draw, 1781).
+-define(wxImageList_GetBitmap, 1782).
+-define(wxImageList_GetIcon, 1783).
+-define(wxImageList_GetImageCount, 1784).
+-define(wxImageList_GetSize, 1785).
+-define(wxImageList_Remove, 1786).
+-define(wxImageList_RemoveAll, 1787).
+-define(wxImageList_Replace_2, 1788).
+-define(wxImageList_Replace_3, 1789).
+-define(wxImageList_destroy, 1790).
+-define(wxTextAttr_new_0, 1791).
+-define(wxTextAttr_new_2, 1792).
+-define(wxTextAttr_GetAlignment, 1793).
+-define(wxTextAttr_GetBackgroundColour, 1794).
+-define(wxTextAttr_GetFont, 1795).
+-define(wxTextAttr_GetLeftIndent, 1796).
+-define(wxTextAttr_GetLeftSubIndent, 1797).
+-define(wxTextAttr_GetRightIndent, 1798).
+-define(wxTextAttr_GetTabs, 1799).
+-define(wxTextAttr_GetTextColour, 1800).
+-define(wxTextAttr_HasBackgroundColour, 1801).
+-define(wxTextAttr_HasFont, 1802).
+-define(wxTextAttr_HasTextColour, 1803).
+-define(wxTextAttr_GetFlags, 1804).
+-define(wxTextAttr_IsDefault, 1805).
+-define(wxTextAttr_SetAlignment, 1806).
+-define(wxTextAttr_SetBackgroundColour, 1807).
+-define(wxTextAttr_SetFlags, 1808).
+-define(wxTextAttr_SetFont, 1809).
+-define(wxTextAttr_SetLeftIndent, 1810).
+-define(wxTextAttr_SetRightIndent, 1811).
+-define(wxTextAttr_SetTabs, 1812).
+-define(wxTextAttr_SetTextColour, 1813).
+-define(wxTextAttr_destroy, 1814).
+-define(wxTextCtrl_new_3, 1816).
+-define(wxTextCtrl_new_0, 1817).
+-define(wxTextCtrl_destruct, 1819).
+-define(wxTextCtrl_AppendText, 1820).
+-define(wxTextCtrl_CanCopy, 1821).
+-define(wxTextCtrl_CanCut, 1822).
+-define(wxTextCtrl_CanPaste, 1823).
+-define(wxTextCtrl_CanRedo, 1824).
+-define(wxTextCtrl_CanUndo, 1825).
+-define(wxTextCtrl_Clear, 1826).
+-define(wxTextCtrl_Copy, 1827).
+-define(wxTextCtrl_Create, 1828).
+-define(wxTextCtrl_Cut, 1829).
+-define(wxTextCtrl_DiscardEdits, 1830).
+-define(wxTextCtrl_ChangeValue, 1831).
+-define(wxTextCtrl_EmulateKeyPress, 1832).
+-define(wxTextCtrl_GetDefaultStyle, 1833).
+-define(wxTextCtrl_GetInsertionPoint, 1834).
+-define(wxTextCtrl_GetLastPosition, 1835).
+-define(wxTextCtrl_GetLineLength, 1836).
+-define(wxTextCtrl_GetLineText, 1837).
+-define(wxTextCtrl_GetNumberOfLines, 1838).
+-define(wxTextCtrl_GetRange, 1839).
+-define(wxTextCtrl_GetSelection, 1840).
+-define(wxTextCtrl_GetStringSelection, 1841).
+-define(wxTextCtrl_GetStyle, 1842).
+-define(wxTextCtrl_GetValue, 1843).
+-define(wxTextCtrl_IsEditable, 1844).
+-define(wxTextCtrl_IsModified, 1845).
+-define(wxTextCtrl_IsMultiLine, 1846).
+-define(wxTextCtrl_IsSingleLine, 1847).
+-define(wxTextCtrl_LoadFile, 1848).
+-define(wxTextCtrl_MarkDirty, 1849).
+-define(wxTextCtrl_Paste, 1850).
+-define(wxTextCtrl_PositionToXY, 1851).
+-define(wxTextCtrl_Redo, 1852).
+-define(wxTextCtrl_Remove, 1853).
+-define(wxTextCtrl_Replace, 1854).
+-define(wxTextCtrl_SaveFile, 1855).
+-define(wxTextCtrl_SetDefaultStyle, 1856).
+-define(wxTextCtrl_SetEditable, 1857).
+-define(wxTextCtrl_SetInsertionPoint, 1858).
+-define(wxTextCtrl_SetInsertionPointEnd, 1859).
+-define(wxTextCtrl_SetMaxLength, 1861).
+-define(wxTextCtrl_SetSelection, 1862).
+-define(wxTextCtrl_SetStyle, 1863).
+-define(wxTextCtrl_SetValue, 1864).
+-define(wxTextCtrl_ShowPosition, 1865).
+-define(wxTextCtrl_Undo, 1866).
+-define(wxTextCtrl_WriteText, 1867).
+-define(wxTextCtrl_XYToPosition, 1868).
+-define(wxNotebook_new_0, 1871).
+-define(wxNotebook_new_3, 1872).
+-define(wxNotebook_destruct, 1873).
+-define(wxNotebook_AddPage, 1874).
+-define(wxNotebook_AdvanceSelection, 1875).
+-define(wxNotebook_AssignImageList, 1876).
+-define(wxNotebook_Create, 1877).
+-define(wxNotebook_DeleteAllPages, 1878).
+-define(wxNotebook_DeletePage, 1879).
+-define(wxNotebook_RemovePage, 1880).
+-define(wxNotebook_GetCurrentPage, 1881).
+-define(wxNotebook_GetImageList, 1882).
+-define(wxNotebook_GetPage, 1884).
+-define(wxNotebook_GetPageCount, 1885).
+-define(wxNotebook_GetPageImage, 1886).
+-define(wxNotebook_GetPageText, 1887).
+-define(wxNotebook_GetRowCount, 1888).
+-define(wxNotebook_GetSelection, 1889).
+-define(wxNotebook_GetThemeBackgroundColour, 1890).
+-define(wxNotebook_HitTest, 1892).
+-define(wxNotebook_InsertPage, 1894).
+-define(wxNotebook_SetImageList, 1895).
+-define(wxNotebook_SetPadding, 1896).
+-define(wxNotebook_SetPageSize, 1897).
+-define(wxNotebook_SetPageImage, 1898).
+-define(wxNotebook_SetPageText, 1899).
+-define(wxNotebook_SetSelection, 1900).
+-define(wxNotebook_ChangeSelection, 1901).
+-define(wxChoicebook_new_0, 1902).
+-define(wxChoicebook_new_3, 1903).
+-define(wxChoicebook_AddPage, 1904).
+-define(wxChoicebook_AdvanceSelection, 1905).
+-define(wxChoicebook_AssignImageList, 1906).
+-define(wxChoicebook_Create, 1907).
+-define(wxChoicebook_DeleteAllPages, 1908).
+-define(wxChoicebook_DeletePage, 1909).
+-define(wxChoicebook_RemovePage, 1910).
+-define(wxChoicebook_GetCurrentPage, 1911).
+-define(wxChoicebook_GetImageList, 1912).
+-define(wxChoicebook_GetPage, 1914).
+-define(wxChoicebook_GetPageCount, 1915).
+-define(wxChoicebook_GetPageImage, 1916).
+-define(wxChoicebook_GetPageText, 1917).
+-define(wxChoicebook_GetSelection, 1918).
+-define(wxChoicebook_HitTest, 1919).
+-define(wxChoicebook_InsertPage, 1920).
+-define(wxChoicebook_SetImageList, 1921).
+-define(wxChoicebook_SetPageSize, 1922).
+-define(wxChoicebook_SetPageImage, 1923).
+-define(wxChoicebook_SetPageText, 1924).
+-define(wxChoicebook_SetSelection, 1925).
+-define(wxChoicebook_ChangeSelection, 1926).
+-define(wxChoicebook_destroy, 1927).
+-define(wxToolbook_new_0, 1928).
+-define(wxToolbook_new_3, 1929).
+-define(wxToolbook_AddPage, 1930).
+-define(wxToolbook_AdvanceSelection, 1931).
+-define(wxToolbook_AssignImageList, 1932).
+-define(wxToolbook_Create, 1933).
+-define(wxToolbook_DeleteAllPages, 1934).
+-define(wxToolbook_DeletePage, 1935).
+-define(wxToolbook_RemovePage, 1936).
+-define(wxToolbook_GetCurrentPage, 1937).
+-define(wxToolbook_GetImageList, 1938).
+-define(wxToolbook_GetPage, 1940).
+-define(wxToolbook_GetPageCount, 1941).
+-define(wxToolbook_GetPageImage, 1942).
+-define(wxToolbook_GetPageText, 1943).
+-define(wxToolbook_GetSelection, 1944).
+-define(wxToolbook_HitTest, 1946).
+-define(wxToolbook_InsertPage, 1947).
+-define(wxToolbook_SetImageList, 1948).
+-define(wxToolbook_SetPageSize, 1949).
+-define(wxToolbook_SetPageImage, 1950).
+-define(wxToolbook_SetPageText, 1951).
+-define(wxToolbook_SetSelection, 1952).
+-define(wxToolbook_ChangeSelection, 1953).
+-define(wxToolbook_destroy, 1954).
+-define(wxListbook_new_0, 1955).
+-define(wxListbook_new_3, 1956).
+-define(wxListbook_AddPage, 1957).
+-define(wxListbook_AdvanceSelection, 1958).
+-define(wxListbook_AssignImageList, 1959).
+-define(wxListbook_Create, 1960).
+-define(wxListbook_DeleteAllPages, 1961).
+-define(wxListbook_DeletePage, 1962).
+-define(wxListbook_RemovePage, 1963).
+-define(wxListbook_GetCurrentPage, 1964).
+-define(wxListbook_GetImageList, 1965).
+-define(wxListbook_GetPage, 1967).
+-define(wxListbook_GetPageCount, 1968).
+-define(wxListbook_GetPageImage, 1969).
+-define(wxListbook_GetPageText, 1970).
+-define(wxListbook_GetSelection, 1971).
+-define(wxListbook_HitTest, 1973).
+-define(wxListbook_InsertPage, 1974).
+-define(wxListbook_SetImageList, 1975).
+-define(wxListbook_SetPageSize, 1976).
+-define(wxListbook_SetPageImage, 1977).
+-define(wxListbook_SetPageText, 1978).
+-define(wxListbook_SetSelection, 1979).
+-define(wxListbook_ChangeSelection, 1980).
+-define(wxListbook_destroy, 1981).
+-define(wxTreebook_new_0, 1982).
+-define(wxTreebook_new_3, 1983).
+-define(wxTreebook_AddPage, 1984).
+-define(wxTreebook_AdvanceSelection, 1985).
+-define(wxTreebook_AssignImageList, 1986).
+-define(wxTreebook_Create, 1987).
+-define(wxTreebook_DeleteAllPages, 1988).
+-define(wxTreebook_DeletePage, 1989).
+-define(wxTreebook_RemovePage, 1990).
+-define(wxTreebook_GetCurrentPage, 1991).
+-define(wxTreebook_GetImageList, 1992).
+-define(wxTreebook_GetPage, 1994).
+-define(wxTreebook_GetPageCount, 1995).
+-define(wxTreebook_GetPageImage, 1996).
+-define(wxTreebook_GetPageText, 1997).
+-define(wxTreebook_GetSelection, 1998).
+-define(wxTreebook_ExpandNode, 1999).
+-define(wxTreebook_IsNodeExpanded, 2000).
+-define(wxTreebook_HitTest, 2002).
+-define(wxTreebook_InsertPage, 2003).
+-define(wxTreebook_InsertSubPage, 2004).
+-define(wxTreebook_SetImageList, 2005).
+-define(wxTreebook_SetPageSize, 2006).
+-define(wxTreebook_SetPageImage, 2007).
+-define(wxTreebook_SetPageText, 2008).
+-define(wxTreebook_SetSelection, 2009).
+-define(wxTreebook_ChangeSelection, 2010).
+-define(wxTreebook_destroy, 2011).
+-define(wxTreeCtrl_new_2, 2014).
+-define(wxTreeCtrl_new_0, 2015).
+-define(wxTreeCtrl_destruct, 2017).
+-define(wxTreeCtrl_AddRoot, 2018).
+-define(wxTreeCtrl_AppendItem, 2019).
+-define(wxTreeCtrl_AssignImageList, 2020).
+-define(wxTreeCtrl_AssignStateImageList, 2021).
+-define(wxTreeCtrl_Collapse, 2022).
+-define(wxTreeCtrl_CollapseAndReset, 2023).
+-define(wxTreeCtrl_Create, 2024).
+-define(wxTreeCtrl_Delete, 2025).
+-define(wxTreeCtrl_DeleteAllItems, 2026).
+-define(wxTreeCtrl_DeleteChildren, 2027).
+-define(wxTreeCtrl_EditLabel, 2028).
+-define(wxTreeCtrl_EnsureVisible, 2029).
+-define(wxTreeCtrl_Expand, 2030).
+-define(wxTreeCtrl_GetBoundingRect, 2031).
+-define(wxTreeCtrl_GetChildrenCount, 2033).
+-define(wxTreeCtrl_GetCount, 2034).
+-define(wxTreeCtrl_GetEditControl, 2035).
+-define(wxTreeCtrl_GetFirstChild, 2036).
+-define(wxTreeCtrl_GetNextChild, 2037).
+-define(wxTreeCtrl_GetFirstVisibleItem, 2038).
+-define(wxTreeCtrl_GetImageList, 2039).
+-define(wxTreeCtrl_GetIndent, 2040).
+-define(wxTreeCtrl_GetItemBackgroundColour, 2041).
+-define(wxTreeCtrl_GetItemData, 2042).
+-define(wxTreeCtrl_GetItemFont, 2043).
+-define(wxTreeCtrl_GetItemImage_1, 2044).
+-define(wxTreeCtrl_GetItemImage_2, 2045).
+-define(wxTreeCtrl_GetItemText, 2046).
+-define(wxTreeCtrl_GetItemTextColour, 2047).
+-define(wxTreeCtrl_GetLastChild, 2048).
+-define(wxTreeCtrl_GetNextSibling, 2049).
+-define(wxTreeCtrl_GetNextVisible, 2050).
+-define(wxTreeCtrl_GetItemParent, 2051).
+-define(wxTreeCtrl_GetPrevSibling, 2052).
+-define(wxTreeCtrl_GetPrevVisible, 2053).
+-define(wxTreeCtrl_GetRootItem, 2054).
+-define(wxTreeCtrl_GetSelection, 2055).
+-define(wxTreeCtrl_GetSelections, 2056).
+-define(wxTreeCtrl_GetStateImageList, 2057).
+-define(wxTreeCtrl_HitTest, 2058).
+-define(wxTreeCtrl_InsertItem, 2060).
+-define(wxTreeCtrl_IsBold, 2061).
+-define(wxTreeCtrl_IsExpanded, 2062).
+-define(wxTreeCtrl_IsSelected, 2063).
+-define(wxTreeCtrl_IsVisible, 2064).
+-define(wxTreeCtrl_ItemHasChildren, 2065).
+-define(wxTreeCtrl_IsTreeItemIdOk, 2066).
+-define(wxTreeCtrl_PrependItem, 2067).
+-define(wxTreeCtrl_ScrollTo, 2068).
+-define(wxTreeCtrl_SelectItem_1, 2069).
+-define(wxTreeCtrl_SelectItem_2, 2070).
+-define(wxTreeCtrl_SetIndent, 2071).
+-define(wxTreeCtrl_SetImageList, 2072).
+-define(wxTreeCtrl_SetItemBackgroundColour, 2073).
+-define(wxTreeCtrl_SetItemBold, 2074).
+-define(wxTreeCtrl_SetItemData, 2075).
+-define(wxTreeCtrl_SetItemDropHighlight, 2076).
+-define(wxTreeCtrl_SetItemFont, 2077).
+-define(wxTreeCtrl_SetItemHasChildren, 2078).
+-define(wxTreeCtrl_SetItemImage_2, 2079).
+-define(wxTreeCtrl_SetItemImage_3, 2080).
+-define(wxTreeCtrl_SetItemText, 2081).
+-define(wxTreeCtrl_SetItemTextColour, 2082).
+-define(wxTreeCtrl_SetStateImageList, 2083).
+-define(wxTreeCtrl_SetWindowStyle, 2084).
+-define(wxTreeCtrl_SortChildren, 2085).
+-define(wxTreeCtrl_Toggle, 2086).
+-define(wxTreeCtrl_ToggleItemSelection, 2087).
+-define(wxTreeCtrl_Unselect, 2088).
+-define(wxTreeCtrl_UnselectAll, 2089).
+-define(wxTreeCtrl_UnselectItem, 2090).
+-define(wxScrollBar_new_0, 2091).
+-define(wxScrollBar_new_3, 2092).
+-define(wxScrollBar_destruct, 2093).
+-define(wxScrollBar_Create, 2094).
+-define(wxScrollBar_GetRange, 2095).
+-define(wxScrollBar_GetPageSize, 2096).
+-define(wxScrollBar_GetThumbPosition, 2097).
+-define(wxScrollBar_GetThumbSize, 2098).
+-define(wxScrollBar_SetThumbPosition, 2099).
+-define(wxScrollBar_SetScrollbar, 2100).
+-define(wxSpinButton_new_2, 2102).
+-define(wxSpinButton_new_0, 2103).
+-define(wxSpinButton_Create, 2104).
+-define(wxSpinButton_GetMax, 2105).
+-define(wxSpinButton_GetMin, 2106).
+-define(wxSpinButton_GetValue, 2107).
+-define(wxSpinButton_SetRange, 2108).
+-define(wxSpinButton_SetValue, 2109).
+-define(wxSpinButton_destroy, 2110).
+-define(wxSpinCtrl_new_0, 2111).
+-define(wxSpinCtrl_new_2, 2112).
+-define(wxSpinCtrl_Create, 2114).
+-define(wxSpinCtrl_SetValue_1_1, 2117).
+-define(wxSpinCtrl_SetValue_1_0, 2118).
+-define(wxSpinCtrl_GetValue, 2120).
+-define(wxSpinCtrl_SetRange, 2122).
+-define(wxSpinCtrl_SetSelection, 2123).
+-define(wxSpinCtrl_GetMin, 2125).
+-define(wxSpinCtrl_GetMax, 2127).
+-define(wxSpinCtrl_destroy, 2128).
+-define(wxStaticText_new_0, 2129).
+-define(wxStaticText_new_4, 2130).
+-define(wxStaticText_Create, 2131).
+-define(wxStaticText_GetLabel, 2132).
+-define(wxStaticText_SetLabel, 2133).
+-define(wxStaticText_Wrap, 2134).
+-define(wxStaticText_destroy, 2135).
+-define(wxStaticBitmap_new_0, 2136).
+-define(wxStaticBitmap_new_4, 2137).
+-define(wxStaticBitmap_Create, 2138).
+-define(wxStaticBitmap_GetBitmap, 2139).
+-define(wxStaticBitmap_SetBitmap, 2140).
+-define(wxStaticBitmap_destroy, 2141).
+-define(wxRadioBox_new, 2142).
+-define(wxRadioBox_destruct, 2144).
+-define(wxRadioBox_Create, 2145).
+-define(wxRadioBox_Enable_2, 2146).
+-define(wxRadioBox_Enable_1, 2147).
+-define(wxRadioBox_GetSelection, 2148).
+-define(wxRadioBox_GetString, 2149).
+-define(wxRadioBox_SetSelection, 2150).
+-define(wxRadioBox_Show_2, 2151).
+-define(wxRadioBox_Show_1, 2152).
+-define(wxRadioBox_GetColumnCount, 2153).
+-define(wxRadioBox_GetItemHelpText, 2154).
+-define(wxRadioBox_GetItemToolTip, 2155).
+-define(wxRadioBox_GetItemFromPoint, 2157).
+-define(wxRadioBox_GetRowCount, 2158).
+-define(wxRadioBox_IsItemEnabled, 2159).
+-define(wxRadioBox_IsItemShown, 2160).
+-define(wxRadioBox_SetItemHelpText, 2161).
+-define(wxRadioBox_SetItemToolTip, 2162).
+-define(wxRadioButton_new_0, 2163).
+-define(wxRadioButton_new_4, 2164).
+-define(wxRadioButton_Create, 2165).
+-define(wxRadioButton_GetValue, 2166).
+-define(wxRadioButton_SetValue, 2167).
+-define(wxRadioButton_destroy, 2168).
+-define(wxSlider_new_6, 2170).
+-define(wxSlider_new_0, 2171).
+-define(wxSlider_Create, 2172).
+-define(wxSlider_GetLineSize, 2173).
+-define(wxSlider_GetMax, 2174).
+-define(wxSlider_GetMin, 2175).
+-define(wxSlider_GetPageSize, 2176).
+-define(wxSlider_GetThumbLength, 2177).
+-define(wxSlider_GetValue, 2178).
+-define(wxSlider_SetLineSize, 2179).
+-define(wxSlider_SetPageSize, 2180).
+-define(wxSlider_SetRange, 2181).
+-define(wxSlider_SetThumbLength, 2182).
+-define(wxSlider_SetValue, 2183).
+-define(wxSlider_destroy, 2184).
+-define(wxDialog_new_4, 2186).
+-define(wxDialog_new_0, 2187).
+-define(wxDialog_destruct, 2189).
+-define(wxDialog_Create, 2190).
+-define(wxDialog_CreateButtonSizer, 2191).
+-define(wxDialog_CreateStdDialogButtonSizer, 2192).
+-define(wxDialog_EndModal, 2193).
+-define(wxDialog_GetAffirmativeId, 2194).
+-define(wxDialog_GetReturnCode, 2195).
+-define(wxDialog_IsModal, 2196).
+-define(wxDialog_SetAffirmativeId, 2197).
+-define(wxDialog_SetReturnCode, 2198).
+-define(wxDialog_Show, 2199).
+-define(wxDialog_ShowModal, 2200).
+-define(wxColourDialog_new_0, 2201).
+-define(wxColourDialog_new_2, 2202).
+-define(wxColourDialog_destruct, 2203).
+-define(wxColourDialog_Create, 2204).
+-define(wxColourDialog_GetColourData, 2205).
+-define(wxColourData_new_0, 2206).
+-define(wxColourData_new_1, 2207).
+-define(wxColourData_destruct, 2208).
+-define(wxColourData_GetChooseFull, 2209).
+-define(wxColourData_GetColour, 2210).
+-define(wxColourData_GetCustomColour, 2212).
+-define(wxColourData_SetChooseFull, 2213).
+-define(wxColourData_SetColour, 2214).
+-define(wxColourData_SetCustomColour, 2215).
+-define(wxPalette_new_0, 2216).
+-define(wxPalette_new_4, 2217).
+-define(wxPalette_destruct, 2219).
+-define(wxPalette_Create, 2220).
+-define(wxPalette_GetColoursCount, 2221).
+-define(wxPalette_GetPixel, 2222).
+-define(wxPalette_GetRGB, 2223).
+-define(wxPalette_IsOk, 2224).
+-define(wxDirDialog_new, 2228).
+-define(wxDirDialog_destruct, 2229).
+-define(wxDirDialog_GetPath, 2230).
+-define(wxDirDialog_GetMessage, 2231).
+-define(wxDirDialog_SetMessage, 2232).
+-define(wxDirDialog_SetPath, 2233).
+-define(wxFileDialog_new, 2237).
+-define(wxFileDialog_destruct, 2238).
+-define(wxFileDialog_GetDirectory, 2239).
+-define(wxFileDialog_GetFilename, 2240).
+-define(wxFileDialog_GetFilenames, 2241).
+-define(wxFileDialog_GetFilterIndex, 2242).
+-define(wxFileDialog_GetMessage, 2243).
+-define(wxFileDialog_GetPath, 2244).
+-define(wxFileDialog_GetPaths, 2245).
+-define(wxFileDialog_GetWildcard, 2246).
+-define(wxFileDialog_SetDirectory, 2247).
+-define(wxFileDialog_SetFilename, 2248).
+-define(wxFileDialog_SetFilterIndex, 2249).
+-define(wxFileDialog_SetMessage, 2250).
+-define(wxFileDialog_SetPath, 2251).
+-define(wxFileDialog_SetWildcard, 2252).
+-define(wxPickerBase_SetInternalMargin, 2253).
+-define(wxPickerBase_GetInternalMargin, 2254).
+-define(wxPickerBase_SetTextCtrlProportion, 2255).
+-define(wxPickerBase_SetPickerCtrlProportion, 2256).
+-define(wxPickerBase_GetTextCtrlProportion, 2257).
+-define(wxPickerBase_GetPickerCtrlProportion, 2258).
+-define(wxPickerBase_HasTextCtrl, 2259).
+-define(wxPickerBase_GetTextCtrl, 2260).
+-define(wxPickerBase_IsTextCtrlGrowable, 2261).
+-define(wxPickerBase_SetPickerCtrlGrowable, 2262).
+-define(wxPickerBase_SetTextCtrlGrowable, 2263).
+-define(wxPickerBase_IsPickerCtrlGrowable, 2264).
+-define(wxFilePickerCtrl_new_0, 2265).
+-define(wxFilePickerCtrl_new_3, 2266).
+-define(wxFilePickerCtrl_Create, 2267).
+-define(wxFilePickerCtrl_GetPath, 2268).
+-define(wxFilePickerCtrl_SetPath, 2269).
+-define(wxFilePickerCtrl_destroy, 2270).
+-define(wxDirPickerCtrl_new_0, 2271).
+-define(wxDirPickerCtrl_new_3, 2272).
+-define(wxDirPickerCtrl_Create, 2273).
+-define(wxDirPickerCtrl_GetPath, 2274).
+-define(wxDirPickerCtrl_SetPath, 2275).
+-define(wxDirPickerCtrl_destroy, 2276).
+-define(wxColourPickerCtrl_new_0, 2277).
+-define(wxColourPickerCtrl_new_3, 2278).
+-define(wxColourPickerCtrl_Create, 2279).
+-define(wxColourPickerCtrl_GetColour, 2280).
+-define(wxColourPickerCtrl_SetColour_1_1, 2281).
+-define(wxColourPickerCtrl_SetColour_1_0, 2282).
+-define(wxColourPickerCtrl_destroy, 2283).
+-define(wxDatePickerCtrl_new_0, 2284).
+-define(wxDatePickerCtrl_new_3, 2285).
+-define(wxDatePickerCtrl_GetRange, 2286).
+-define(wxDatePickerCtrl_GetValue, 2287).
+-define(wxDatePickerCtrl_SetRange, 2288).
+-define(wxDatePickerCtrl_SetValue, 2289).
+-define(wxDatePickerCtrl_destroy, 2290).
+-define(wxFontPickerCtrl_new_0, 2291).
+-define(wxFontPickerCtrl_new_3, 2292).
+-define(wxFontPickerCtrl_Create, 2293).
+-define(wxFontPickerCtrl_GetSelectedFont, 2294).
+-define(wxFontPickerCtrl_SetSelectedFont, 2295).
+-define(wxFontPickerCtrl_GetMaxPointSize, 2296).
+-define(wxFontPickerCtrl_SetMaxPointSize, 2297).
+-define(wxFontPickerCtrl_destroy, 2298).
+-define(wxFindReplaceDialog_new_0, 2301).
+-define(wxFindReplaceDialog_new_4, 2302).
+-define(wxFindReplaceDialog_destruct, 2303).
+-define(wxFindReplaceDialog_Create, 2304).
+-define(wxFindReplaceDialog_GetData, 2305).
+-define(wxFindReplaceData_new_0, 2306).
+-define(wxFindReplaceData_new_1, 2307).
+-define(wxFindReplaceData_GetFindString, 2308).
+-define(wxFindReplaceData_GetReplaceString, 2309).
+-define(wxFindReplaceData_GetFlags, 2310).
+-define(wxFindReplaceData_SetFlags, 2311).
+-define(wxFindReplaceData_SetFindString, 2312).
+-define(wxFindReplaceData_SetReplaceString, 2313).
+-define(wxFindReplaceData_destroy, 2314).
+-define(wxMultiChoiceDialog_new_0, 2315).
+-define(wxMultiChoiceDialog_new_5, 2317).
+-define(wxMultiChoiceDialog_GetSelections, 2318).
+-define(wxMultiChoiceDialog_SetSelections, 2319).
+-define(wxMultiChoiceDialog_destroy, 2320).
+-define(wxSingleChoiceDialog_new_0, 2321).
+-define(wxSingleChoiceDialog_new_5, 2323).
+-define(wxSingleChoiceDialog_GetSelection, 2324).
+-define(wxSingleChoiceDialog_GetStringSelection, 2325).
+-define(wxSingleChoiceDialog_SetSelection, 2326).
+-define(wxSingleChoiceDialog_destroy, 2327).
+-define(wxTextEntryDialog_new, 2328).
+-define(wxTextEntryDialog_GetValue, 2329).
+-define(wxTextEntryDialog_SetValue, 2330).
+-define(wxTextEntryDialog_destroy, 2331).
+-define(wxPasswordEntryDialog_new, 2332).
+-define(wxPasswordEntryDialog_destroy, 2333).
+-define(wxFontData_new_0, 2334).
+-define(wxFontData_new_1, 2335).
+-define(wxFontData_destruct, 2336).
+-define(wxFontData_EnableEffects, 2337).
+-define(wxFontData_GetAllowSymbols, 2338).
+-define(wxFontData_GetColour, 2339).
+-define(wxFontData_GetChosenFont, 2340).
+-define(wxFontData_GetEnableEffects, 2341).
+-define(wxFontData_GetInitialFont, 2342).
+-define(wxFontData_GetShowHelp, 2343).
+-define(wxFontData_SetAllowSymbols, 2344).
+-define(wxFontData_SetChosenFont, 2345).
+-define(wxFontData_SetColour, 2346).
+-define(wxFontData_SetInitialFont, 2347).
+-define(wxFontData_SetRange, 2348).
+-define(wxFontData_SetShowHelp, 2349).
+-define(wxFontDialog_new_0, 2353).
+-define(wxFontDialog_new_2, 2355).
+-define(wxFontDialog_Create, 2357).
+-define(wxFontDialog_GetFontData, 2358).
+-define(wxFontDialog_destroy, 2360).
+-define(wxProgressDialog_new, 2361).
+-define(wxProgressDialog_destruct, 2362).
+-define(wxProgressDialog_Resume, 2363).
+-define(wxProgressDialog_Update_2, 2364).
+-define(wxProgressDialog_Update_0, 2365).
+-define(wxMessageDialog_new, 2366).
+-define(wxMessageDialog_destruct, 2367).
+-define(wxPageSetupDialog_new, 2368).
+-define(wxPageSetupDialog_destruct, 2369).
+-define(wxPageSetupDialog_GetPageSetupData, 2370).
+-define(wxPageSetupDialog_ShowModal, 2371).
+-define(wxPageSetupDialogData_new_0, 2372).
+-define(wxPageSetupDialogData_new_1_0, 2373).
+-define(wxPageSetupDialogData_new_1_1, 2374).
+-define(wxPageSetupDialogData_destruct, 2375).
+-define(wxPageSetupDialogData_EnableHelp, 2376).
+-define(wxPageSetupDialogData_EnableMargins, 2377).
+-define(wxPageSetupDialogData_EnableOrientation, 2378).
+-define(wxPageSetupDialogData_EnablePaper, 2379).
+-define(wxPageSetupDialogData_EnablePrinter, 2380).
+-define(wxPageSetupDialogData_GetDefaultMinMargins, 2381).
+-define(wxPageSetupDialogData_GetEnableMargins, 2382).
+-define(wxPageSetupDialogData_GetEnableOrientation, 2383).
+-define(wxPageSetupDialogData_GetEnablePaper, 2384).
+-define(wxPageSetupDialogData_GetEnablePrinter, 2385).
+-define(wxPageSetupDialogData_GetEnableHelp, 2386).
+-define(wxPageSetupDialogData_GetDefaultInfo, 2387).
+-define(wxPageSetupDialogData_GetMarginTopLeft, 2388).
+-define(wxPageSetupDialogData_GetMarginBottomRight, 2389).
+-define(wxPageSetupDialogData_GetMinMarginTopLeft, 2390).
+-define(wxPageSetupDialogData_GetMinMarginBottomRight, 2391).
+-define(wxPageSetupDialogData_GetPaperId, 2392).
+-define(wxPageSetupDialogData_GetPaperSize, 2393).
+-define(wxPageSetupDialogData_GetPrintData, 2395).
+-define(wxPageSetupDialogData_IsOk, 2396).
+-define(wxPageSetupDialogData_SetDefaultInfo, 2397).
+-define(wxPageSetupDialogData_SetDefaultMinMargins, 2398).
+-define(wxPageSetupDialogData_SetMarginTopLeft, 2399).
+-define(wxPageSetupDialogData_SetMarginBottomRight, 2400).
+-define(wxPageSetupDialogData_SetMinMarginTopLeft, 2401).
+-define(wxPageSetupDialogData_SetMinMarginBottomRight, 2402).
+-define(wxPageSetupDialogData_SetPaperId, 2403).
+-define(wxPageSetupDialogData_SetPaperSize_1_1, 2404).
+-define(wxPageSetupDialogData_SetPaperSize_1_0, 2405).
+-define(wxPageSetupDialogData_SetPrintData, 2406).
+-define(wxPrintDialog_new_2_0, 2407).
+-define(wxPrintDialog_new_2_1, 2408).
+-define(wxPrintDialog_destruct, 2409).
+-define(wxPrintDialog_GetPrintDialogData, 2410).
+-define(wxPrintDialog_GetPrintDC, 2411).
+-define(wxPrintDialogData_new_0, 2412).
+-define(wxPrintDialogData_new_1_1, 2413).
+-define(wxPrintDialogData_new_1_0, 2414).
+-define(wxPrintDialogData_destruct, 2415).
+-define(wxPrintDialogData_EnableHelp, 2416).
+-define(wxPrintDialogData_EnablePageNumbers, 2417).
+-define(wxPrintDialogData_EnablePrintToFile, 2418).
+-define(wxPrintDialogData_EnableSelection, 2419).
+-define(wxPrintDialogData_GetAllPages, 2420).
+-define(wxPrintDialogData_GetCollate, 2421).
+-define(wxPrintDialogData_GetFromPage, 2422).
+-define(wxPrintDialogData_GetMaxPage, 2423).
+-define(wxPrintDialogData_GetMinPage, 2424).
+-define(wxPrintDialogData_GetNoCopies, 2425).
+-define(wxPrintDialogData_GetPrintData, 2426).
+-define(wxPrintDialogData_GetPrintToFile, 2427).
+-define(wxPrintDialogData_GetSelection, 2428).
+-define(wxPrintDialogData_GetToPage, 2429).
+-define(wxPrintDialogData_IsOk, 2430).
+-define(wxPrintDialogData_SetCollate, 2431).
+-define(wxPrintDialogData_SetFromPage, 2432).
+-define(wxPrintDialogData_SetMaxPage, 2433).
+-define(wxPrintDialogData_SetMinPage, 2434).
+-define(wxPrintDialogData_SetNoCopies, 2435).
+-define(wxPrintDialogData_SetPrintData, 2436).
+-define(wxPrintDialogData_SetPrintToFile, 2437).
+-define(wxPrintDialogData_SetSelection, 2438).
+-define(wxPrintDialogData_SetToPage, 2439).
+-define(wxPrintData_new_0, 2440).
+-define(wxPrintData_new_1, 2441).
+-define(wxPrintData_destruct, 2442).
+-define(wxPrintData_GetCollate, 2443).
+-define(wxPrintData_GetBin, 2444).
+-define(wxPrintData_GetColour, 2445).
+-define(wxPrintData_GetDuplex, 2446).
+-define(wxPrintData_GetNoCopies, 2447).
+-define(wxPrintData_GetOrientation, 2448).
+-define(wxPrintData_GetPaperId, 2449).
+-define(wxPrintData_GetPrinterName, 2450).
+-define(wxPrintData_GetQuality, 2451).
+-define(wxPrintData_IsOk, 2452).
+-define(wxPrintData_SetBin, 2453).
+-define(wxPrintData_SetCollate, 2454).
+-define(wxPrintData_SetColour, 2455).
+-define(wxPrintData_SetDuplex, 2456).
+-define(wxPrintData_SetNoCopies, 2457).
+-define(wxPrintData_SetOrientation, 2458).
+-define(wxPrintData_SetPaperId, 2459).
+-define(wxPrintData_SetPrinterName, 2460).
+-define(wxPrintData_SetQuality, 2461).
+-define(wxPrintPreview_new_2, 2464).
+-define(wxPrintPreview_new_3, 2465).
+-define(wxPrintPreview_destruct, 2467).
+-define(wxPrintPreview_GetCanvas, 2468).
+-define(wxPrintPreview_GetCurrentPage, 2469).
+-define(wxPrintPreview_GetFrame, 2470).
+-define(wxPrintPreview_GetMaxPage, 2471).
+-define(wxPrintPreview_GetMinPage, 2472).
+-define(wxPrintPreview_GetPrintout, 2473).
+-define(wxPrintPreview_GetPrintoutForPrinting, 2474).
+-define(wxPrintPreview_IsOk, 2475).
+-define(wxPrintPreview_PaintPage, 2476).
+-define(wxPrintPreview_Print, 2477).
+-define(wxPrintPreview_RenderPage, 2478).
+-define(wxPrintPreview_SetCanvas, 2479).
+-define(wxPrintPreview_SetCurrentPage, 2480).
+-define(wxPrintPreview_SetFrame, 2481).
+-define(wxPrintPreview_SetPrintout, 2482).
+-define(wxPrintPreview_SetZoom, 2483).
+-define(wxPreviewFrame_new, 2484).
+-define(wxPreviewFrame_destruct, 2485).
+-define(wxPreviewFrame_CreateControlBar, 2486).
+-define(wxPreviewFrame_CreateCanvas, 2487).
+-define(wxPreviewFrame_Initialize, 2488).
+-define(wxPreviewFrame_OnCloseWindow, 2489).
+-define(wxPreviewControlBar_new, 2490).
+-define(wxPreviewControlBar_destruct, 2491).
+-define(wxPreviewControlBar_CreateButtons, 2492).
+-define(wxPreviewControlBar_GetPrintPreview, 2493).
+-define(wxPreviewControlBar_GetZoomControl, 2494).
+-define(wxPreviewControlBar_SetZoomControl, 2495).
+-define(wxPrinter_new, 2497).
+-define(wxPrinter_CreateAbortWindow, 2498).
+-define(wxPrinter_GetAbort, 2499).
+-define(wxPrinter_GetLastError, 2500).
+-define(wxPrinter_GetPrintDialogData, 2501).
+-define(wxPrinter_Print, 2502).
+-define(wxPrinter_PrintDialog, 2503).
+-define(wxPrinter_ReportError, 2504).
+-define(wxPrinter_Setup, 2505).
+-define(wxPrinter_destroy, 2506).
+-define(wxXmlResource_new_1, 2507).
+-define(wxXmlResource_new_2, 2508).
+-define(wxXmlResource_destruct, 2509).
+-define(wxXmlResource_AttachUnknownControl, 2510).
+-define(wxXmlResource_ClearHandlers, 2511).
+-define(wxXmlResource_CompareVersion, 2512).
+-define(wxXmlResource_Get, 2513).
+-define(wxXmlResource_GetFlags, 2514).
+-define(wxXmlResource_GetVersion, 2515).
+-define(wxXmlResource_GetXRCID, 2516).
+-define(wxXmlResource_InitAllHandlers, 2517).
+-define(wxXmlResource_Load, 2518).
+-define(wxXmlResource_LoadBitmap, 2519).
+-define(wxXmlResource_LoadDialog_2, 2520).
+-define(wxXmlResource_LoadDialog_3, 2521).
+-define(wxXmlResource_LoadFrame_2, 2522).
+-define(wxXmlResource_LoadFrame_3, 2523).
+-define(wxXmlResource_LoadIcon, 2524).
+-define(wxXmlResource_LoadMenu, 2525).
+-define(wxXmlResource_LoadMenuBar_2, 2526).
+-define(wxXmlResource_LoadMenuBar_1, 2527).
+-define(wxXmlResource_LoadPanel_2, 2528).
+-define(wxXmlResource_LoadPanel_3, 2529).
+-define(wxXmlResource_LoadToolBar, 2530).
+-define(wxXmlResource_Set, 2531).
+-define(wxXmlResource_SetFlags, 2532).
+-define(wxXmlResource_Unload, 2533).
+-define(wxXmlResource_xrcctrl, 2534).
+-define(wxHtmlEasyPrinting_new, 2535).
+-define(wxHtmlEasyPrinting_destruct, 2536).
+-define(wxHtmlEasyPrinting_GetPrintData, 2537).
+-define(wxHtmlEasyPrinting_GetPageSetupData, 2538).
+-define(wxHtmlEasyPrinting_PreviewFile, 2539).
+-define(wxHtmlEasyPrinting_PreviewText, 2540).
+-define(wxHtmlEasyPrinting_PrintFile, 2541).
+-define(wxHtmlEasyPrinting_PrintText, 2542).
+-define(wxHtmlEasyPrinting_PageSetup, 2543).
+-define(wxHtmlEasyPrinting_SetFonts, 2544).
+-define(wxHtmlEasyPrinting_SetHeader, 2545).
+-define(wxHtmlEasyPrinting_SetFooter, 2546).
+-define(wxGLCanvas_new_2, 2548).
+-define(wxGLCanvas_new_3_1, 2549).
+-define(wxGLCanvas_new_3_0, 2550).
+-define(wxGLCanvas_GetContext, 2551).
+-define(wxGLCanvas_SetCurrent, 2553).
+-define(wxGLCanvas_SwapBuffers, 2554).
+-define(wxGLCanvas_destroy, 2555).
+-define(wxAuiManager_new, 2556).
+-define(wxAuiManager_destruct, 2557).
+-define(wxAuiManager_AddPane_2_1, 2558).
+-define(wxAuiManager_AddPane_3, 2559).
+-define(wxAuiManager_AddPane_2_0, 2560).
+-define(wxAuiManager_DetachPane, 2561).
+-define(wxAuiManager_GetAllPanes, 2562).
+-define(wxAuiManager_GetArtProvider, 2563).
+-define(wxAuiManager_GetDockSizeConstraint, 2564).
+-define(wxAuiManager_GetFlags, 2565).
+-define(wxAuiManager_GetManagedWindow, 2566).
+-define(wxAuiManager_GetManager, 2567).
+-define(wxAuiManager_GetPane_1_1, 2568).
+-define(wxAuiManager_GetPane_1_0, 2569).
+-define(wxAuiManager_HideHint, 2570).
+-define(wxAuiManager_InsertPane, 2571).
+-define(wxAuiManager_LoadPaneInfo, 2572).
+-define(wxAuiManager_LoadPerspective, 2573).
+-define(wxAuiManager_SavePaneInfo, 2574).
+-define(wxAuiManager_SavePerspective, 2575).
+-define(wxAuiManager_SetArtProvider, 2576).
+-define(wxAuiManager_SetDockSizeConstraint, 2577).
+-define(wxAuiManager_SetFlags, 2578).
+-define(wxAuiManager_SetManagedWindow, 2579).
+-define(wxAuiManager_ShowHint, 2580).
+-define(wxAuiManager_UnInit, 2581).
+-define(wxAuiManager_Update, 2582).
+-define(wxAuiPaneInfo_new_0, 2583).
+-define(wxAuiPaneInfo_new_1, 2584).
+-define(wxAuiPaneInfo_destruct, 2585).
+-define(wxAuiPaneInfo_BestSize_1, 2586).
+-define(wxAuiPaneInfo_BestSize_2, 2587).
+-define(wxAuiPaneInfo_Bottom, 2588).
+-define(wxAuiPaneInfo_BottomDockable, 2589).
+-define(wxAuiPaneInfo_Caption, 2590).
+-define(wxAuiPaneInfo_CaptionVisible, 2591).
+-define(wxAuiPaneInfo_Centre, 2592).
+-define(wxAuiPaneInfo_CentrePane, 2593).
+-define(wxAuiPaneInfo_CloseButton, 2594).
+-define(wxAuiPaneInfo_DefaultPane, 2595).
+-define(wxAuiPaneInfo_DestroyOnClose, 2596).
+-define(wxAuiPaneInfo_Direction, 2597).
+-define(wxAuiPaneInfo_Dock, 2598).
+-define(wxAuiPaneInfo_Dockable, 2599).
+-define(wxAuiPaneInfo_Fixed, 2600).
+-define(wxAuiPaneInfo_Float, 2601).
+-define(wxAuiPaneInfo_Floatable, 2602).
+-define(wxAuiPaneInfo_FloatingPosition_1, 2603).
+-define(wxAuiPaneInfo_FloatingPosition_2, 2604).
+-define(wxAuiPaneInfo_FloatingSize_1, 2605).
+-define(wxAuiPaneInfo_FloatingSize_2, 2606).
+-define(wxAuiPaneInfo_Gripper, 2607).
+-define(wxAuiPaneInfo_GripperTop, 2608).
+-define(wxAuiPaneInfo_HasBorder, 2609).
+-define(wxAuiPaneInfo_HasCaption, 2610).
+-define(wxAuiPaneInfo_HasCloseButton, 2611).
+-define(wxAuiPaneInfo_HasFlag, 2612).
+-define(wxAuiPaneInfo_HasGripper, 2613).
+-define(wxAuiPaneInfo_HasGripperTop, 2614).
+-define(wxAuiPaneInfo_HasMaximizeButton, 2615).
+-define(wxAuiPaneInfo_HasMinimizeButton, 2616).
+-define(wxAuiPaneInfo_HasPinButton, 2617).
+-define(wxAuiPaneInfo_Hide, 2618).
+-define(wxAuiPaneInfo_IsBottomDockable, 2619).
+-define(wxAuiPaneInfo_IsDocked, 2620).
+-define(wxAuiPaneInfo_IsFixed, 2621).
+-define(wxAuiPaneInfo_IsFloatable, 2622).
+-define(wxAuiPaneInfo_IsFloating, 2623).
+-define(wxAuiPaneInfo_IsLeftDockable, 2624).
+-define(wxAuiPaneInfo_IsMovable, 2625).
+-define(wxAuiPaneInfo_IsOk, 2626).
+-define(wxAuiPaneInfo_IsResizable, 2627).
+-define(wxAuiPaneInfo_IsRightDockable, 2628).
+-define(wxAuiPaneInfo_IsShown, 2629).
+-define(wxAuiPaneInfo_IsToolbar, 2630).
+-define(wxAuiPaneInfo_IsTopDockable, 2631).
+-define(wxAuiPaneInfo_Layer, 2632).
+-define(wxAuiPaneInfo_Left, 2633).
+-define(wxAuiPaneInfo_LeftDockable, 2634).
+-define(wxAuiPaneInfo_MaxSize_1, 2635).
+-define(wxAuiPaneInfo_MaxSize_2, 2636).
+-define(wxAuiPaneInfo_MaximizeButton, 2637).
+-define(wxAuiPaneInfo_MinSize_1, 2638).
+-define(wxAuiPaneInfo_MinSize_2, 2639).
+-define(wxAuiPaneInfo_MinimizeButton, 2640).
+-define(wxAuiPaneInfo_Movable, 2641).
+-define(wxAuiPaneInfo_Name, 2642).
+-define(wxAuiPaneInfo_PaneBorder, 2643).
+-define(wxAuiPaneInfo_PinButton, 2644).
+-define(wxAuiPaneInfo_Position, 2645).
+-define(wxAuiPaneInfo_Resizable, 2646).
+-define(wxAuiPaneInfo_Right, 2647).
+-define(wxAuiPaneInfo_RightDockable, 2648).
+-define(wxAuiPaneInfo_Row, 2649).
+-define(wxAuiPaneInfo_SafeSet, 2650).
+-define(wxAuiPaneInfo_SetFlag, 2651).
+-define(wxAuiPaneInfo_Show, 2652).
+-define(wxAuiPaneInfo_ToolbarPane, 2653).
+-define(wxAuiPaneInfo_Top, 2654).
+-define(wxAuiPaneInfo_TopDockable, 2655).
+-define(wxAuiPaneInfo_Window, 2656).
+-define(wxAuiPaneInfo_GetWindow, 2657).
+-define(wxAuiPaneInfo_GetFrame, 2658).
+-define(wxAuiPaneInfo_GetDirection, 2659).
+-define(wxAuiPaneInfo_GetLayer, 2660).
+-define(wxAuiPaneInfo_GetRow, 2661).
+-define(wxAuiPaneInfo_GetPosition, 2662).
+-define(wxAuiPaneInfo_GetFloatingPosition, 2663).
+-define(wxAuiPaneInfo_GetFloatingSize, 2664).
+-define(wxAuiNotebook_new_0, 2665).
+-define(wxAuiNotebook_new_2, 2666).
+-define(wxAuiNotebook_AddPage, 2667).
+-define(wxAuiNotebook_Create, 2668).
+-define(wxAuiNotebook_DeletePage, 2669).
+-define(wxAuiNotebook_GetArtProvider, 2670).
+-define(wxAuiNotebook_GetPage, 2671).
+-define(wxAuiNotebook_GetPageBitmap, 2672).
+-define(wxAuiNotebook_GetPageCount, 2673).
+-define(wxAuiNotebook_GetPageIndex, 2674).
+-define(wxAuiNotebook_GetPageText, 2675).
+-define(wxAuiNotebook_GetSelection, 2676).
+-define(wxAuiNotebook_InsertPage, 2677).
+-define(wxAuiNotebook_RemovePage, 2678).
+-define(wxAuiNotebook_SetArtProvider, 2679).
+-define(wxAuiNotebook_SetFont, 2680).
+-define(wxAuiNotebook_SetPageBitmap, 2681).
+-define(wxAuiNotebook_SetPageText, 2682).
+-define(wxAuiNotebook_SetSelection, 2683).
+-define(wxAuiNotebook_SetTabCtrlHeight, 2684).
+-define(wxAuiNotebook_SetUniformBitmapSize, 2685).
+-define(wxAuiNotebook_destroy, 2686).
+-define(wxAuiTabArt_SetFlags, 2687).
+-define(wxAuiTabArt_SetMeasuringFont, 2688).
+-define(wxAuiTabArt_SetNormalFont, 2689).
+-define(wxAuiTabArt_SetSelectedFont, 2690).
+-define(wxAuiTabArt_SetColour, 2691).
+-define(wxAuiTabArt_SetActiveColour, 2692).
+-define(wxAuiDockArt_GetColour, 2693).
+-define(wxAuiDockArt_GetFont, 2694).
+-define(wxAuiDockArt_GetMetric, 2695).
+-define(wxAuiDockArt_SetColour, 2696).
+-define(wxAuiDockArt_SetFont, 2697).
+-define(wxAuiDockArt_SetMetric, 2698).
+-define(wxAuiSimpleTabArt_new, 2699).
+-define(wxAuiSimpleTabArt_destroy, 2700).
+-define(wxMDIParentFrame_new_0, 2701).
+-define(wxMDIParentFrame_new_4, 2702).
+-define(wxMDIParentFrame_destruct, 2703).
+-define(wxMDIParentFrame_ActivateNext, 2704).
+-define(wxMDIParentFrame_ActivatePrevious, 2705).
+-define(wxMDIParentFrame_ArrangeIcons, 2706).
+-define(wxMDIParentFrame_Cascade, 2707).
+-define(wxMDIParentFrame_Create, 2708).
+-define(wxMDIParentFrame_GetActiveChild, 2709).
+-define(wxMDIParentFrame_GetClientWindow, 2710).
+-define(wxMDIParentFrame_Tile, 2711).
+-define(wxMDIChildFrame_new_0, 2712).
+-define(wxMDIChildFrame_new_4, 2713).
+-define(wxMDIChildFrame_destruct, 2714).
+-define(wxMDIChildFrame_Activate, 2715).
+-define(wxMDIChildFrame_Create, 2716).
+-define(wxMDIChildFrame_Maximize, 2717).
+-define(wxMDIChildFrame_Restore, 2718).
+-define(wxMDIClientWindow_new_0, 2719).
+-define(wxMDIClientWindow_new_2, 2720).
+-define(wxMDIClientWindow_destruct, 2721).
+-define(wxMDIClientWindow_CreateClient, 2722).
+-define(wxLayoutAlgorithm_new, 2723).
+-define(wxLayoutAlgorithm_LayoutFrame, 2724).
+-define(wxLayoutAlgorithm_LayoutMDIFrame, 2725).
+-define(wxLayoutAlgorithm_LayoutWindow, 2726).
+-define(wxLayoutAlgorithm_destroy, 2727).
+-define(wxEvent_GetId, 2728).
+-define(wxEvent_GetSkipped, 2729).
+-define(wxEvent_GetTimestamp, 2730).
+-define(wxEvent_IsCommandEvent, 2731).
+-define(wxEvent_ResumePropagation, 2732).
+-define(wxEvent_ShouldPropagate, 2733).
+-define(wxEvent_Skip, 2734).
+-define(wxEvent_StopPropagation, 2735).
+-define(wxCommandEvent_getClientData, 2736).
+-define(wxCommandEvent_GetExtraLong, 2737).
+-define(wxCommandEvent_GetInt, 2738).
+-define(wxCommandEvent_GetSelection, 2739).
+-define(wxCommandEvent_GetString, 2740).
+-define(wxCommandEvent_IsChecked, 2741).
+-define(wxCommandEvent_IsSelection, 2742).
+-define(wxCommandEvent_SetInt, 2743).
+-define(wxCommandEvent_SetString, 2744).
+-define(wxScrollEvent_GetOrientation, 2745).
+-define(wxScrollEvent_GetPosition, 2746).
+-define(wxScrollWinEvent_GetOrientation, 2747).
+-define(wxScrollWinEvent_GetPosition, 2748).
+-define(wxMouseEvent_AltDown, 2749).
+-define(wxMouseEvent_Button, 2750).
+-define(wxMouseEvent_ButtonDClick, 2751).
+-define(wxMouseEvent_ButtonDown, 2752).
+-define(wxMouseEvent_ButtonUp, 2753).
+-define(wxMouseEvent_CmdDown, 2754).
+-define(wxMouseEvent_ControlDown, 2755).
+-define(wxMouseEvent_Dragging, 2756).
+-define(wxMouseEvent_Entering, 2757).
+-define(wxMouseEvent_GetButton, 2758).
+-define(wxMouseEvent_GetPosition, 2761).
+-define(wxMouseEvent_GetLogicalPosition, 2762).
+-define(wxMouseEvent_GetLinesPerAction, 2763).
+-define(wxMouseEvent_GetWheelRotation, 2764).
+-define(wxMouseEvent_GetWheelDelta, 2765).
+-define(wxMouseEvent_GetX, 2766).
+-define(wxMouseEvent_GetY, 2767).
+-define(wxMouseEvent_IsButton, 2768).
+-define(wxMouseEvent_IsPageScroll, 2769).
+-define(wxMouseEvent_Leaving, 2770).
+-define(wxMouseEvent_LeftDClick, 2771).
+-define(wxMouseEvent_LeftDown, 2772).
+-define(wxMouseEvent_LeftIsDown, 2773).
+-define(wxMouseEvent_LeftUp, 2774).
+-define(wxMouseEvent_MetaDown, 2775).
+-define(wxMouseEvent_MiddleDClick, 2776).
+-define(wxMouseEvent_MiddleDown, 2777).
+-define(wxMouseEvent_MiddleIsDown, 2778).
+-define(wxMouseEvent_MiddleUp, 2779).
+-define(wxMouseEvent_Moving, 2780).
+-define(wxMouseEvent_RightDClick, 2781).
+-define(wxMouseEvent_RightDown, 2782).
+-define(wxMouseEvent_RightIsDown, 2783).
+-define(wxMouseEvent_RightUp, 2784).
+-define(wxMouseEvent_ShiftDown, 2785).
+-define(wxSetCursorEvent_GetCursor, 2786).
+-define(wxSetCursorEvent_GetX, 2787).
+-define(wxSetCursorEvent_GetY, 2788).
+-define(wxSetCursorEvent_HasCursor, 2789).
+-define(wxSetCursorEvent_SetCursor, 2790).
+-define(wxKeyEvent_AltDown, 2791).
+-define(wxKeyEvent_CmdDown, 2792).
+-define(wxKeyEvent_ControlDown, 2793).
+-define(wxKeyEvent_GetKeyCode, 2794).
+-define(wxKeyEvent_GetModifiers, 2795).
+-define(wxKeyEvent_GetPosition, 2798).
+-define(wxKeyEvent_GetRawKeyCode, 2799).
+-define(wxKeyEvent_GetRawKeyFlags, 2800).
+-define(wxKeyEvent_GetUnicodeKey, 2801).
+-define(wxKeyEvent_GetX, 2802).
+-define(wxKeyEvent_GetY, 2803).
+-define(wxKeyEvent_HasModifiers, 2804).
+-define(wxKeyEvent_MetaDown, 2805).
+-define(wxKeyEvent_ShiftDown, 2806).
+-define(wxSizeEvent_GetSize, 2807).
+-define(wxMoveEvent_GetPosition, 2808).
+-define(wxEraseEvent_GetDC, 2809).
+-define(wxFocusEvent_GetWindow, 2810).
+-define(wxChildFocusEvent_GetWindow, 2811).
+-define(wxMenuEvent_GetMenu, 2812).
+-define(wxMenuEvent_GetMenuId, 2813).
+-define(wxMenuEvent_IsPopup, 2814).
+-define(wxCloseEvent_CanVeto, 2815).
+-define(wxCloseEvent_GetLoggingOff, 2816).
+-define(wxCloseEvent_SetCanVeto, 2817).
+-define(wxCloseEvent_SetLoggingOff, 2818).
+-define(wxCloseEvent_Veto, 2819).
+-define(wxShowEvent_SetShow, 2820).
+-define(wxShowEvent_GetShow, 2821).
+-define(wxIconizeEvent_Iconized, 2822).
+-define(wxJoystickEvent_ButtonDown, 2823).
+-define(wxJoystickEvent_ButtonIsDown, 2824).
+-define(wxJoystickEvent_ButtonUp, 2825).
+-define(wxJoystickEvent_GetButtonChange, 2826).
+-define(wxJoystickEvent_GetButtonState, 2827).
+-define(wxJoystickEvent_GetJoystick, 2828).
+-define(wxJoystickEvent_GetPosition, 2829).
+-define(wxJoystickEvent_GetZPosition, 2830).
+-define(wxJoystickEvent_IsButton, 2831).
+-define(wxJoystickEvent_IsMove, 2832).
+-define(wxJoystickEvent_IsZMove, 2833).
+-define(wxUpdateUIEvent_CanUpdate, 2834).
+-define(wxUpdateUIEvent_Check, 2835).
+-define(wxUpdateUIEvent_Enable, 2836).
+-define(wxUpdateUIEvent_Show, 2837).
+-define(wxUpdateUIEvent_GetChecked, 2838).
+-define(wxUpdateUIEvent_GetEnabled, 2839).
+-define(wxUpdateUIEvent_GetShown, 2840).
+-define(wxUpdateUIEvent_GetSetChecked, 2841).
+-define(wxUpdateUIEvent_GetSetEnabled, 2842).
+-define(wxUpdateUIEvent_GetSetShown, 2843).
+-define(wxUpdateUIEvent_GetSetText, 2844).
+-define(wxUpdateUIEvent_GetText, 2845).
+-define(wxUpdateUIEvent_GetMode, 2846).
+-define(wxUpdateUIEvent_GetUpdateInterval, 2847).
+-define(wxUpdateUIEvent_ResetUpdateTime, 2848).
+-define(wxUpdateUIEvent_SetMode, 2849).
+-define(wxUpdateUIEvent_SetText, 2850).
+-define(wxUpdateUIEvent_SetUpdateInterval, 2851).
+-define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2852).
+-define(wxPaletteChangedEvent_SetChangedWindow, 2853).
+-define(wxPaletteChangedEvent_GetChangedWindow, 2854).
+-define(wxQueryNewPaletteEvent_SetPaletteRealized, 2855).
+-define(wxQueryNewPaletteEvent_GetPaletteRealized, 2856).
+-define(wxNavigationKeyEvent_GetDirection, 2857).
+-define(wxNavigationKeyEvent_SetDirection, 2858).
+-define(wxNavigationKeyEvent_IsWindowChange, 2859).
+-define(wxNavigationKeyEvent_SetWindowChange, 2860).
+-define(wxNavigationKeyEvent_IsFromTab, 2861).
+-define(wxNavigationKeyEvent_SetFromTab, 2862).
+-define(wxNavigationKeyEvent_GetCurrentFocus, 2863).
+-define(wxNavigationKeyEvent_SetCurrentFocus, 2864).
+-define(wxHelpEvent_GetOrigin, 2865).
+-define(wxHelpEvent_GetPosition, 2866).
+-define(wxHelpEvent_SetOrigin, 2867).
+-define(wxHelpEvent_SetPosition, 2868).
+-define(wxContextMenuEvent_GetPosition, 2869).
+-define(wxContextMenuEvent_SetPosition, 2870).
+-define(wxIdleEvent_CanSend, 2871).
+-define(wxIdleEvent_GetMode, 2872).
+-define(wxIdleEvent_RequestMore, 2873).
+-define(wxIdleEvent_MoreRequested, 2874).
+-define(wxIdleEvent_SetMode, 2875).
+-define(wxGridEvent_AltDown, 2876).
+-define(wxGridEvent_ControlDown, 2877).
+-define(wxGridEvent_GetCol, 2878).
+-define(wxGridEvent_GetPosition, 2879).
+-define(wxGridEvent_GetRow, 2880).
+-define(wxGridEvent_MetaDown, 2881).
+-define(wxGridEvent_Selecting, 2882).
+-define(wxGridEvent_ShiftDown, 2883).
+-define(wxNotifyEvent_Allow, 2884).
+-define(wxNotifyEvent_IsAllowed, 2885).
+-define(wxNotifyEvent_Veto, 2886).
+-define(wxSashEvent_GetEdge, 2887).
+-define(wxSashEvent_GetDragRect, 2888).
+-define(wxSashEvent_GetDragStatus, 2889).
+-define(wxListEvent_GetCacheFrom, 2890).
+-define(wxListEvent_GetCacheTo, 2891).
+-define(wxListEvent_GetKeyCode, 2892).
+-define(wxListEvent_GetIndex, 2893).
+-define(wxListEvent_GetColumn, 2894).
+-define(wxListEvent_GetPoint, 2895).
+-define(wxListEvent_GetLabel, 2896).
+-define(wxListEvent_GetText, 2897).
+-define(wxListEvent_GetImage, 2898).
+-define(wxListEvent_GetData, 2899).
+-define(wxListEvent_GetMask, 2900).
+-define(wxListEvent_GetItem, 2901).
+-define(wxListEvent_IsEditCancelled, 2902).
+-define(wxDateEvent_GetDate, 2903).
+-define(wxCalendarEvent_GetWeekDay, 2904).
+-define(wxFileDirPickerEvent_GetPath, 2905).
+-define(wxColourPickerEvent_GetColour, 2906).
+-define(wxFontPickerEvent_GetFont, 2907).
+-define(wxStyledTextEvent_GetPosition, 2908).
+-define(wxStyledTextEvent_GetKey, 2909).
+-define(wxStyledTextEvent_GetModifiers, 2910).
+-define(wxStyledTextEvent_GetModificationType, 2911).
+-define(wxStyledTextEvent_GetText, 2912).
+-define(wxStyledTextEvent_GetLength, 2913).
+-define(wxStyledTextEvent_GetLinesAdded, 2914).
+-define(wxStyledTextEvent_GetLine, 2915).
+-define(wxStyledTextEvent_GetFoldLevelNow, 2916).
+-define(wxStyledTextEvent_GetFoldLevelPrev, 2917).
+-define(wxStyledTextEvent_GetMargin, 2918).
+-define(wxStyledTextEvent_GetMessage, 2919).
+-define(wxStyledTextEvent_GetWParam, 2920).
+-define(wxStyledTextEvent_GetLParam, 2921).
+-define(wxStyledTextEvent_GetListType, 2922).
+-define(wxStyledTextEvent_GetX, 2923).
+-define(wxStyledTextEvent_GetY, 2924).
+-define(wxStyledTextEvent_GetDragText, 2925).
+-define(wxStyledTextEvent_GetDragAllowMove, 2926).
+-define(wxStyledTextEvent_GetDragResult, 2927).
+-define(wxStyledTextEvent_GetShift, 2928).
+-define(wxStyledTextEvent_GetControl, 2929).
+-define(wxStyledTextEvent_GetAlt, 2930).
+-define(utils_wxGetKeyState, 2931).
+-define(utils_wxGetMousePosition, 2932).
+-define(utils_wxGetMouseState, 2933).
+-define(utils_wxSetDetectableAutoRepeat, 2934).
+-define(utils_wxBell, 2935).
+-define(utils_wxFindMenuItemId, 2936).
+-define(utils_wxGenericFindWindowAtPoint, 2937).
+-define(utils_wxFindWindowAtPoint, 2938).
+-define(utils_wxBeginBusyCursor, 2939).
+-define(utils_wxEndBusyCursor, 2940).
+-define(utils_wxIsBusy, 2941).
+-define(utils_wxShutdown, 2942).
+-define(utils_wxShell, 2943).
+-define(utils_wxLaunchDefaultBrowser, 2944).
+-define(utils_wxGetEmailAddress, 2945).
+-define(utils_wxGetUserId, 2946).
+-define(utils_wxGetHomeDir, 2947).
+-define(utils_wxNewId, 2948).
+-define(utils_wxRegisterId, 2949).
+-define(utils_wxGetCurrentId, 2950).
+-define(utils_wxGetOsDescription, 2951).
+-define(utils_wxIsPlatformLittleEndian, 2952).
+-define(utils_wxIsPlatform64Bit, 2953).
+-define(gdicmn_wxDisplaySize, 2954).
+-define(gdicmn_wxSetCursor, 2955).
+-define(wxPrintout_new, 2956).
+-define(wxPrintout_destruct, 2957).
+-define(wxPrintout_GetDC, 2958).
+-define(wxPrintout_GetPageSizeMM, 2959).
+-define(wxPrintout_GetPageSizePixels, 2960).
+-define(wxPrintout_GetPaperRectPixels, 2961).
+-define(wxPrintout_GetPPIPrinter, 2962).
+-define(wxPrintout_GetPPIScreen, 2963).
+-define(wxPrintout_GetTitle, 2964).
+-define(wxPrintout_IsPreview, 2965).
+-define(wxPrintout_FitThisSizeToPaper, 2966).
+-define(wxPrintout_FitThisSizeToPage, 2967).
+-define(wxPrintout_FitThisSizeToPageMargins, 2968).
+-define(wxPrintout_MapScreenSizeToPaper, 2969).
+-define(wxPrintout_MapScreenSizeToPage, 2970).
+-define(wxPrintout_MapScreenSizeToPageMargins, 2971).
+-define(wxPrintout_MapScreenSizeToDevice, 2972).
+-define(wxPrintout_GetLogicalPaperRect, 2973).
+-define(wxPrintout_GetLogicalPageRect, 2974).
+-define(wxPrintout_GetLogicalPageMarginsRect, 2975).
+-define(wxPrintout_SetLogicalOrigin, 2976).
+-define(wxPrintout_OffsetLogicalOrigin, 2977).
+-define(wxStyledTextCtrl_new_2, 2978).
+-define(wxStyledTextCtrl_new_0, 2979).
+-define(wxStyledTextCtrl_destruct, 2980).
+-define(wxStyledTextCtrl_Create, 2981).
+-define(wxStyledTextCtrl_AddText, 2982).
+-define(wxStyledTextCtrl_AddStyledText, 2983).
+-define(wxStyledTextCtrl_InsertText, 2984).
+-define(wxStyledTextCtrl_ClearAll, 2985).
+-define(wxStyledTextCtrl_ClearDocumentStyle, 2986).
+-define(wxStyledTextCtrl_GetLength, 2987).
+-define(wxStyledTextCtrl_GetCharAt, 2988).
+-define(wxStyledTextCtrl_GetCurrentPos, 2989).
+-define(wxStyledTextCtrl_GetAnchor, 2990).
+-define(wxStyledTextCtrl_GetStyleAt, 2991).
+-define(wxStyledTextCtrl_Redo, 2992).
+-define(wxStyledTextCtrl_SetUndoCollection, 2993).
+-define(wxStyledTextCtrl_SelectAll, 2994).
+-define(wxStyledTextCtrl_SetSavePoint, 2995).
+-define(wxStyledTextCtrl_GetStyledText, 2996).
+-define(wxStyledTextCtrl_CanRedo, 2997).
+-define(wxStyledTextCtrl_MarkerLineFromHandle, 2998).
+-define(wxStyledTextCtrl_MarkerDeleteHandle, 2999).
+-define(wxStyledTextCtrl_GetUndoCollection, 3000).
+-define(wxStyledTextCtrl_GetViewWhiteSpace, 3001).
+-define(wxStyledTextCtrl_SetViewWhiteSpace, 3002).
+-define(wxStyledTextCtrl_PositionFromPoint, 3003).
+-define(wxStyledTextCtrl_PositionFromPointClose, 3004).
+-define(wxStyledTextCtrl_GotoLine, 3005).
+-define(wxStyledTextCtrl_GotoPos, 3006).
+-define(wxStyledTextCtrl_SetAnchor, 3007).
+-define(wxStyledTextCtrl_GetCurLine, 3008).
+-define(wxStyledTextCtrl_GetEndStyled, 3009).
+-define(wxStyledTextCtrl_ConvertEOLs, 3010).
+-define(wxStyledTextCtrl_GetEOLMode, 3011).
+-define(wxStyledTextCtrl_SetEOLMode, 3012).
+-define(wxStyledTextCtrl_StartStyling, 3013).
+-define(wxStyledTextCtrl_SetStyling, 3014).
+-define(wxStyledTextCtrl_GetBufferedDraw, 3015).
+-define(wxStyledTextCtrl_SetBufferedDraw, 3016).
+-define(wxStyledTextCtrl_SetTabWidth, 3017).
+-define(wxStyledTextCtrl_GetTabWidth, 3018).
+-define(wxStyledTextCtrl_SetCodePage, 3019).
+-define(wxStyledTextCtrl_MarkerDefine, 3020).
+-define(wxStyledTextCtrl_MarkerSetForeground, 3021).
+-define(wxStyledTextCtrl_MarkerSetBackground, 3022).
+-define(wxStyledTextCtrl_MarkerAdd, 3023).
+-define(wxStyledTextCtrl_MarkerDelete, 3024).
+-define(wxStyledTextCtrl_MarkerDeleteAll, 3025).
+-define(wxStyledTextCtrl_MarkerGet, 3026).
+-define(wxStyledTextCtrl_MarkerNext, 3027).
+-define(wxStyledTextCtrl_MarkerPrevious, 3028).
+-define(wxStyledTextCtrl_MarkerDefineBitmap, 3029).
+-define(wxStyledTextCtrl_MarkerAddSet, 3030).
+-define(wxStyledTextCtrl_MarkerSetAlpha, 3031).
+-define(wxStyledTextCtrl_SetMarginType, 3032).
+-define(wxStyledTextCtrl_GetMarginType, 3033).
+-define(wxStyledTextCtrl_SetMarginWidth, 3034).
+-define(wxStyledTextCtrl_GetMarginWidth, 3035).
+-define(wxStyledTextCtrl_SetMarginMask, 3036).
+-define(wxStyledTextCtrl_GetMarginMask, 3037).
+-define(wxStyledTextCtrl_SetMarginSensitive, 3038).
+-define(wxStyledTextCtrl_GetMarginSensitive, 3039).
+-define(wxStyledTextCtrl_StyleClearAll, 3040).
+-define(wxStyledTextCtrl_StyleSetForeground, 3041).
+-define(wxStyledTextCtrl_StyleSetBackground, 3042).
+-define(wxStyledTextCtrl_StyleSetBold, 3043).
+-define(wxStyledTextCtrl_StyleSetItalic, 3044).
+-define(wxStyledTextCtrl_StyleSetSize, 3045).
+-define(wxStyledTextCtrl_StyleSetFaceName, 3046).
+-define(wxStyledTextCtrl_StyleSetEOLFilled, 3047).
+-define(wxStyledTextCtrl_StyleResetDefault, 3048).
+-define(wxStyledTextCtrl_StyleSetUnderline, 3049).
+-define(wxStyledTextCtrl_StyleSetCase, 3050).
+-define(wxStyledTextCtrl_StyleSetHotSpot, 3051).
+-define(wxStyledTextCtrl_SetSelForeground, 3052).
+-define(wxStyledTextCtrl_SetSelBackground, 3053).
+-define(wxStyledTextCtrl_GetSelAlpha, 3054).
+-define(wxStyledTextCtrl_SetSelAlpha, 3055).
+-define(wxStyledTextCtrl_SetCaretForeground, 3056).
+-define(wxStyledTextCtrl_CmdKeyAssign, 3057).
+-define(wxStyledTextCtrl_CmdKeyClear, 3058).
+-define(wxStyledTextCtrl_CmdKeyClearAll, 3059).
+-define(wxStyledTextCtrl_SetStyleBytes, 3060).
+-define(wxStyledTextCtrl_StyleSetVisible, 3061).
+-define(wxStyledTextCtrl_GetCaretPeriod, 3062).
+-define(wxStyledTextCtrl_SetCaretPeriod, 3063).
+-define(wxStyledTextCtrl_SetWordChars, 3064).
+-define(wxStyledTextCtrl_BeginUndoAction, 3065).
+-define(wxStyledTextCtrl_EndUndoAction, 3066).
+-define(wxStyledTextCtrl_IndicatorSetStyle, 3067).
+-define(wxStyledTextCtrl_IndicatorGetStyle, 3068).
+-define(wxStyledTextCtrl_IndicatorSetForeground, 3069).
+-define(wxStyledTextCtrl_IndicatorGetForeground, 3070).
+-define(wxStyledTextCtrl_SetWhitespaceForeground, 3071).
+-define(wxStyledTextCtrl_SetWhitespaceBackground, 3072).
+-define(wxStyledTextCtrl_GetStyleBits, 3073).
+-define(wxStyledTextCtrl_SetLineState, 3074).
+-define(wxStyledTextCtrl_GetLineState, 3075).
+-define(wxStyledTextCtrl_GetMaxLineState, 3076).
+-define(wxStyledTextCtrl_GetCaretLineVisible, 3077).
+-define(wxStyledTextCtrl_SetCaretLineVisible, 3078).
+-define(wxStyledTextCtrl_GetCaretLineBackground, 3079).
+-define(wxStyledTextCtrl_SetCaretLineBackground, 3080).
+-define(wxStyledTextCtrl_AutoCompShow, 3081).
+-define(wxStyledTextCtrl_AutoCompCancel, 3082).
+-define(wxStyledTextCtrl_AutoCompActive, 3083).
+-define(wxStyledTextCtrl_AutoCompPosStart, 3084).
+-define(wxStyledTextCtrl_AutoCompComplete, 3085).
+-define(wxStyledTextCtrl_AutoCompStops, 3086).
+-define(wxStyledTextCtrl_AutoCompSetSeparator, 3087).
+-define(wxStyledTextCtrl_AutoCompGetSeparator, 3088).
+-define(wxStyledTextCtrl_AutoCompSelect, 3089).
+-define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3090).
+-define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3091).
+-define(wxStyledTextCtrl_AutoCompSetFillUps, 3092).
+-define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3093).
+-define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3094).
+-define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3095).
+-define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3096).
+-define(wxStyledTextCtrl_UserListShow, 3097).
+-define(wxStyledTextCtrl_AutoCompSetAutoHide, 3098).
+-define(wxStyledTextCtrl_AutoCompGetAutoHide, 3099).
+-define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3100).
+-define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3101).
+-define(wxStyledTextCtrl_RegisterImage, 3102).
+-define(wxStyledTextCtrl_ClearRegisteredImages, 3103).
+-define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3104).
+-define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3105).
+-define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3106).
+-define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3107).
+-define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3108).
+-define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3109).
+-define(wxStyledTextCtrl_SetIndent, 3110).
+-define(wxStyledTextCtrl_GetIndent, 3111).
+-define(wxStyledTextCtrl_SetUseTabs, 3112).
+-define(wxStyledTextCtrl_GetUseTabs, 3113).
+-define(wxStyledTextCtrl_SetLineIndentation, 3114).
+-define(wxStyledTextCtrl_GetLineIndentation, 3115).
+-define(wxStyledTextCtrl_GetLineIndentPosition, 3116).
+-define(wxStyledTextCtrl_GetColumn, 3117).
+-define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3118).
+-define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3119).
+-define(wxStyledTextCtrl_SetIndentationGuides, 3120).
+-define(wxStyledTextCtrl_GetIndentationGuides, 3121).
+-define(wxStyledTextCtrl_SetHighlightGuide, 3122).
+-define(wxStyledTextCtrl_GetHighlightGuide, 3123).
+-define(wxStyledTextCtrl_GetLineEndPosition, 3124).
+-define(wxStyledTextCtrl_GetCodePage, 3125).
+-define(wxStyledTextCtrl_GetCaretForeground, 3126).
+-define(wxStyledTextCtrl_GetReadOnly, 3127).
+-define(wxStyledTextCtrl_SetCurrentPos, 3128).
+-define(wxStyledTextCtrl_SetSelectionStart, 3129).
+-define(wxStyledTextCtrl_GetSelectionStart, 3130).
+-define(wxStyledTextCtrl_SetSelectionEnd, 3131).
+-define(wxStyledTextCtrl_GetSelectionEnd, 3132).
+-define(wxStyledTextCtrl_SetPrintMagnification, 3133).
+-define(wxStyledTextCtrl_GetPrintMagnification, 3134).
+-define(wxStyledTextCtrl_SetPrintColourMode, 3135).
+-define(wxStyledTextCtrl_GetPrintColourMode, 3136).
+-define(wxStyledTextCtrl_FindText, 3137).
+-define(wxStyledTextCtrl_FormatRange, 3138).
+-define(wxStyledTextCtrl_GetFirstVisibleLine, 3139).
+-define(wxStyledTextCtrl_GetLine, 3140).
+-define(wxStyledTextCtrl_GetLineCount, 3141).
+-define(wxStyledTextCtrl_SetMarginLeft, 3142).
+-define(wxStyledTextCtrl_GetMarginLeft, 3143).
+-define(wxStyledTextCtrl_SetMarginRight, 3144).
+-define(wxStyledTextCtrl_GetMarginRight, 3145).
+-define(wxStyledTextCtrl_GetModify, 3146).
+-define(wxStyledTextCtrl_SetSelection, 3147).
+-define(wxStyledTextCtrl_GetSelectedText, 3148).
+-define(wxStyledTextCtrl_GetTextRange, 3149).
+-define(wxStyledTextCtrl_HideSelection, 3150).
+-define(wxStyledTextCtrl_LineFromPosition, 3151).
+-define(wxStyledTextCtrl_PositionFromLine, 3152).
+-define(wxStyledTextCtrl_LineScroll, 3153).
+-define(wxStyledTextCtrl_EnsureCaretVisible, 3154).
+-define(wxStyledTextCtrl_ReplaceSelection, 3155).
+-define(wxStyledTextCtrl_SetReadOnly, 3156).
+-define(wxStyledTextCtrl_CanPaste, 3157).
+-define(wxStyledTextCtrl_CanUndo, 3158).
+-define(wxStyledTextCtrl_EmptyUndoBuffer, 3159).
+-define(wxStyledTextCtrl_Undo, 3160).
+-define(wxStyledTextCtrl_Cut, 3161).
+-define(wxStyledTextCtrl_Copy, 3162).
+-define(wxStyledTextCtrl_Paste, 3163).
+-define(wxStyledTextCtrl_Clear, 3164).
+-define(wxStyledTextCtrl_SetText, 3165).
+-define(wxStyledTextCtrl_GetText, 3166).
+-define(wxStyledTextCtrl_GetTextLength, 3167).
+-define(wxStyledTextCtrl_GetOvertype, 3168).
+-define(wxStyledTextCtrl_SetCaretWidth, 3169).
+-define(wxStyledTextCtrl_GetCaretWidth, 3170).
+-define(wxStyledTextCtrl_SetTargetStart, 3171).
+-define(wxStyledTextCtrl_GetTargetStart, 3172).
+-define(wxStyledTextCtrl_SetTargetEnd, 3173).
+-define(wxStyledTextCtrl_GetTargetEnd, 3174).
+-define(wxStyledTextCtrl_ReplaceTarget, 3175).
+-define(wxStyledTextCtrl_SearchInTarget, 3176).
+-define(wxStyledTextCtrl_SetSearchFlags, 3177).
+-define(wxStyledTextCtrl_GetSearchFlags, 3178).
+-define(wxStyledTextCtrl_CallTipShow, 3179).
+-define(wxStyledTextCtrl_CallTipCancel, 3180).
+-define(wxStyledTextCtrl_CallTipActive, 3181).
+-define(wxStyledTextCtrl_CallTipPosAtStart, 3182).
+-define(wxStyledTextCtrl_CallTipSetHighlight, 3183).
+-define(wxStyledTextCtrl_CallTipSetBackground, 3184).
+-define(wxStyledTextCtrl_CallTipSetForeground, 3185).
+-define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3186).
+-define(wxStyledTextCtrl_CallTipUseStyle, 3187).
+-define(wxStyledTextCtrl_VisibleFromDocLine, 3188).
+-define(wxStyledTextCtrl_DocLineFromVisible, 3189).
+-define(wxStyledTextCtrl_WrapCount, 3190).
+-define(wxStyledTextCtrl_SetFoldLevel, 3191).
+-define(wxStyledTextCtrl_GetFoldLevel, 3192).
+-define(wxStyledTextCtrl_GetLastChild, 3193).
+-define(wxStyledTextCtrl_GetFoldParent, 3194).
+-define(wxStyledTextCtrl_ShowLines, 3195).
+-define(wxStyledTextCtrl_HideLines, 3196).
+-define(wxStyledTextCtrl_GetLineVisible, 3197).
+-define(wxStyledTextCtrl_SetFoldExpanded, 3198).
+-define(wxStyledTextCtrl_GetFoldExpanded, 3199).
+-define(wxStyledTextCtrl_ToggleFold, 3200).
+-define(wxStyledTextCtrl_EnsureVisible, 3201).
+-define(wxStyledTextCtrl_SetFoldFlags, 3202).
+-define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3203).
+-define(wxStyledTextCtrl_SetTabIndents, 3204).
+-define(wxStyledTextCtrl_GetTabIndents, 3205).
+-define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3206).
+-define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3207).
+-define(wxStyledTextCtrl_SetMouseDwellTime, 3208).
+-define(wxStyledTextCtrl_GetMouseDwellTime, 3209).
+-define(wxStyledTextCtrl_WordStartPosition, 3210).
+-define(wxStyledTextCtrl_WordEndPosition, 3211).
+-define(wxStyledTextCtrl_SetWrapMode, 3212).
+-define(wxStyledTextCtrl_GetWrapMode, 3213).
+-define(wxStyledTextCtrl_SetWrapVisualFlags, 3214).
+-define(wxStyledTextCtrl_GetWrapVisualFlags, 3215).
+-define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3216).
+-define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3217).
+-define(wxStyledTextCtrl_SetWrapStartIndent, 3218).
+-define(wxStyledTextCtrl_GetWrapStartIndent, 3219).
+-define(wxStyledTextCtrl_SetLayoutCache, 3220).
+-define(wxStyledTextCtrl_GetLayoutCache, 3221).
+-define(wxStyledTextCtrl_SetScrollWidth, 3222).
+-define(wxStyledTextCtrl_GetScrollWidth, 3223).
+-define(wxStyledTextCtrl_TextWidth, 3224).
+-define(wxStyledTextCtrl_GetEndAtLastLine, 3225).
+-define(wxStyledTextCtrl_TextHeight, 3226).
+-define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3227).
+-define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3228).
+-define(wxStyledTextCtrl_AppendText, 3229).
+-define(wxStyledTextCtrl_GetTwoPhaseDraw, 3230).
+-define(wxStyledTextCtrl_SetTwoPhaseDraw, 3231).
+-define(wxStyledTextCtrl_TargetFromSelection, 3232).
+-define(wxStyledTextCtrl_LinesJoin, 3233).
+-define(wxStyledTextCtrl_LinesSplit, 3234).
+-define(wxStyledTextCtrl_SetFoldMarginColour, 3235).
+-define(wxStyledTextCtrl_SetFoldMarginHiColour, 3236).
+-define(wxStyledTextCtrl_LineDown, 3237).
+-define(wxStyledTextCtrl_LineDownExtend, 3238).
+-define(wxStyledTextCtrl_LineUp, 3239).
+-define(wxStyledTextCtrl_LineUpExtend, 3240).
+-define(wxStyledTextCtrl_CharLeft, 3241).
+-define(wxStyledTextCtrl_CharLeftExtend, 3242).
+-define(wxStyledTextCtrl_CharRight, 3243).
+-define(wxStyledTextCtrl_CharRightExtend, 3244).
+-define(wxStyledTextCtrl_WordLeft, 3245).
+-define(wxStyledTextCtrl_WordLeftExtend, 3246).
+-define(wxStyledTextCtrl_WordRight, 3247).
+-define(wxStyledTextCtrl_WordRightExtend, 3248).
+-define(wxStyledTextCtrl_Home, 3249).
+-define(wxStyledTextCtrl_HomeExtend, 3250).
+-define(wxStyledTextCtrl_LineEnd, 3251).
+-define(wxStyledTextCtrl_LineEndExtend, 3252).
+-define(wxStyledTextCtrl_DocumentStart, 3253).
+-define(wxStyledTextCtrl_DocumentStartExtend, 3254).
+-define(wxStyledTextCtrl_DocumentEnd, 3255).
+-define(wxStyledTextCtrl_DocumentEndExtend, 3256).
+-define(wxStyledTextCtrl_PageUp, 3257).
+-define(wxStyledTextCtrl_PageUpExtend, 3258).
+-define(wxStyledTextCtrl_PageDown, 3259).
+-define(wxStyledTextCtrl_PageDownExtend, 3260).
+-define(wxStyledTextCtrl_EditToggleOvertype, 3261).
+-define(wxStyledTextCtrl_Cancel, 3262).
+-define(wxStyledTextCtrl_DeleteBack, 3263).
+-define(wxStyledTextCtrl_Tab, 3264).
+-define(wxStyledTextCtrl_BackTab, 3265).
+-define(wxStyledTextCtrl_NewLine, 3266).
+-define(wxStyledTextCtrl_FormFeed, 3267).
+-define(wxStyledTextCtrl_VCHome, 3268).
+-define(wxStyledTextCtrl_VCHomeExtend, 3269).
+-define(wxStyledTextCtrl_ZoomIn, 3270).
+-define(wxStyledTextCtrl_ZoomOut, 3271).
+-define(wxStyledTextCtrl_DelWordLeft, 3272).
+-define(wxStyledTextCtrl_DelWordRight, 3273).
+-define(wxStyledTextCtrl_LineCut, 3274).
+-define(wxStyledTextCtrl_LineDelete, 3275).
+-define(wxStyledTextCtrl_LineTranspose, 3276).
+-define(wxStyledTextCtrl_LineDuplicate, 3277).
+-define(wxStyledTextCtrl_LowerCase, 3278).
+-define(wxStyledTextCtrl_UpperCase, 3279).
+-define(wxStyledTextCtrl_LineScrollDown, 3280).
+-define(wxStyledTextCtrl_LineScrollUp, 3281).
+-define(wxStyledTextCtrl_DeleteBackNotLine, 3282).
+-define(wxStyledTextCtrl_HomeDisplay, 3283).
+-define(wxStyledTextCtrl_HomeDisplayExtend, 3284).
+-define(wxStyledTextCtrl_LineEndDisplay, 3285).
+-define(wxStyledTextCtrl_LineEndDisplayExtend, 3286).
+-define(wxStyledTextCtrl_HomeWrapExtend, 3287).
+-define(wxStyledTextCtrl_LineEndWrap, 3288).
+-define(wxStyledTextCtrl_LineEndWrapExtend, 3289).
+-define(wxStyledTextCtrl_VCHomeWrap, 3290).
+-define(wxStyledTextCtrl_VCHomeWrapExtend, 3291).
+-define(wxStyledTextCtrl_LineCopy, 3292).
+-define(wxStyledTextCtrl_MoveCaretInsideView, 3293).
+-define(wxStyledTextCtrl_LineLength, 3294).
+-define(wxStyledTextCtrl_BraceHighlight, 3295).
+-define(wxStyledTextCtrl_BraceBadLight, 3296).
+-define(wxStyledTextCtrl_BraceMatch, 3297).
+-define(wxStyledTextCtrl_GetViewEOL, 3298).
+-define(wxStyledTextCtrl_SetViewEOL, 3299).
+-define(wxStyledTextCtrl_SetModEventMask, 3300).
+-define(wxStyledTextCtrl_GetEdgeColumn, 3301).
+-define(wxStyledTextCtrl_SetEdgeColumn, 3302).
+-define(wxStyledTextCtrl_SetEdgeMode, 3303).
+-define(wxStyledTextCtrl_GetEdgeMode, 3304).
+-define(wxStyledTextCtrl_GetEdgeColour, 3305).
+-define(wxStyledTextCtrl_SetEdgeColour, 3306).
+-define(wxStyledTextCtrl_SearchAnchor, 3307).
+-define(wxStyledTextCtrl_SearchNext, 3308).
+-define(wxStyledTextCtrl_SearchPrev, 3309).
+-define(wxStyledTextCtrl_LinesOnScreen, 3310).
+-define(wxStyledTextCtrl_UsePopUp, 3311).
+-define(wxStyledTextCtrl_SelectionIsRectangle, 3312).
+-define(wxStyledTextCtrl_SetZoom, 3313).
+-define(wxStyledTextCtrl_GetZoom, 3314).
+-define(wxStyledTextCtrl_GetModEventMask, 3315).
+-define(wxStyledTextCtrl_SetSTCFocus, 3316).
+-define(wxStyledTextCtrl_GetSTCFocus, 3317).
+-define(wxStyledTextCtrl_SetStatus, 3318).
+-define(wxStyledTextCtrl_GetStatus, 3319).
+-define(wxStyledTextCtrl_SetMouseDownCaptures, 3320).
+-define(wxStyledTextCtrl_GetMouseDownCaptures, 3321).
+-define(wxStyledTextCtrl_SetSTCCursor, 3322).
+-define(wxStyledTextCtrl_GetSTCCursor, 3323).
+-define(wxStyledTextCtrl_SetControlCharSymbol, 3324).
+-define(wxStyledTextCtrl_GetControlCharSymbol, 3325).
+-define(wxStyledTextCtrl_WordPartLeft, 3326).
+-define(wxStyledTextCtrl_WordPartLeftExtend, 3327).
+-define(wxStyledTextCtrl_WordPartRight, 3328).
+-define(wxStyledTextCtrl_WordPartRightExtend, 3329).
+-define(wxStyledTextCtrl_SetVisiblePolicy, 3330).
+-define(wxStyledTextCtrl_DelLineLeft, 3331).
+-define(wxStyledTextCtrl_DelLineRight, 3332).
+-define(wxStyledTextCtrl_GetXOffset, 3333).
+-define(wxStyledTextCtrl_ChooseCaretX, 3334).
+-define(wxStyledTextCtrl_SetXCaretPolicy, 3335).
+-define(wxStyledTextCtrl_SetYCaretPolicy, 3336).
+-define(wxStyledTextCtrl_GetPrintWrapMode, 3337).
+-define(wxStyledTextCtrl_SetHotspotActiveForeground, 3338).
+-define(wxStyledTextCtrl_SetHotspotActiveBackground, 3339).
+-define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3340).
+-define(wxStyledTextCtrl_SetHotspotSingleLine, 3341).
+-define(wxStyledTextCtrl_ParaDownExtend, 3342).
+-define(wxStyledTextCtrl_ParaUp, 3343).
+-define(wxStyledTextCtrl_ParaUpExtend, 3344).
+-define(wxStyledTextCtrl_PositionBefore, 3345).
+-define(wxStyledTextCtrl_PositionAfter, 3346).
+-define(wxStyledTextCtrl_CopyRange, 3347).
+-define(wxStyledTextCtrl_CopyText, 3348).
+-define(wxStyledTextCtrl_SetSelectionMode, 3349).
+-define(wxStyledTextCtrl_GetSelectionMode, 3350).
+-define(wxStyledTextCtrl_LineDownRectExtend, 3351).
+-define(wxStyledTextCtrl_LineUpRectExtend, 3352).
+-define(wxStyledTextCtrl_CharLeftRectExtend, 3353).
+-define(wxStyledTextCtrl_CharRightRectExtend, 3354).
+-define(wxStyledTextCtrl_HomeRectExtend, 3355).
+-define(wxStyledTextCtrl_VCHomeRectExtend, 3356).
+-define(wxStyledTextCtrl_LineEndRectExtend, 3357).
+-define(wxStyledTextCtrl_PageUpRectExtend, 3358).
+-define(wxStyledTextCtrl_PageDownRectExtend, 3359).
+-define(wxStyledTextCtrl_StutteredPageUp, 3360).
+-define(wxStyledTextCtrl_StutteredPageUpExtend, 3361).
+-define(wxStyledTextCtrl_StutteredPageDown, 3362).
+-define(wxStyledTextCtrl_StutteredPageDownExtend, 3363).
+-define(wxStyledTextCtrl_WordLeftEnd, 3364).
+-define(wxStyledTextCtrl_WordLeftEndExtend, 3365).
+-define(wxStyledTextCtrl_WordRightEnd, 3366).
+-define(wxStyledTextCtrl_WordRightEndExtend, 3367).
+-define(wxStyledTextCtrl_SetWhitespaceChars, 3368).
+-define(wxStyledTextCtrl_SetCharsDefault, 3369).
+-define(wxStyledTextCtrl_AutoCompGetCurrent, 3370).
+-define(wxStyledTextCtrl_Allocate, 3371).
+-define(wxStyledTextCtrl_FindColumn, 3372).
+-define(wxStyledTextCtrl_GetCaretSticky, 3373).
+-define(wxStyledTextCtrl_SetCaretSticky, 3374).
+-define(wxStyledTextCtrl_ToggleCaretSticky, 3375).
+-define(wxStyledTextCtrl_SetPasteConvertEndings, 3376).
+-define(wxStyledTextCtrl_GetPasteConvertEndings, 3377).
+-define(wxStyledTextCtrl_SelectionDuplicate, 3378).
+-define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3379).
+-define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3380).
+-define(wxStyledTextCtrl_StartRecord, 3381).
+-define(wxStyledTextCtrl_StopRecord, 3382).
+-define(wxStyledTextCtrl_SetLexer, 3383).
+-define(wxStyledTextCtrl_GetLexer, 3384).
+-define(wxStyledTextCtrl_Colourise, 3385).
+-define(wxStyledTextCtrl_SetProperty, 3386).
+-define(wxStyledTextCtrl_SetKeyWords, 3387).
+-define(wxStyledTextCtrl_SetLexerLanguage, 3388).
+-define(wxStyledTextCtrl_GetProperty, 3389).
+-define(wxStyledTextCtrl_GetStyleBitsNeeded, 3390).
+-define(wxStyledTextCtrl_GetCurrentLine, 3391).
+-define(wxStyledTextCtrl_StyleSetSpec, 3392).
+-define(wxStyledTextCtrl_StyleSetFont, 3393).
+-define(wxStyledTextCtrl_StyleSetFontAttr, 3394).
+-define(wxStyledTextCtrl_StyleSetCharacterSet, 3395).
+-define(wxStyledTextCtrl_StyleSetFontEncoding, 3396).
+-define(wxStyledTextCtrl_CmdKeyExecute, 3397).
+-define(wxStyledTextCtrl_SetMargins, 3398).
+-define(wxStyledTextCtrl_GetSelection, 3399).
+-define(wxStyledTextCtrl_PointFromPosition, 3400).
+-define(wxStyledTextCtrl_ScrollToLine, 3401).
+-define(wxStyledTextCtrl_ScrollToColumn, 3402).
+-define(wxStyledTextCtrl_SetVScrollBar, 3403).
+-define(wxStyledTextCtrl_SetHScrollBar, 3404).
+-define(wxStyledTextCtrl_GetLastKeydownProcessed, 3405).
+-define(wxStyledTextCtrl_SetLastKeydownProcessed, 3406).
+-define(wxStyledTextCtrl_SaveFile, 3407).
+-define(wxStyledTextCtrl_LoadFile, 3408).
+-define(wxStyledTextCtrl_DoDragOver, 3409).
+-define(wxStyledTextCtrl_DoDropText, 3410).
+-define(wxStyledTextCtrl_GetUseAntiAliasing, 3411).
+-define(wxStyledTextCtrl_AddTextRaw, 3412).
+-define(wxStyledTextCtrl_InsertTextRaw, 3413).
+-define(wxStyledTextCtrl_GetCurLineRaw, 3414).
+-define(wxStyledTextCtrl_GetLineRaw, 3415).
+-define(wxStyledTextCtrl_GetSelectedTextRaw, 3416).
+-define(wxStyledTextCtrl_GetTextRangeRaw, 3417).
+-define(wxStyledTextCtrl_SetTextRaw, 3418).
+-define(wxStyledTextCtrl_GetTextRaw, 3419).
+-define(wxStyledTextCtrl_AppendTextRaw, 3420).
+-define(wxArtProvider_GetBitmap, 3421).
+-define(wxArtProvider_GetIcon, 3422).
+-define(wxTreeEvent_GetKeyCode, 3423).
+-define(wxTreeEvent_GetItem, 3424).
+-define(wxTreeEvent_GetKeyEvent, 3425).
+-define(wxTreeEvent_GetLabel, 3426).
+-define(wxTreeEvent_GetOldItem, 3427).
+-define(wxTreeEvent_GetPoint, 3428).
+-define(wxTreeEvent_IsEditCancelled, 3429).
+-define(wxTreeEvent_SetToolTip, 3430).
+-define(wxNotebookEvent_GetOldSelection, 3431).
+-define(wxNotebookEvent_GetSelection, 3432).
+-define(wxNotebookEvent_SetOldSelection, 3433).
+-define(wxNotebookEvent_SetSelection, 3434).
+-define(wxFileDataObject_new, 3435).
+-define(wxFileDataObject_AddFile, 3436).
+-define(wxFileDataObject_GetFilenames, 3437).
+-define(wxFileDataObject_destroy, 3438).
+-define(wxTextDataObject_new, 3439).
+-define(wxTextDataObject_GetTextLength, 3440).
+-define(wxTextDataObject_GetText, 3441).
+-define(wxTextDataObject_SetText, 3442).
+-define(wxTextDataObject_destroy, 3443).
+-define(wxBitmapDataObject_new_1_1, 3444).
+-define(wxBitmapDataObject_new_1_0, 3445).
+-define(wxBitmapDataObject_GetBitmap, 3446).
+-define(wxBitmapDataObject_SetBitmap, 3447).
+-define(wxBitmapDataObject_destroy, 3448).
+-define(wxClipboard_new, 3450).
+-define(wxClipboard_destruct, 3451).
+-define(wxClipboard_AddData, 3452).
+-define(wxClipboard_Clear, 3453).
+-define(wxClipboard_Close, 3454).
+-define(wxClipboard_Flush, 3455).
+-define(wxClipboard_GetData, 3456).
+-define(wxClipboard_IsOpened, 3457).
+-define(wxClipboard_Open, 3458).
+-define(wxClipboard_SetData, 3459).
+-define(wxClipboard_UsePrimarySelection, 3461).
+-define(wxClipboard_IsSupported, 3462).
+-define(wxClipboard_Get, 3463).
+-define(wxSpinEvent_GetPosition, 3464).
+-define(wxSpinEvent_SetPosition, 3465).
+-define(wxSplitterWindow_new_0, 3466).
+-define(wxSplitterWindow_new_2, 3467).
+-define(wxSplitterWindow_destruct, 3468).
+-define(wxSplitterWindow_Create, 3469).
+-define(wxSplitterWindow_GetMinimumPaneSize, 3470).
+-define(wxSplitterWindow_GetSashGravity, 3471).
+-define(wxSplitterWindow_GetSashPosition, 3472).
+-define(wxSplitterWindow_GetSplitMode, 3473).
+-define(wxSplitterWindow_GetWindow1, 3474).
+-define(wxSplitterWindow_GetWindow2, 3475).
+-define(wxSplitterWindow_Initialize, 3476).
+-define(wxSplitterWindow_IsSplit, 3477).
+-define(wxSplitterWindow_ReplaceWindow, 3478).
+-define(wxSplitterWindow_SetSashGravity, 3479).
+-define(wxSplitterWindow_SetSashPosition, 3480).
+-define(wxSplitterWindow_SetSashSize, 3481).
+-define(wxSplitterWindow_SetMinimumPaneSize, 3482).
+-define(wxSplitterWindow_SetSplitMode, 3483).
+-define(wxSplitterWindow_SplitHorizontally, 3484).
+-define(wxSplitterWindow_SplitVertically, 3485).
+-define(wxSplitterWindow_Unsplit, 3486).
+-define(wxSplitterWindow_UpdateSize, 3487).
+-define(wxSplitterEvent_GetSashPosition, 3488).
+-define(wxSplitterEvent_GetX, 3489).
+-define(wxSplitterEvent_GetY, 3490).
+-define(wxSplitterEvent_GetWindowBeingRemoved, 3491).
+-define(wxSplitterEvent_SetSashPosition, 3492).
+-define(wxHtmlWindow_new_0, 3493).
+-define(wxHtmlWindow_new_2, 3494).
+-define(wxHtmlWindow_AppendToPage, 3495).
+-define(wxHtmlWindow_GetOpenedAnchor, 3496).
+-define(wxHtmlWindow_GetOpenedPage, 3497).
+-define(wxHtmlWindow_GetOpenedPageTitle, 3498).
+-define(wxHtmlWindow_GetRelatedFrame, 3499).
+-define(wxHtmlWindow_HistoryBack, 3500).
+-define(wxHtmlWindow_HistoryCanBack, 3501).
+-define(wxHtmlWindow_HistoryCanForward, 3502).
+-define(wxHtmlWindow_HistoryClear, 3503).
+-define(wxHtmlWindow_HistoryForward, 3504).
+-define(wxHtmlWindow_LoadFile, 3505).
+-define(wxHtmlWindow_LoadPage, 3506).
+-define(wxHtmlWindow_SelectAll, 3507).
+-define(wxHtmlWindow_SelectionToText, 3508).
+-define(wxHtmlWindow_SelectLine, 3509).
+-define(wxHtmlWindow_SelectWord, 3510).
+-define(wxHtmlWindow_SetBorders, 3511).
+-define(wxHtmlWindow_SetFonts, 3512).
+-define(wxHtmlWindow_SetPage, 3513).
+-define(wxHtmlWindow_SetRelatedFrame, 3514).
+-define(wxHtmlWindow_SetRelatedStatusBar, 3515).
+-define(wxHtmlWindow_ToText, 3516).
+-define(wxHtmlWindow_destroy, 3517).
+-define(wxHtmlLinkEvent_GetLinkInfo, 3518).
+-define(wxSystemSettings_GetColour, 3519).
+-define(wxSystemSettings_GetFont, 3520).
+-define(wxSystemSettings_GetMetric, 3521).
+-define(wxSystemSettings_GetScreenType, 3522).
+-define(wxSystemOptions_GetOption, 3523).
+-define(wxSystemOptions_GetOptionInt, 3524).
+-define(wxSystemOptions_HasOption, 3525).
+-define(wxSystemOptions_IsFalse, 3526).
+-define(wxSystemOptions_SetOption_2_1, 3527).
+-define(wxSystemOptions_SetOption_2_0, 3528).
+-define(wxAuiNotebookEvent_SetSelection, 3529).
+-define(wxAuiNotebookEvent_GetSelection, 3530).
+-define(wxAuiNotebookEvent_SetOldSelection, 3531).
+-define(wxAuiNotebookEvent_GetOldSelection, 3532).
+-define(wxAuiNotebookEvent_SetDragSource, 3533).
+-define(wxAuiNotebookEvent_GetDragSource, 3534).
+-define(wxAuiManagerEvent_SetManager, 3535).
+-define(wxAuiManagerEvent_GetManager, 3536).
+-define(wxAuiManagerEvent_SetPane, 3537).
+-define(wxAuiManagerEvent_GetPane, 3538).
+-define(wxAuiManagerEvent_SetButton, 3539).
+-define(wxAuiManagerEvent_GetButton, 3540).
+-define(wxAuiManagerEvent_SetDC, 3541).
+-define(wxAuiManagerEvent_GetDC, 3542).
+-define(wxAuiManagerEvent_Veto, 3543).
+-define(wxAuiManagerEvent_GetVeto, 3544).
+-define(wxAuiManagerEvent_SetCanVeto, 3545).
+-define(wxAuiManagerEvent_CanVeto, 3546).
+-define(wxLogNull_new, 3547).
+-define(wxLogNull_destroy, 3548).
+-define(wxTaskBarIcon_new, 3549).
+-define(wxTaskBarIcon_destruct, 3550).
+-define(wxTaskBarIcon_PopupMenu, 3551).
+-define(wxTaskBarIcon_RemoveIcon, 3552).
+-define(wxTaskBarIcon_SetIcon, 3553).
+-define(wxLocale_new_0, 3554).
+-define(wxLocale_new_2, 3556).
+-define(wxLocale_destruct, 3557).
+-define(wxLocale_Init, 3559).
+-define(wxLocale_AddCatalog_1, 3560).
+-define(wxLocale_AddCatalog_3, 3561).
+-define(wxLocale_AddCatalogLookupPathPrefix, 3562).
+-define(wxLocale_GetCanonicalName, 3563).
+-define(wxLocale_GetLanguage, 3564).
+-define(wxLocale_GetLanguageName, 3565).
+-define(wxLocale_GetLocale, 3566).
+-define(wxLocale_GetName, 3567).
+-define(wxLocale_GetString_2, 3568).
+-define(wxLocale_GetString_4, 3569).
+-define(wxLocale_GetHeaderValue, 3570).
+-define(wxLocale_GetSysName, 3571).
+-define(wxLocale_GetSystemEncoding, 3572).
+-define(wxLocale_GetSystemEncodingName, 3573).
+-define(wxLocale_GetSystemLanguage, 3574).
+-define(wxLocale_IsLoaded, 3575).
+-define(wxLocale_IsOk, 3576).
+-define(wxActivateEvent_GetActive, 3577).
+-define(wxPopupWindow_new_2, 3579).
+-define(wxPopupWindow_new_0, 3580).
+-define(wxPopupWindow_destruct, 3582).
+-define(wxPopupWindow_Create, 3583).
+-define(wxPopupWindow_Position, 3584).
+-define(wxPopupTransientWindow_new_0, 3585).
+-define(wxPopupTransientWindow_new_2, 3586).
+-define(wxPopupTransientWindow_destruct, 3587).
+-define(wxPopupTransientWindow_Popup, 3588).
+-define(wxPopupTransientWindow_Dismiss, 3589).
+-define(wxOverlay_new, 3590).
+-define(wxOverlay_destruct, 3591).
+-define(wxOverlay_Reset, 3592).
+-define(wxDCOverlay_new_6, 3593).
+-define(wxDCOverlay_new_2, 3594).
+-define(wxDCOverlay_destruct, 3595).
+-define(wxDCOverlay_Clear, 3596).
+-define(wxDropFilesEvent_GetPosition, 3597).
+-define(wxDropFilesEvent_GetNumberOfFiles, 3598).
+-define(wxDropFilesEvent_GetFiles, 3599).
diff --git a/lib/wx/src/wx_object.erl b/lib/wx/src/wx_object.erl
index 40ee308358..40170b6eb1 100644
--- a/lib/wx/src/wx_object.erl
+++ b/lib/wx/src/wx_object.erl
@@ -55,7 +55,7 @@
%% When stop is returned in one of the functions above with Reason =
%% normal | shutdown | Term, terminate(State) is called. It lets the
%% user module clean up, it is always called when server terminates or
-%% when wxObject() in the driver is deleted. If the Parent process
+%% when wx_object() in the driver is deleted. If the Parent process
%% terminates the Module:terminate/2 function is called. <br/>
%% terminate(Reason, State)
%%
@@ -171,58 +171,59 @@
%% -----------------------------------------------------------------
-%% @spec (Mod, Args, Options) -> wxWindow:wxWindow()
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start(Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start(Mod, Args, Options) ->
gen_response(gen:start(?MODULE, nolink, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-
-%% @spec (Name, Mod, Args, Options) -> wxWindow:wxWindow()
-%% Name = {local, atom()}
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
+
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start(Name, Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Name::{local, atom()},
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start(Name, Mod, Args, Options) ->
gen_response(gen:start(?MODULE, nolink, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-%% @spec (Mod, Args, Options) -> wxWindow:wxWindow()
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start_link(Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start_link(Mod, Args, Options) ->
gen_response(gen:start(?MODULE, link, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-%% @spec (Name, Mod, Args, Options) -> wxWindow:wxWindow()
-%% Name = {local, atom()}
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start_link(Name, Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Name::{local, atom()},
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start_link(Name, Mod, Args, Options) ->
gen_response(gen:start(?MODULE, link, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-
+
gen_response({ok, Pid}) ->
receive {ack, Pid, Ref = #wx_ref{}} -> Ref end;
gen_response(Reply) ->
Reply.
-%% @spec (Ref::wxObject()|atom()|pid()) -> ok
%% @doc Stops a generic wx_object server with reason 'normal'.
%% Invokes terminate(Reason,State) in the server. The call waits until
%% the process is terminated. If the process does not exist, an
%% exception is raised.
+-spec stop(Obj) -> ok when
+ Obj::wx:wx_object()|atom()|pid().
stop(Ref = #wx_ref{state=Pid}) when is_pid(Pid) ->
try
gen:stop(Pid)
@@ -236,11 +237,14 @@ stop(Name) when is_atom(Name) orelse is_pid(Name) ->
erlang:error({ExitReason, {?MODULE, stop, [Name]}})
end.
-%% @spec (Ref::wxObject()|atom()|pid(), Reason::term(), Timeout::timeout()) -> ok
%% @doc Stops a generic wx_object server with the given Reason.
%% Invokes terminate(Reason,State) in the server. The call waits until
%% the process is terminated. If the call times out, or if the process
%% does not exist, an exception is raised.
+-spec stop(Obj, Reason, Timeout) -> ok when
+ Obj::wx:wx_object()|atom()|pid(),
+ Reason::term(),
+ Timeout::timeout().
stop(Ref = #wx_ref{state=Pid}, Reason, Timeout) when is_pid(Pid) ->
try
gen:stop(Pid, Reason, Timeout)
@@ -254,12 +258,14 @@ stop(Name, Reason, Timeout) when is_atom(Name) orelse is_pid(Name) ->
erlang:error({ExitReason, {?MODULE, stop, [Name, Reason, Timeout]}})
end.
-%% @spec (Ref::wxObject()|atom()|pid(), Request::term()) -> term()
%% @doc Make a call to a wx_object server.
%% The call waits until it gets a result.
%% Invokes handle_call(Request, From, State) in the server
+-spec call(Obj, Request) -> term() when
+ Obj::wx:wx_object()|atom()|pid(),
+ Request::term().
call(Ref = #wx_ref{state=Pid}, Request) when is_pid(Pid) ->
- try
+ try
{ok,Res} = gen:call(Pid, '$gen_call', Request, infinity),
Res
catch _:Reason ->
@@ -272,10 +278,13 @@ call(Name, Request) when is_atom(Name) orelse is_pid(Name) ->
catch _:Reason ->
erlang:error({Reason, {?MODULE, call, [Name, Request]}})
end.
-
-%% @spec (Ref::wxObject()|atom()|pid(), Request::term(), Timeout::integer()) -> term()
+
%% @doc Make a call to a wx_object server with a timeout.
%% Invokes handle_call(Request, From, State) in server
+-spec call(Obj, Request, Timeout) -> term() when
+ Obj::wx:wx_object()|atom()|pid(),
+ Request::term(),
+ Timeout::integer().
call(Ref = #wx_ref{state=Pid}, Request, Timeout) when is_pid(Pid) ->
try
{ok,Res} = gen:call(Pid, '$gen_call', Request, Timeout),
@@ -291,10 +300,11 @@ call(Name, Request, Timeout) when is_atom(Name) orelse is_pid(Name) ->
erlang:error({Reason, {?MODULE, call, [Name, Request, Timeout]}})
end.
-%% @spec (Ref::wxObject()|atom()|pid(), Request::term()) -> ok
%% @doc Make a cast to a wx_object server.
%% Invokes handle_cast(Request, State) in the server
-
+-spec cast(Obj, Request) -> ok when
+ Obj::wx:wx_object()|atom()|pid(),
+ Request::term().
cast(#wx_ref{state=Pid}, Request) when is_pid(Pid) ->
Pid ! {'$gen_cast',Request},
ok;
@@ -302,21 +312,23 @@ cast(Name, Request) when is_atom(Name) orelse is_pid(Name) ->
Name ! {'$gen_cast',Request},
ok.
-%% @spec (Ref::wxObject()) -> pid()
%% @doc Get the pid of the object handle.
+-spec get_pid(Obj) -> pid() when
+ Obj::wx:wx_object()|atom()|pid().
get_pid(#wx_ref{state=Pid}) when is_pid(Pid) ->
Pid.
-%% @spec (Ref::wxObject(), pid()) -> wxObject()
%% @doc Sets the controlling process of the object handle.
+-spec set_pid(Obj, pid()) -> wx:wx_object() when
+ Obj::wx:wx_object()|atom()|pid().
set_pid(#wx_ref{}=R, Pid) when is_pid(Pid) ->
R#wx_ref{state=Pid}.
%% -----------------------------------------------------------------
%% Send a reply to the client.
%% -----------------------------------------------------------------
-%% @spec (From::tuple(), Reply::term()) -> pid()
%% @doc Get the pid of the object handle.
+-spec reply({pid(), Tag::term()}, Reply::term()) -> pid().
reply({To, Tag}, Reply) ->
catch To ! {Tag, Reply}.
diff --git a/lib/wx/src/wxe.hrl b/lib/wx/src/wxe.hrl
index da65cb939d..0f42d7e82e 100644
--- a/lib/wx/src/wxe.hrl
+++ b/lib/wx/src/wxe.hrl
@@ -44,6 +44,8 @@
-define(I, signed-native).
-define(F, float-native).
+-define(is_chardata(String), (is_list(String) orelse is_binary(String))).
+
-define(WXE_IDENTIFIER, wx_env).
-define(BATCH_BEGIN, 0).
-define(BATCH_END, 1).
diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl
index 643a0df6a3..3de9209fae 100644
--- a/lib/wx/test/wx_opengl_SUITE.erl
+++ b/lib/wx/test/wx_opengl_SUITE.erl
@@ -111,6 +111,8 @@ canvas(Config) ->
?m(false, wx:is_null(wxGLCanvas:getContext(Canvas))),
?m({'EXIT', {{error, no_gl_context,_},_}}, gl:getString(?GL_VENDOR)),
+ gl:viewport(0,0,50,50), %% Show cause an error report
+
?m(ok, wxGLCanvas:setCurrent(Canvas)),
io:format("Vendor: ~s~n", [gl:getString(?GL_VENDOR)]),
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index de4e5e1935..cfa256fb12 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.7
+WX_VSN = 1.8
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index 0abcb87998..0c89311579 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -32,6 +32,97 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> A couple of bugs are fixed in the sax parser
+ (xmerl_sax_parser). </p> <list> <item>The continuation
+ function was not called correctly when the XML directive
+ was fragmented. </item> <item>When the event callback
+ modules (xmerl_sax_old_dom and xmerl_sax_simple) got an
+ endDocument event at certain conditions the parser
+ crashed.</item> <item>Replaced internal ets table with
+ map to avoid table leakage.</item> </list>
+ <p>
+ Own Id: OTP-14430</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The namespace_conformant option in xmerl_scan did not
+ work when parsing documents without explicit XML
+ namespace declaration.</p>
+ <p>
+ Own Id: OTP-14139</p>
+ </item>
+ <item>
+ <p> Fix a "well-formedness" bug in the XML Sax parser so
+ it returns an error if there are something more in the
+ file after the matching document. If one using the
+ xmerl_sax_parser:stream() a rest is allowed which then
+ can be sent to a new call of xmerl_sax_parser:stream() to
+ parse next document. </p> <p> This is done to be
+ compliant with XML conformance tests. </p>
+ <p>
+ Own Id: OTP-14211</p>
+ </item>
+ <item>
+ <p> Fixed compiler and dialyzer warnings in the XML SAX
+ parser. </p>
+ <p>
+ Own Id: OTP-14212</p>
+ </item>
+ <item>
+ <p> Change how to interpret end of document in the XML
+ SAX parser to comply with Tim Brays comment on the
+ standard. This makes it possible to handle more than one
+ doc on a stream, the standard makes it impossible to know
+ when the document is ended without waiting for the next
+ document (and not always even that). </p> <p> Tim Brays
+ comment: </p> <p> Trailing "Misc"<br/> The fact that
+ you're allowed some trailing junk after the root element,
+ I decided (but unfortunately too late) is a real design
+ error in XML. If I'm writing a network client, I'm
+ probably going to close the link as soon as a I see the
+ root element end-tag, and not depend on the other end
+ closing it down properly.<br/> Furthermore, if I want to
+ send a succession of XML documents over a network link,
+ if I find a processing instruction after a root element,
+ is it a trailer on the previous document, or part of the
+ prolog of the next? </p>
+ <p>
+ Own Id: OTP-14213</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a number of broken links in the xmerl
+ documentation. </p>
+ <p>
+ Own Id: OTP-13880</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.11</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/xmerl/src/xmerl_eventp.erl b/lib/xmerl/src/xmerl_eventp.erl
index 2cb76abc6e..8d7ea25e24 100644
--- a/lib/xmerl/src/xmerl_eventp.erl
+++ b/lib/xmerl/src/xmerl_eventp.erl
@@ -25,6 +25,90 @@
%% Each contain more elaborate settings of xmerl_scan that makes usage of
%% the customization functions.
%%
+%% @type xmlElement() = #xmlElement{}.
+%%
+%% @type option_list(). <p>Options allow to customize the behaviour of the
+%% scanner.
+%% See also <a href="xmerl_examples.html">tutorial</a> on customization
+%% functions.
+%% </p>
+%% <p>
+%% Possible options are:
+%% </p>
+%% <dl>
+%% <dt><code>{acc_fun, Fun}</code></dt>
+%% <dd>Call back function to accumulate contents of entity.</dd>
+%% <dt><code>{continuation_fun, Fun} |
+%% {continuation_fun, Fun, ContinuationState}</code></dt>
+%% <dd>Call back function to decide what to do if the scanner runs into EOF
+%% before the document is complete.</dd>
+%% <dt><code>{event_fun, Fun} |
+%% {event_fun, Fun, EventState}</code></dt>
+%% <dd>Call back function to handle scanner events.</dd>
+%% <dt><code>{fetch_fun, Fun} |
+%% {fetch_fun, Fun, FetchState}</code></dt>
+%% <dd>Call back function to fetch an external resource.</dd>
+%% <dt><code>{hook_fun, Fun} |
+%% {hook_fun, Fun, HookState}</code></dt>
+%% <dd>Call back function to process the document entities once
+%% identified.</dd>
+%% <dt><code>{close_fun, Fun}</code></dt>
+%% <dd>Called when document has been completely parsed.</dd>
+%% <dt><code>{rules, ReadFun, WriteFun, RulesState} |
+%% {rules, Rules}</code></dt>
+%% <dd>Handles storing of scanner information when parsing.</dd>
+%% <dt><code>{user_state, UserState}</code></dt>
+%% <dd>Global state variable accessible from all customization functions</dd>
+%%
+%% <dt><code>{fetch_path, PathList}</code></dt>
+%% <dd>PathList is a list of
+%% directories to search when fetching files. If the file in question
+%% is not in the fetch_path, the URI will be used as a file
+%% name.</dd>
+%% <dt><code>{space, Flag}</code></dt>
+%% <dd>'preserve' (default) to preserve spaces, 'normalize' to
+%% accumulate consecutive whitespace and replace it with one space.</dd>
+%% <dt><code>{line, Line}</code></dt>
+%% <dd>To specify starting line for scanning in document which contains
+%% fragments of XML.</dd>
+%% <dt><code>{namespace_conformant, Flag}</code></dt>
+%% <dd>Controls whether to behave as a namespace conformant XML parser,
+%% 'false' (default) to not otherwise 'true'.</dd>
+%% <dt><code>{validation, Flag}</code></dt>
+%% <dd>Controls whether to process as a validating XML parser:
+%% 'off' (default) no validation, or validation 'dtd' by DTD or 'schema'
+%% by XML Schema. 'false' and 'true' options are obsolete
+%% (i.e. they may be removed in a future release), if used 'false'
+%% equals 'off' and 'true' equals 'dtd'.</dd>
+%% <dt><code>{schemaLocation, [{Namespace,Link}|...]}</code></dt>
+%% <dd>Tells explicitly which XML Schema documents to use to validate
+%% the XML document. Used together with the
+%% <code>{validation,schema}</code> option.</dd>
+%% <dt><code>{quiet, Flag}</code></dt>
+%% <dd>Set to 'true' if xmerl should behave quietly and not output any
+%% information to standard output (default 'false').</dd>
+%% <dt><code>{doctype_DTD, DTD}</code></dt>
+%% <dd>Allows to specify DTD name when it isn't available in the XML
+%% document. This option has effect only together with
+%% <code>{validation,'dtd'</code> option.</dd>
+%% <dt><code>{xmlbase, Dir}</code></dt>
+%% <dd>XML Base directory. If using string/1 default is current directory.
+%% If using file/1 default is directory of given file.</dd>
+%% <dt><code>{encoding, Enc}</code></dt>
+%% <dd>Set default character set used (default UTF-8).
+%% This character set is used only if not explicitly given by the XML
+%% declaration. </dd>
+%% <dt><code>{document, Flag}</code></dt>
+%% <dd>Set to 'true' if xmerl should return a complete XML document
+%% as an xmlDocument record (default 'false').</dd>
+%% <dt><code>{comments, Flag}</code></dt>
+%% <dd>Set to 'false' if xmerl should skip comments otherwise they will
+%% be returned as xmlComment records (default 'true').</dd>
+%% <dt><code>{default_attrs, Flag}</code></dt>
+%% <dd>Set to 'true' if xmerl should add to elements missing attributes
+%% with a defined default value (default 'false').</dd>
+%% </dl>
+%%
-module(xmerl_eventp).
-vsn('0.19').
-date('03-09-17').
diff --git a/lib/xmerl/src/xmerl_sax_old_dom.erl b/lib/xmerl/src/xmerl_sax_old_dom.erl
index fefcf03fce..411121370f 100644
--- a/lib/xmerl/src/xmerl_sax_old_dom.erl
+++ b/lib/xmerl/src/xmerl_sax_old_dom.erl
@@ -127,9 +127,10 @@ build_dom(endDocument,
State#xmerl_sax_old_dom_state{dom=[Decl, Current#xmlElement{
content=lists:reverse(C)
}]};
- _ ->
- %%?dbg("~p\n", [D]),
- ?error("we're not at end the document when endDocument event is encountered.")
+ _ ->
+ %% endDocument is also sent by the parser when a fault occur to tell
+ %% the event receiver that no more input will be sent
+ State
end;
%% Element
diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl
index 318a0cf7f4..e383c4c349 100644
--- a/lib/xmerl/src/xmerl_sax_parser.erl
+++ b/lib/xmerl/src/xmerl_sax_parser.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
%% External exports
%%----------------------------------------------------------------------
-export([file/2,
+ stream/3,
stream/2]).
%%----------------------------------------------------------------------
@@ -63,7 +64,7 @@
%% Description: Parse file containing an XML document.
%%----------------------------------------------------------------------
file(Name,Options) ->
- case file:open(Name, [raw, read,binary]) of
+ case file:open(Name, [raw, read_ahead, read,binary]) of
{error, Reason} ->
{error,{Name, file:format_error(Reason)}};
{ok, FD} ->
@@ -72,11 +73,12 @@ file(Name,Options) ->
File = filename:basename(Name),
ContinuationFun = fun default_continuation_cb/1,
Res = stream(<<>>,
- [{continuation_fun, ContinuationFun},
- {continuation_state, FD},
- {current_location, CL},
- {entity, File}
- |Options]),
+ [{continuation_fun, ContinuationFun},
+ {continuation_state, FD},
+ {current_location, CL},
+ {entity, File}
+ |Options],
+ file),
ok = file:close(FD),
Res
end.
@@ -92,19 +94,22 @@ file(Name,Options) ->
%% EventState = term()
%% Description: Parse a stream containing an XML document.
%%----------------------------------------------------------------------
-stream(Xml, Options) when is_list(Xml), is_list(Options) ->
+stream(Xml, Options) ->
+ stream(Xml, Options, stream).
+
+stream(Xml, Options, InputType) when is_list(Xml), is_list(Options) ->
State = parse_options(Options, initial_state()),
- case State#xmerl_sax_parser_state.file_type of
+ case State#xmerl_sax_parser_state.file_type of
dtd ->
xmerl_sax_parser_list:parse_dtd(Xml,
State#xmerl_sax_parser_state{encoding = list,
- input_type = stream});
+ input_type = InputType});
normal ->
xmerl_sax_parser_list:parse(Xml,
State#xmerl_sax_parser_state{encoding = list,
- input_type = stream})
+ input_type = InputType})
end;
-stream(Xml, Options) when is_binary(Xml), is_list(Options) ->
+stream(Xml, Options, InputType) when is_binary(Xml), is_list(Options) ->
case parse_options(Options, initial_state()) of
{error, Reason} -> {error, Reason};
State ->
@@ -115,21 +120,22 @@ stream(Xml, Options) when is_binary(Xml), is_list(Options) ->
normal ->
parse
end,
- case detect_charset(Xml, State) of
- {error, Reason} -> {fatal_error,
- {
- State#xmerl_sax_parser_state.current_location,
- State#xmerl_sax_parser_state.entity,
- 1
- },
- Reason,
- [],
- State#xmerl_sax_parser_state.event_state};
- {Xml1, State1} ->
- parse_binary(Xml1,
- State1#xmerl_sax_parser_state{input_type = stream},
- ParseFunction)
- end
+ try
+ {Xml1, State1} = detect_charset(Xml, State),
+ parse_binary(Xml1,
+ State1#xmerl_sax_parser_state{input_type = InputType},
+ ParseFunction)
+ catch
+ throw:{fatal_error, {State2, Reason}} ->
+ {fatal_error,
+ {
+ State2#xmerl_sax_parser_state.current_location,
+ State2#xmerl_sax_parser_state.entity,
+ 1
+ },
+ Reason, [],
+ State2#xmerl_sax_parser_state.event_state}
+ end
end.
%%----------------------------------------------------------------------
@@ -151,8 +157,8 @@ parse_binary(Xml, #xmerl_sax_parser_state{encoding={utf16,big}}=State, F) ->
xmerl_sax_parser_utf16be:F(Xml, State);
parse_binary(Xml, #xmerl_sax_parser_state{encoding=latin1}=State, F) ->
xmerl_sax_parser_latin1:F(Xml, State);
-parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, _) ->
- {error, lists:flatten(io_lib:format("Charcter set ~p not supported", [Enc]))}.
+parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, State) ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Charcter set ~p not supported", [Enc]))).
%%----------------------------------------------------------------------
%% Function: initial_state/0
@@ -206,8 +212,7 @@ parse_options([{entity, Entity} |Options], State) ->
parse_options([skip_external_dtd |Options], State) ->
parse_options(Options, State#xmerl_sax_parser_state{skip_external_dtd = true});
parse_options([O |_], _State) ->
- {error,
- lists:flatten(io_lib:format("Option: ~p not supported", [O]))}.
+ {error, lists:flatten(io_lib:format("Option: ~p not supported", [O]))}.
check_encoding_option(E) when E==utf8; E=={utf16,little}; E=={utf16,big};
@@ -225,16 +230,10 @@ check_encoding_option(E) ->
%% Output: {utf8|utf16le|utf16be|iso8859, Xml, State}
%% Description: Detects which character set is used in a binary stream.
%%----------------------------------------------------------------------
-detect_charset(<<>>, #xmerl_sax_parser_state{continuation_fun = undefined} = _) ->
- throw({error, "Can't detect character encoding due to no indata"});
-detect_charset(<<>>, #xmerl_sax_parser_state{continuation_fun = CFun,
- continuation_state = CState} = State) ->
- case CFun(CState) of
- {<<>>, _} ->
- throw({error, "Can't detect character encoding due to lack of indata"});
- {NewBytes, NewContState} ->
- detect_charset(NewBytes, State#xmerl_sax_parser_state{continuation_state = NewContState})
- end;
+detect_charset(<<>>, #xmerl_sax_parser_state{continuation_fun = undefined} = State) ->
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+detect_charset(<<>>, State) ->
+ cf(<<>>, State, fun detect_charset/2);
detect_charset(Bytes, State) ->
case unicode:bom_to_encoding(Bytes) of
{latin1, 0} ->
@@ -244,25 +243,47 @@ detect_charset(Bytes, State) ->
{RealBytes, State#xmerl_sax_parser_state{encoding=Enc}}
end.
+detect_charset_1(<<16#00>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#00, 16#3C>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#00, 16#3C, 16#00>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
detect_charset_1(<<16#00, 16#3C, 16#00, 16#3F, _/binary>> = Xml, State) ->
{Xml, State#xmerl_sax_parser_state{encoding={utf16, big}}};
+detect_charset_1(<<16#3C>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#3C, 16#00>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#3C, 16#00, 16#3F>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
detect_charset_1(<<16#3C, 16#00, 16#3F, 16#00, _/binary>> = Xml, State) ->
{Xml, State#xmerl_sax_parser_state{encoding={utf16, little}}};
-detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml2/binary>> = Xml, State) ->
- case parse_xml_directive(Xml2) of
+detect_charset_1(<<16#3C>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#3C, 16#3F>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#3C, 16#3F, 16#78>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D>> = Xml, State) ->
+ cf(Xml, State, fun detect_charset_1/2);
+detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml2/binary>>, State) ->
+ {Xml3, State1} = read_until_end_of_xml_directive(Xml2, State),
+ case parse_xml_directive(Xml3) of
{error, Reason} ->
- {error, Reason};
+ ?fatal_error(State, Reason);
AttrList ->
case lists:keysearch("encoding", 1, AttrList) of
{value, {_, E}} ->
case convert_encoding(E) of
{error, Reason} ->
- {error, Reason};
+ ?fatal_error(State, Reason);
Enc ->
- {Xml, State#xmerl_sax_parser_state{encoding=Enc}}
+ {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>,
+ State1#xmerl_sax_parser_state{encoding=Enc}}
end;
_ ->
- {Xml, State}
+ {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, State1}
end
end;
detect_charset_1(Xml, State) ->
@@ -372,7 +393,7 @@ parse_value_1(<<C, Rest/binary>>, Stop, Acc) ->
parse_value_1(Rest, Stop, [C |Acc]).
%%======================================================================
-%%Default functions
+%% Default functions
%%======================================================================
%%----------------------------------------------------------------------
%% Function: default_event_cb(Event, LineNo, State) -> Result
@@ -388,7 +409,7 @@ default_event_cb(_Event, _LineNo, State) ->
%%----------------------------------------------------------------------
%% Function: default_continuation_cb(IoDevice) -> Result
%% IoDevice = iodevice()
-%% Output: Result = {[char()], State}
+%% Output: Result = {binary(), IoDevice}
%% Description: Default continuation callback reading blocks.
%%----------------------------------------------------------------------
default_continuation_cb(IoDevice) ->
@@ -398,3 +419,82 @@ default_continuation_cb(IoDevice) ->
{ok, FileBin} ->
{FileBin, IoDevice}
end.
+
+%%----------------------------------------------------------------------
+%% Function: read_until_end_of_xml_directive(Rest, State) -> Result
+%% Rest = binary()
+%% Output: Result = {binary(), State}
+%% Description: Reads a utf8 or latin1 until it finds '?>'
+%%----------------------------------------------------------------------
+read_until_end_of_xml_directive(Rest, State) ->
+ case binary:match(Rest, <<"?>">>) of
+ nomatch ->
+ case cf(Rest, State) of
+ {<<>>, _} ->
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ {NewBytes, NewState} ->
+ read_until_end_of_xml_directive(NewBytes, NewState)
+ end;
+ _ ->
+ {Rest, State}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Function : cf(Rest, State) -> Result
+%% Parameters: Rest = binary()
+%% State = #xmerl_sax_parser_state{}
+%% NextCall = fun()
+%% Result : {Rest, State}
+%% Description: Function that uses provided fun to read another chunk from
+%% input stream and calls the fun in NextCall.
+%%----------------------------------------------------------------------
+cf(_Rest, #xmerl_sax_parser_state{continuation_fun = undefined} = State) ->
+ ?fatal_error(State, "Continuation function undefined");
+cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State) ->
+ Result =
+ try
+ CFun(CState)
+ catch
+ throw:ErrorTerm ->
+ ?fatal_error(State, ErrorTerm);
+ exit:Reason ->
+ ?fatal_error(State, {'EXIT', Reason})
+ end,
+ case Result of
+ {<<>>, _} ->
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ {NewBytes, NewContState} ->
+ {<<Rest/binary, NewBytes/binary>>,
+ State#xmerl_sax_parser_state{continuation_state = NewContState}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Function : cf(Rest, State, NextCall) -> Result
+%% Parameters: Rest = binary()
+%% State = #xmerl_sax_parser_state{}
+%% NextCall = fun()
+%% Result : {Rest, State}
+%% Description: Function that uses provided fun to read another chunk from
+%% input stream and calls the fun in NextCall.
+%%----------------------------------------------------------------------
+cf(_Rest, #xmerl_sax_parser_state{continuation_fun = undefined} = State, _) ->
+ ?fatal_error(State, "Continuation function undefined");
+cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State,
+ NextCall) ->
+ Result =
+ try
+ CFun(CState)
+ catch
+ throw:ErrorTerm ->
+ ?fatal_error(State, ErrorTerm);
+ exit:Reason ->
+ ?fatal_error(State, {'EXIT', Reason})
+ end,
+ case Result of
+ {<<>>, _} ->
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ {NewBytes, NewContState} ->
+ NextCall(<<Rest/binary, NewBytes/binary>>,
+ State#xmerl_sax_parser_state{continuation_state = NewContState})
+ end.
diff --git a/lib/xmerl/src/xmerl_sax_parser.hrl b/lib/xmerl/src/xmerl_sax_parser.hrl
index 932ab0cec5..56a3a42e5f 100644
--- a/lib/xmerl/src/xmerl_sax_parser.hrl
+++ b/lib/xmerl/src/xmerl_sax_parser.hrl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -88,14 +88,7 @@
current_location, % Location of the currently parsed XML entity
entity, % Parsed XML entity
skip_external_dtd = false,% If true the external DTD is skipped during parsing
- input_type % Source type: file | stream.
- % This field is a preparation for an fix in R17 of a bug in
- % the conformance against the standard.
- % Today a file which contains two XML documents will be considered
- % well-formed and the second is placed in the rest part of the
- % return tuple, according to the conformance tests this should fail.
- % In the future this will fail if xmerl_sax_aprser:file/2 is used but
- % left to the user in the xmerl_sax_aprser:stream/2 case.
+ input_type % Source type: file | stream
}).
diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
index 4d75805b9b..1dca9608cb 100644
--- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
@@ -1,7 +1,7 @@
%%-*-erlang-*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,29 +64,42 @@
%% Description: Parsing XML from input stream.
%%----------------------------------------------------------------------
parse(Xml, State) ->
- RefTable = ets:new(xmerl_sax_entity_refs, [private]),
-
- State1 = event_callback(startDocument, State),
-
- case catch parse_document(Xml, State1#xmerl_sax_parser_state{ref_table=RefTable}) of
- {ok, Rest, State2} ->
- State3 = event_callback(endDocument, State2),
- ets:delete(RefTable),
- {ok, State3#xmerl_sax_parser_state.event_state, Rest};
- {fatal_error, {State2, Reason}} ->
- State3 = event_callback(endDocument, State2),
- ets:delete(RefTable),
- format_error(fatal_error, State3, Reason);
- {event_receiver_error, State2, {Tag, Reason}} ->
- State3 = event_callback(endDocument, State2),
- ets:delete(RefTable),
- format_error(Tag, State3, Reason);
- Other ->
- _State2 = event_callback(endDocument, State1),
- ets:delete(RefTable),
- throw(Other)
+ RefTable = maps:new(),
+
+ try
+ State1 = event_callback(startDocument, State),
+ Result = parse_document(Xml, State1#xmerl_sax_parser_state{ref_table=RefTable}),
+ handle_end_document(Result)
+ catch
+ throw:Exception ->
+ handle_end_document(Exception);
+ _:OtherError ->
+ handle_end_document({other, OtherError, State})
end.
+ % case catch parse_document(Xml, State1#xmerl_sax_parser_state{ref_table=RefTable}) of
+ % {ok, Rest, State2} ->
+ % State3 = event_callback(endDocument, State2),
+ % case check_if_rest_ok(State3#xmerl_sax_parser_state.input_type, Rest) of
+ % true ->
+ % {ok, State3#xmerl_sax_parser_state.event_state, Rest};
+ % false ->
+ % format_error(fatal_error, State3, "Input found after legal document")
+ % end;
+ % {fatal_error, {State2, Reason}} ->
+ % State3 = event_callback(endDocument, State2),
+ % format_error(fatal_error, State3, Reason);
+ % {event_receiver_error, State2, {Tag, Reason}} ->
+ % State3 = event_callback(endDocument, State2),
+ % format_error(Tag, State3, Reason);
+ % {endDocument, Rest, State2} ->
+ % State3 = event_callback(endDocument, State2),
+ % {ok, State3#xmerl_sax_parser_state.event_state, Rest};
+ % Other ->
+ % _State2 = event_callback(endDocument, State1),
+ % {fatal_error, Other}
+ % end.
+
%%----------------------------------------------------------------------
%% Function: parse_dtd(Xml, State) -> Result
%% Input: Xml = string() | binary()
@@ -96,38 +109,120 @@ parse(Xml, State) ->
%% Description: Parsing XML DTD from input stream.
%%----------------------------------------------------------------------
parse_dtd(Xml, State) ->
- RefTable = ets:new(xmerl_sax_entity_refs, [private]),
-
- State1 = event_callback(startDocument, State),
-
- case catch parse_external_entity_1(Xml, State1#xmerl_sax_parser_state{ref_table=RefTable}) of
- {fatal_error, {State2, Reason}} ->
- State3 = event_callback(endDocument, State2),
- ets:delete(RefTable),
- format_error(fatal_error, State3, Reason);
- {event_receiver_error, State2, {Tag, Reason}} ->
- State3 = event_callback(endDocument, State2),
- format_error(Tag, State3, Reason);
- {Rest, State2} when is_record(State2, xmerl_sax_parser_state) ->
- State3 = event_callback(endDocument, State2),
- ets:delete(RefTable),
- {ok, State3#xmerl_sax_parser_state.event_state, Rest};
- {endDocument, Rest, State2} when is_record(State2, xmerl_sax_parser_state) ->
- State3 = event_callback(endDocument, State2),
- ets:delete(RefTable),
- {ok, State3#xmerl_sax_parser_state.event_state, Rest};
- Other ->
- _State2 = event_callback(endDocument, State1),
- ets:delete(RefTable),
- throw(Other)
+ RefTable = maps:new(),
+
+ try
+ State1 = event_callback(startDocument, State),
+ Result = parse_external_entity_1(Xml, State1#xmerl_sax_parser_state{ref_table=RefTable}),
+ handle_end_document(Result)
+ catch
+ throw:Exception ->
+ handle_end_document(Exception);
+ _:OtherError ->
+ handle_end_document({other, OtherError, State})
end.
+ % case catch parse_external_entity_1(Xml, State1#xmerl_sax_parser_state{ref_table=RefTable}) of
+ % {fatal_error, {State2, Reason}} ->
+ % State3 = event_callback(endDocument, State2),
+ % format_error(fatal_error, State3, Reason);
+ % {event_receiver_error, State2, {Tag, Reason}} ->
+ % State3 = event_callback(endDocument, State2),
+ % format_error(Tag, State3, Reason);
+ % {Rest, State2} when is_record(State2, xmerl_sax_parser_state) ->
+ % State3 = event_callback(endDocument, State2),
+ % {ok, State3#xmerl_sax_parser_state.event_state, Rest};
+ % {endDocument, Rest, State2} when is_record(State2, xmerl_sax_parser_state) ->
+ % State3 = event_callback(endDocument, State2),
+ % {ok, State3#xmerl_sax_parser_state.event_state, Rest};
+ % Other ->
+ % _State2 = event_callback(endDocument, State1),
+ % {fatal_error, Other}
+ % end.
+
+
%%======================================================================
%% Internal functions
%%======================================================================
%%----------------------------------------------------------------------
+%% Function: handle_end_document(ParserResult) -> Result
+%% Input: ParseResult = term()
+%% Output: Result = {ok, Rest, EventState} |
+%% EventState = term()
+%% Description: Ends the parsing and formats output
+%%----------------------------------------------------------------------
+handle_end_document({ok, Rest, State}) ->
+ %%ok case from parse
+ try
+ State1 = event_callback(endDocument, State),
+ case check_if_rest_ok(State1#xmerl_sax_parser_state.input_type, Rest) of
+ true ->
+ {ok, State1#xmerl_sax_parser_state.event_state, Rest};
+ false ->
+ format_error(fatal_error, State1, "Input found after legal document")
+ end
+ catch
+ throw:{event_receiver_error, State2, {Tag, Reason}} ->
+ format_error(Tag, State2, Reason);
+ _:Other ->
+ {fatal_error, Other}
+ end;
+handle_end_document({endDocument, Rest, State}) ->
+ %% ok case from parse and parse_dtd
+ try
+ State1 = event_callback(endDocument, State),
+ {ok, State1#xmerl_sax_parser_state.event_state, Rest}
+ catch
+ throw:{event_receiver_error, State2, {Tag, Reason}} ->
+ format_error(Tag, State2, Reason);
+ _:Other ->
+ {fatal_error, Other}
+ end;
+handle_end_document({fatal_error, {State, Reason}}) ->
+ try
+ State1 = event_callback(endDocument, State),
+ format_error(fatal_error, State1, Reason)
+ catch
+ throw:{event_receiver_error, State2, {Tag, Reason}} ->
+ format_error(Tag, State2, Reason);
+ _:Other ->
+ {fatal_error, Other}
+ end;
+handle_end_document({event_receiver_error, State, {Tag, Reason}}) ->
+ try
+ State1 = event_callback(endDocument, State),
+ format_error(Tag, State1, Reason)
+ catch
+ throw:{event_receiver_error, State2, {Tag, Reason}} ->
+ format_error(Tag, State2, Reason);
+ _:Other ->
+ {fatal_error, Other}
+ end;
+handle_end_document({Rest, State}) when is_record(State, xmerl_sax_parser_state) ->
+ %%ok case from parse_dtd
+ try
+ State1 = event_callback(endDocument, State),
+ {ok, State1#xmerl_sax_parser_state.event_state, Rest}
+ catch
+ throw:{event_receiver_error, State2, {Tag, Reason}} ->
+ format_error(Tag, State2, Reason);
+ _:Other ->
+ {fatal_error, Other}
+ end;
+handle_end_document({other, Error, State}) ->
+ try
+ _State1 = event_callback(endDocument, State),
+ {fatal_error, Error}
+ catch
+ throw:{event_receiver_error, State2, {Tag, Reason}} ->
+ format_error(Tag, State2, Reason);
+ _:Other ->
+ {fatal_error, Other}
+ end.
+
+%%----------------------------------------------------------------------
%% Function: parse_document(Rest, State) -> Result
%% Input: Rest = string() | binary()
%% State = #xmerl_sax_parser_state{}
@@ -136,10 +231,11 @@ parse_dtd(Xml, State) ->
%% [1] document ::= prolog element Misc*
%%----------------------------------------------------------------------
parse_document(Rest, State) when is_record(State, xmerl_sax_parser_state) ->
- {Rest1, State1} = parse_xml_decl(Rest, State),
+ {Rest1, State1} = parse_byte_order_mark(Rest, State),
{Rest2, State2} = parse_misc(Rest1, State1, true),
{ok, Rest2, State2}.
+?PARSE_BYTE_ORDER_MARK(Bytes, State).
%%----------------------------------------------------------------------
%% Function: parse_xml_decl(Rest, State) -> Result
@@ -150,15 +246,8 @@ parse_document(Rest, State) when is_record(State, xmerl_sax_parser_state) ->
%% [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
%% [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
%%----------------------------------------------------------------------
--dialyzer({[no_fail_call, no_match], parse_xml_decl/2}).
parse_xml_decl(?STRING_EMPTY, State) ->
cf(?STRING_EMPTY, State, fun parse_xml_decl/2);
-parse_xml_decl(?BYTE_ORDER_MARK_1, State) ->
- cf(?BYTE_ORDER_MARK_1, State, fun parse_xml_decl/2);
-parse_xml_decl(?BYTE_ORDER_MARK_2, State) ->
- cf(?BYTE_ORDER_MARK_2, State, fun parse_xml_decl/2);
-parse_xml_decl(?BYTE_ORDER_MARK_REST(Rest), State) ->
- cf(Rest, State, fun parse_xml_decl/2);
parse_xml_decl(?STRING("<") = Bytes, State) ->
cf(Bytes, State, fun parse_xml_decl/2);
parse_xml_decl(?STRING("<?") = Bytes, State) ->
@@ -170,31 +259,19 @@ parse_xml_decl(?STRING("<?xm") = Bytes, State) ->
parse_xml_decl(?STRING("<?xml") = Bytes, State) ->
cf(Bytes, State, fun parse_xml_decl/2);
parse_xml_decl(?STRING_REST("<?xml", Rest1), State) ->
- parse_xml_decl_1(Rest1, State);
-parse_xml_decl(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State) when is_binary(Bytes) ->
- case unicode:characters_to_list(Bytes, Enc) of
- {incomplete, _, _} ->
- cf(Bytes, State, fun parse_xml_decl/2);
- {error, _Encoded, _Rest} ->
- ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])));
- _ ->
- parse_prolog(Bytes, State)
- end;
-parse_xml_decl(Bytes, State) ->
- parse_prolog(Bytes, State).
-
+ parse_xml_decl_rest(Rest1, State);
+?PARSE_XML_DECL(Bytes, State).
-parse_xml_decl_1(?STRING_UNBOUND_REST(C, Rest) = Bytes, State) ->
+parse_xml_decl_rest(?STRING_UNBOUND_REST(C, Rest) = Bytes, State) ->
if
?is_whitespace(C) ->
{_XmlAttributes, Rest1, State1} = parse_version_info(Rest, State, []),
- %State2 = event_callback({processingInstruction, "xml", XmlAttributes}, State1),% The XML decl. should not be reported as a PI
parse_prolog(Rest1, State1);
true ->
parse_prolog(?STRING_REST("<?xml", Bytes), State)
end;
-parse_xml_decl_1(Bytes, State) ->
- unicode_incomplete_check([Bytes, State, fun parse_xml_decl_1/2], undefined).
+parse_xml_decl_rest(Bytes, State) ->
+ unicode_incomplete_check([Bytes, State, fun parse_xml_decl_rest/2], undefined).
@@ -216,8 +293,6 @@ parse_prolog(?STRING_REST("<?", Rest), State) ->
parse_prolog(Rest1, State1);
{endDocument, Rest1, State1} ->
parse_prolog(Rest1, State1)
- % IValue = ?TO_INPUT_FORMAT("<?"),
- % {?APPEND_STRING(IValue, Rest1), State1}
end;
parse_prolog(?STRING_REST("<!", Rest), State) ->
parse_prolog_1(Rest, State);
@@ -230,7 +305,6 @@ parse_prolog(Bytes, State) ->
unicode_incomplete_check([Bytes, State, fun parse_prolog/2],
"expecting < or whitespace").
-
parse_prolog_1(?STRING_EMPTY, State) ->
cf(?STRING_EMPTY, State, fun parse_prolog_1/2);
parse_prolog_1(?STRING("D") = Bytes, State) ->
@@ -442,6 +516,16 @@ check_if_new_doc_allowed(stream, []) ->
check_if_new_doc_allowed(_, _) ->
false.
+check_if_rest_ok(file, []) ->
+ true;
+check_if_rest_ok(file, <<>>) ->
+ true;
+check_if_rest_ok(stream, _) ->
+ true;
+check_if_rest_ok(_, _) ->
+ false.
+
+
%%----------------------------------------------------------------------
%% Function: parse_pi_1(Rest, State) -> Result
%% Input: Rest = string() | binary()
@@ -886,11 +970,11 @@ send_end_prefix_mapping_event([{Prefix, _Uri} |Ns], State) ->
parse_eq(?STRING_EMPTY, State) ->
cf(?STRING_EMPTY, State, fun parse_eq/2);
parse_eq(?STRING_REST("=", Rest), State) ->
- {Rest, State};
+ {Rest, State};
parse_eq(?STRING_UNBOUND_REST(C, _) = Bytes, State) when ?is_whitespace(C) ->
- {_WS, Rest, State1} =
- whitespace(Bytes, State, []),
- parse_eq(Rest, State1);
+ {_WS, Rest, State1} =
+ whitespace(Bytes, State, []),
+ parse_eq(Rest, State1);
parse_eq(Bytes, State) ->
unicode_incomplete_check([Bytes, State, fun parse_eq/2],
"expecting = or whitespace").
@@ -908,11 +992,11 @@ parse_eq(Bytes, State) ->
parse_att_value(?STRING_EMPTY, State) ->
cf(?STRING_EMPTY, State, fun parse_att_value/2);
parse_att_value(?STRING_UNBOUND_REST(C, Rest), State) when C == $'; C == $" ->
- parse_att_value(Rest, State, C, []);
+ parse_att_value(Rest, State, C, []);
parse_att_value(?STRING_UNBOUND_REST(C, _) = Bytes, State) when ?is_whitespace(C) ->
- {_WS, Rest, State1} =
- whitespace(Bytes, State, []),
- parse_att_value(Rest, State1);
+ {_WS, Rest, State1} =
+ whitespace(Bytes, State, []),
+ parse_att_value(Rest, State1);
parse_att_value(Bytes, State) ->
unicode_incomplete_check([Bytes, State, fun parse_att_value/2],
"\', \" or whitespace expected").
@@ -1024,16 +1108,21 @@ parse_etag(Bytes, State) ->
unicode_incomplete_check([Bytes, State, fun parse_etag/2],
undefined).
-
parse_etag_1(?STRING_REST(">", Rest),
#xmerl_sax_parser_state{end_tags=[{_ETag, Uri, LocalName, QName, OldNsList, NewNsList}
- |RestOfETags]} = State, _Tag) ->
+ |RestOfETags],
+ input_type=InputType} = State, _Tag) ->
State1 = event_callback({endElement, Uri, LocalName, QName}, State),
State2 = send_end_prefix_mapping_event(NewNsList, State1),
- parse_content(Rest,
- State2#xmerl_sax_parser_state{end_tags=RestOfETags,
- ns = OldNsList},
- [], true);
+ case check_if_new_doc_allowed(InputType, RestOfETags) of
+ true ->
+ throw({endDocument, Rest, State2#xmerl_sax_parser_state{ns = OldNsList}});
+ false ->
+ parse_content(Rest,
+ State2#xmerl_sax_parser_state{end_tags=RestOfETags,
+ ns = OldNsList},
+ [], true)
+ end;
parse_etag_1(?STRING_UNBOUND_REST(_C, _), State, Tag) ->
{P,TN} = Tag,
?fatal_error(State, "Bad EndTag: " ++ P ++ ":" ++ TN);
@@ -1051,21 +1140,26 @@ parse_etag_1(Bytes, State, Tag) ->
%% Description: Parsing the content part of tags
%% [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
%%----------------------------------------------------------------------
-
parse_content(?STRING_EMPTY, State, Acc, IgnorableWS) ->
- case catch cf(?STRING_EMPTY, State, Acc, IgnorableWS, fun parse_content/4) of
- {Rest, State1} when is_record(State1, xmerl_sax_parser_state) ->
- {Rest, State1};
- {fatal_error, {State1, Msg}} ->
- case check_if_document_complete(State1, Msg) of
- true ->
- State2 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State1),
- {?STRING_EMPTY, State2};
- false ->
- ?fatal_error(State1, Msg)
- end;
- Other ->
- throw(Other)
+ case check_if_document_complete(State, "No more bytes") of
+ true ->
+ State1 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State),
+ {?STRING_EMPTY, State1};
+ false ->
+ case catch cf(?STRING_EMPTY, State, Acc, IgnorableWS, fun parse_content/4) of
+ {Rest, State1} when is_record(State1, xmerl_sax_parser_state) ->
+ {Rest, State1};
+ {fatal_error, {State1, Msg}} ->
+ case check_if_document_complete(State1, Msg) of
+ true ->
+ State2 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State1),
+ {?STRING_EMPTY, State2};
+ false ->
+ ?fatal_error(State1, Msg)
+ end;
+ Other ->
+ throw(Other)
+ end
end;
parse_content(?STRING("\r") = Bytes, State, Acc, IgnorableWS) ->
cf(Bytes, State, Acc, IgnorableWS, fun parse_content/4);
@@ -1094,7 +1188,7 @@ parse_content(?STRING_REST("<?", Rest), State, Acc, IgnorableWS) ->
parse_content(?STRING_REST("<!", Rest1) = Rest, #xmerl_sax_parser_state{end_tags = ET} = State, Acc, IgnorableWS) ->
case ET of
[] ->
- {Rest, State}; %%LATH : Skicka ignorable WS ???
+ {Rest, State}; %% Skicka ignorable WS ???
_ ->
State1 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State),
parse_cdata(Rest1, State1)
@@ -1102,7 +1196,7 @@ parse_content(?STRING_REST("<!", Rest1) = Rest, #xmerl_sax_parser_state{end_tags
parse_content(?STRING_REST("<", Rest1) = Rest, #xmerl_sax_parser_state{end_tags = ET} = State, Acc, IgnorableWS) ->
case ET of
[] ->
- {Rest, State}; %%LATH : Skicka ignorable WS ???
+ {Rest, State}; %% Skicka ignorable WS ???
_ ->
State1 = send_character_event(length(Acc), IgnorableWS, lists:reverse(Acc), State),
parse_stag(Rest1, State1)
@@ -1204,7 +1298,6 @@ send_character_event(_, true, String, State) ->
%% Description: Parse whitespaces.
%% [3] S ::= (#x20 | #x9 | #xD | #xA)+
%%----------------------------------------------------------------------
--dialyzer({no_fail_call, whitespace/3}).
whitespace(?STRING_EMPTY, State, Acc) ->
case cf(?STRING_EMPTY, State, Acc, fun whitespace/3) of
{?STRING_EMPTY, State} ->
@@ -1230,16 +1323,7 @@ whitespace(?STRING_REST("\r", Rest), State, Acc) ->
whitespace(Rest, State#xmerl_sax_parser_state{line_no=N+1}, [?lf |Acc]);
whitespace(?STRING_UNBOUND_REST(C, Rest), State, Acc) when ?is_whitespace(C) ->
whitespace(Rest, State, [C|Acc]);
-whitespace(?STRING_UNBOUND_REST(_C, _) = Bytes, State, Acc) ->
- {lists:reverse(Acc), Bytes, State};
-whitespace(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State, Acc) when is_binary(Bytes) ->
- case unicode:characters_to_list(Bytes, Enc) of
- {incomplete, _, _} ->
- cf(Bytes, State, Acc, fun whitespace/3);
- {error, _Encoded, _Rest} ->
- ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])))
- end.
-
+?WHITESPACE(Bytes, State, Acc).
%%----------------------------------------------------------------------
%% Function: parse_reference(Rest, State, HaveToExist) -> Result
@@ -1362,23 +1446,24 @@ parse_pe_reference_1(Bytes, State, Name) ->
"missing ; after reference " ++ Name).
-
%%----------------------------------------------------------------------
-%% Function: insert_reference(Reference, State) -> Result
-%% Parameters: Reference = string()
+%% Function: insert_reference(Name, Ref, State) -> Result
+%% Parameters: Name = string()
+%% Ref = {Type, Value}
+%% Type = atom()
+%% Value = term()
%% State = #xmerl_sax_parser_state{}
%% Result :
%%----------------------------------------------------------------------
-insert_reference({Name, Type, Value}, Table) ->
- case ets:lookup(Table, Name) of
- [{Name, _, _}] ->
- ok;
+insert_reference(Name, Value, #xmerl_sax_parser_state{ref_table = Map} = State) ->
+ case maps:find(Name, Map) of
+ error ->
+ State#xmerl_sax_parser_state{ref_table = maps:put(Name, Value, Map)};
_ ->
- ets:insert(Table, {Name, Type, Value})
+ State
end.
-
%%----------------------------------------------------------------------
%% Function: look_up_reference(Reference, State) -> Result
%% Parameters: Reference = string()
@@ -1396,8 +1481,8 @@ look_up_reference("apos", _, _) ->
look_up_reference("quot", _, _) ->
{internal_general, "quot", "\""};
look_up_reference(Name, HaveToExist, State) ->
- case ets:lookup(State#xmerl_sax_parser_state.ref_table, Name) of
- [{Name, Type, Value}] ->
+ case maps:find(Name, State#xmerl_sax_parser_state.ref_table) of
+ {ok, {Type, Value}} ->
{Type, Name, Value};
_ ->
case HaveToExist of
@@ -1479,7 +1564,7 @@ parse_system_litteral(?STRING_EMPTY, State, Stop, Acc) ->
parse_system_litteral(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) ->
{lists:reverse(Acc), Rest, State};
parse_system_litteral(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) ->
- parse_system_litteral(Rest, State, Stop, [C |Acc]);
+ parse_system_litteral(Rest, State, Stop, [C |Acc]);
parse_system_litteral(Bytes, State, Stop, Acc) ->
unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_system_litteral/4],
undefined).
@@ -1651,9 +1736,11 @@ parse_external_entity(State, _PubId, SysId) ->
end_tags = []},
- EventState = handle_external_entity(ExtRef, State1),
+ {EventState, RefTable} = handle_external_entity(ExtRef, State1),
- NewState = event_callback({endEntity, SysId}, SaveState#xmerl_sax_parser_state{event_state=EventState}),
+ NewState = event_callback({endEntity, SysId},
+ SaveState#xmerl_sax_parser_state{event_state=EventState,
+ ref_table=RefTable}),
NewState#xmerl_sax_parser_state{file_type=normal}.
@@ -1680,7 +1767,8 @@ handle_external_entity({file, FileToOpen}, State) ->
entity=filename:basename(FileToOpen),
input_type=file}),
ok = file:close(FD),
- EntityState#xmerl_sax_parser_state.event_state
+ {EntityState#xmerl_sax_parser_state.event_state,
+ EntityState#xmerl_sax_parser_state.ref_table}
end;
handle_external_entity({http, Url}, State) ->
@@ -1693,14 +1781,16 @@ handle_external_entity({http, Url}, State) ->
++ file:format_error(Reason));
{ok, FD} ->
{?STRING_EMPTY, EntityState} =
- parse_external_entity_1(<<>>,
+ parse_external_entity_byte_order_mark(<<>>,
State#xmerl_sax_parser_state{continuation_state=FD,
current_location=filename:dirname(Url),
entity=filename:basename(Url),
input_type=file}),
ok = file:close(FD),
ok = file:delete(TmpFile),
- EntityState#xmerl_sax_parser_state.event_state
+ {EntityState#xmerl_sax_parser_state.event_state,
+ EntityState#xmerl_sax_parser_state.ref_table}
+
end
catch
throw:{error, Error} ->
@@ -1709,6 +1799,8 @@ handle_external_entity({http, Url}, State) ->
handle_external_entity({Tag, _Url}, State) ->
?fatal_error(State, "Unsupported URI type: " ++ atom_to_list(Tag)).
+?PARSE_EXTERNAL_ENTITY_BYTE_ORDER_MARK(Bytes, State).
+
%%----------------------------------------------------------------------
%% Function : parse_external_entity_1(Rest, State) -> Result
%% Parameters: Rest = string() | binary()
@@ -1716,22 +1808,15 @@ handle_external_entity({Tag, _Url}, State) ->
%% Result : {Rest, State}
%% Description: Parse the external entity.
%%----------------------------------------------------------------------
--dialyzer({[no_fail_call, no_match], parse_external_entity_1/2}).
parse_external_entity_1(?STRING_EMPTY, #xmerl_sax_parser_state{file_type=Type} = State) ->
case catch cf(?STRING_EMPTY, State, fun parse_external_entity_1/2) of
{Rest, State1} when is_record(State1, xmerl_sax_parser_state) ->
- {Rest, State};
+ {Rest, State1};
{fatal_error, {State1, "No more bytes"}} when Type == dtd; Type == entity ->
{?STRING_EMPTY, State1};
Other ->
throw(Other)
end;
-parse_external_entity_1(?BYTE_ORDER_MARK_1, State) ->
- cf(?BYTE_ORDER_MARK_1, State, fun parse_external_entity_1/2);
-parse_external_entity_1(?BYTE_ORDER_MARK_2, State) ->
- cf(?BYTE_ORDER_MARK_2, State, fun parse_external_entity_1/2);
-parse_external_entity_1(?BYTE_ORDER_MARK_REST(Rest), State) ->
- parse_external_entity_1(Rest, State);
parse_external_entity_1(?STRING("<") = Bytes, State) ->
cf(Bytes, State, fun parse_external_entity_1/2);
parse_external_entity_1(?STRING("<?") = Bytes, State) ->
@@ -2452,24 +2537,24 @@ parse_entity_def(?STRING_EMPTY, State, Name) ->
cf(?STRING_EMPTY, State, Name, fun parse_entity_def/3);
parse_entity_def(?STRING_UNBOUND_REST(C, Rest), State, Name) when C == $'; C == $" ->
{Value, Rest1, State1} = parse_entity_value(Rest, State, C, []),
- insert_reference({Name, internal_general, Value}, State1#xmerl_sax_parser_state.ref_table),
- State2 = event_callback({internalEntityDecl, Name, Value}, State1),
- {_WS, Rest2, State3} = whitespace(Rest1, State2, []),
- parse_def_end(Rest2, State3);
+ State2 = insert_reference(Name, {internal_general, Value}, State1),
+ State3 = event_callback({internalEntityDecl, Name, Value}, State2),
+ {_WS, Rest2, State4} = whitespace(Rest1, State3, []),
+ parse_def_end(Rest2, State4);
parse_entity_def(?STRING_UNBOUND_REST(C, _) = Rest, State, Name) when C == $S; C == $P ->
{PubId, SysId, Rest1, State1} = parse_external_id(Rest, State, false),
{Ndata, Rest2, State2} = parse_ndata(Rest1, State1),
case Ndata of
undefined ->
- insert_reference({Name, external_general, {PubId, SysId}},
- State2#xmerl_sax_parser_state.ref_table),
- State3 = event_callback({externalEntityDecl, Name, PubId, SysId}, State2),
- {Rest2, State3};
+ State3 = insert_reference(Name, {external_general, {PubId, SysId}},
+ State2),
+ State4 = event_callback({externalEntityDecl, Name, PubId, SysId}, State3),
+ {Rest2, State4};
_ ->
- insert_reference({Name, unparsed, {PubId, SysId, Ndata}},
- State2#xmerl_sax_parser_state.ref_table),
- State3 = event_callback({unparsedEntityDecl, Name, PubId, SysId, Ndata}, State2),
- {Rest2, State3}
+ State3 = insert_reference(Name, {unparsed, {PubId, SysId, Ndata}},
+ State2),
+ State4 = event_callback({unparsedEntityDecl, Name, PubId, SysId, Ndata}, State3),
+ {Rest2, State4}
end;
parse_entity_def(Bytes, State, Name) ->
unicode_incomplete_check([Bytes, State, Name, fun parse_entity_def/3],
@@ -2646,19 +2731,19 @@ parse_pe_def(?STRING_EMPTY, State, Name) ->
parse_pe_def(?STRING_UNBOUND_REST(C, Rest), State, Name) when C == $'; C == $" ->
{Value, Rest1, State1} = parse_entity_value(Rest, State, C, []),
Name1 = "%" ++ Name,
- insert_reference({Name1, internal_parameter, Value},
- State1#xmerl_sax_parser_state.ref_table),
- State2 = event_callback({internalEntityDecl, Name1, Value}, State1),
- {_WS, Rest2, State3} = whitespace(Rest1, State2, []),
- parse_def_end(Rest2, State3);
+ State2 = insert_reference(Name1, {internal_parameter, Value},
+ State1),
+ State3 = event_callback({internalEntityDecl, Name1, Value}, State2),
+ {_WS, Rest2, State4} = whitespace(Rest1, State3, []),
+ parse_def_end(Rest2, State4);
parse_pe_def(?STRING_UNBOUND_REST(C, _) = Bytes, State, Name) when C == $S; C == $P ->
{PubId, SysId, Rest1, State1} = parse_external_id(Bytes, State, false),
Name1 = "%" ++ Name,
- insert_reference({Name1, external_parameter, {PubId, SysId}},
- State1#xmerl_sax_parser_state.ref_table),
- State2 = event_callback({externalEntityDecl, Name1, PubId, SysId}, State1),
- {_WS, Rest2, State3} = whitespace(Rest1, State2, []),
- parse_def_end(Rest2, State3);
+ State2 = insert_reference(Name1, {external_parameter, {PubId, SysId}},
+ State1),
+ State3 = event_callback({externalEntityDecl, Name1, PubId, SysId}, State2),
+ {_WS, Rest2, State4} = whitespace(Rest1, State3, []),
+ parse_def_end(Rest2, State4);
parse_pe_def(Bytes, State, Name) ->
unicode_incomplete_check([Bytes, State, Name, fun parse_pe_def/3],
"\", \', SYSTEM or PUBLIC expected").
@@ -3290,7 +3375,7 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C
catch
throw:ErrorTerm ->
?fatal_error(State, ErrorTerm);
- exit:Reason ->
+ exit:Reason ->
?fatal_error(State, {'EXIT', Reason})
end,
case Result of
diff --git a/lib/xmerl/src/xmerl_sax_parser_latin1.erlsrc b/lib/xmerl/src/xmerl_sax_parser_latin1.erlsrc
index 961806bf4c..6e59347fb8 100644
--- a/lib/xmerl/src/xmerl_sax_parser_latin1.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_latin1.erlsrc
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,8 +34,36 @@
-define(APPEND_STRING(Rest, New), <<Rest/binary, New/binary>>).
-define(TO_INPUT_FORMAT(Val), unicode:characters_to_binary(Val, unicode, latin1)).
-%% STRING_REST and STRING_UNBOUND_REST is only different in the list case
-define(STRING_UNBOUND_REST(MatchChar, Rest), <<MatchChar, Rest/binary>>).
--define(BYTE_ORDER_MARK_1, undefined_bom1).
--define(BYTE_ORDER_MARK_2, undefined_bom2).
--define(BYTE_ORDER_MARK_REST(Rest), <<undefined, Rest/binary>>).
+
+-define(PARSE_BYTE_ORDER_MARK(Bytes, State),
+ parse_byte_order_mark(Bytes, State) ->
+ parse_xml_decl(Bytes, State)).
+
+-define(PARSE_XML_DECL(Bytes, State),
+ parse_xml_decl(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, fun parse_xml_decl/2);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])));
+ _ ->
+ parse_prolog(Bytes, State)
+ end;
+ parse_xml_decl(Bytes, State) ->
+ parse_prolog(Bytes, State)).
+
+-define(WHITESPACE(Bytes, State, Acc),
+ whitespace(?STRING_UNBOUND_REST(_C, _) = Bytes, State, Acc) ->
+ {lists:reverse(Acc), Bytes, State};
+ whitespace(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State, Acc) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, Acc, fun whitespace/3);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])))
+ end).
+
+-define(PARSE_EXTERNAL_ENTITY_BYTE_ORDER_MARK(Bytes, State),
+ parse_external_entity_byte_order_mark(Bytes, State) ->
+ parse_external_entity_1(Bytes, State)).
diff --git a/lib/xmerl/src/xmerl_sax_parser_list.erlsrc b/lib/xmerl/src/xmerl_sax_parser_list.erlsrc
index 624a621d92..ac89896215 100644
--- a/lib/xmerl/src/xmerl_sax_parser_list.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_list.erlsrc
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,6 +36,19 @@
%% In the list case we can't use a '++' when matchin against an unbound variable
-define(STRING_UNBOUND_REST(MatchChar, Rest), [MatchChar | Rest]).
--define(BYTE_ORDER_MARK_1, undefined_bom1).
--define(BYTE_ORDER_MARK_2, undefined_bom2).
--define(BYTE_ORDER_MARK_REST(Rest), [undefined|Rest]).
+
+-define(PARSE_BYTE_ORDER_MARK(Bytes, State),
+ parse_byte_order_mark(Bytes, State) ->
+ parse_xml_decl(Bytes, State)).
+
+-define(PARSE_XML_DECL(Bytes, State),
+ parse_xml_decl(Bytes, State) ->
+ parse_prolog(Bytes, State)).
+
+-define(WHITESPACE(Bytes, State, Acc),
+ whitespace(?STRING_UNBOUND_REST(_C, _) = Bytes, State, Acc) ->
+ {lists:reverse(Acc), Bytes, State}).
+
+-define(PARSE_EXTERNAL_ENTITY_BYTE_ORDER_MARK(Bytes, State),
+ parse_external_entity_byte_order_mark(Bytes, State) ->
+ parse_external_entity_1(Bytes, State)).
diff --git a/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc b/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc
index ff84ece97a..ec89024729 100644
--- a/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,8 +34,50 @@
-define(APPEND_STRING(Rest, New), <<Rest/binary, New/binary>>).
-define(TO_INPUT_FORMAT(Val), unicode:characters_to_binary(Val, unicode, {utf16, big})).
-%% STRING_REST and STRING_UNBOUND_REST is only different in the list case
-define(STRING_UNBOUND_REST(MatchChar, Rest), <<MatchChar/big-utf16, Rest/binary>>).
--define(BYTE_ORDER_MARK_1, undefined_bom1).
--define(BYTE_ORDER_MARK_2, <<16#FE>>).
+-define(BYTE_ORDER_MARK_1, <<16#FE>>).
-define(BYTE_ORDER_MARK_REST(Rest), <<16#FE, 16#FF, Rest/binary>>).
+
+-define(PARSE_BYTE_ORDER_MARK(Bytes, State),
+ parse_byte_order_mark(?STRING_EMPTY, State) ->
+ cf(?STRING_EMPTY, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_1, State) ->
+ cf(?BYTE_ORDER_MARK_1, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_REST(Rest), State) ->
+ parse_xml_decl(Rest, State);
+ parse_byte_order_mark(Bytes, State) ->
+ parse_xml_decl(Bytes, State)).
+
+-define(PARSE_XML_DECL(Bytes, State),
+ parse_xml_decl(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, fun parse_xml_decl/2);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])));
+ _ ->
+ parse_prolog(Bytes, State)
+ end;
+ parse_xml_decl(Bytes, State) ->
+ parse_prolog(Bytes, State)).
+
+-define(WHITESPACE(Bytes, State, Acc),
+ whitespace(?STRING_UNBOUND_REST(_C, _) = Bytes, State, Acc) ->
+ {lists:reverse(Acc), Bytes, State};
+ whitespace(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State, Acc) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, Acc, fun whitespace/3);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])))
+ end).
+
+-define(PARSE_EXTERNAL_ENTITY_BYTE_ORDER_MARK(Bytes, State),
+ parse_external_entity_byte_order_mark(?STRING_EMPTY, State) ->
+ cf(?STRING_EMPTY, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_1, State) ->
+ cf(?BYTE_ORDER_MARK_1, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_REST(Rest), State) ->
+ parse_external_entity_1(Rest, State);
+ parse_external_entity_byte_order_mark(Bytes, State) ->
+ parse_external_entity_1(Bytes, State)).
diff --git a/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc b/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc
index a330fce8d0..566333a045 100644
--- a/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,8 +34,50 @@
-define(APPEND_STRING(Rest, New), <<Rest/binary, New/binary>>).
-define(TO_INPUT_FORMAT(Val), unicode:characters_to_binary(Val, unicode, {utf16, little})).
-%% STRING_REST and STRING_UNBOUND_REST is only different in the list case
-define(STRING_UNBOUND_REST(MatchChar, Rest), <<MatchChar/little-utf16, Rest/binary>>).
--define(BYTE_ORDER_MARK_1, undefined_bom1).
--define(BYTE_ORDER_MARK_2, <<16#FF>>).
+-define(BYTE_ORDER_MARK_1, <<16#FF>>).
-define(BYTE_ORDER_MARK_REST(Rest), <<16#FF, 16#FE, Rest/binary>>).
+
+-define(PARSE_BYTE_ORDER_MARK(Bytes, State),
+ parse_byte_order_mark(?STRING_EMPTY, State) ->
+ cf(?STRING_EMPTY, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_1, State) ->
+ cf(?BYTE_ORDER_MARK_1, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_REST(Rest), State) ->
+ parse_xml_decl(Rest, State);
+ parse_byte_order_mark(Bytes, State) ->
+ parse_xml_decl(Bytes, State)).
+
+-define(PARSE_XML_DECL(Bytes, State),
+ parse_xml_decl(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, fun parse_xml_decl/2);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])));
+ _ ->
+ parse_prolog(Bytes, State)
+ end;
+ parse_xml_decl(Bytes, State) ->
+ parse_prolog(Bytes, State)).
+
+-define(WHITESPACE(Bytes, State, Acc),
+ whitespace(?STRING_UNBOUND_REST(_C, _) = Bytes, State, Acc) ->
+ {lists:reverse(Acc), Bytes, State};
+ whitespace(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State, Acc) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, Acc, fun whitespace/3);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])))
+ end).
+
+-define(PARSE_EXTERNAL_ENTITY_BYTE_ORDER_MARK(Bytes, State),
+ parse_external_entity_byte_order_mark(?STRING_EMPTY, State) ->
+ cf(?STRING_EMPTY, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_1, State) ->
+ cf(?BYTE_ORDER_MARK_1, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_REST(Rest), State) ->
+ parse_external_entity_1(Rest, State);
+ parse_external_entity_byte_order_mark(Bytes, State) ->
+ parse_external_entity_1(Bytes, State)).
diff --git a/lib/xmerl/src/xmerl_sax_parser_utf8.erlsrc b/lib/xmerl/src/xmerl_sax_parser_utf8.erlsrc
index d46d60d237..f41d06d013 100644
--- a/lib/xmerl/src/xmerl_sax_parser_utf8.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_utf8.erlsrc
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,11 +34,55 @@
-define(APPEND_STRING(Rest, New), <<Rest/binary, New/binary>>).
-define(TO_INPUT_FORMAT(Val), unicode:characters_to_binary(Val, unicode, utf8)).
-
-%% STRING_REST and STRING_UNBOUND_REST is only different in the list case
-define(STRING_UNBOUND_REST(MatchChar, Rest), <<MatchChar/utf8, Rest/binary>>).
-define(BYTE_ORDER_MARK_1, <<16#EF>>).
-define(BYTE_ORDER_MARK_2, <<16#EF, 16#BB>>).
-define(BYTE_ORDER_MARK_REST(Rest), <<16#EF, 16#BB, 16#BF, Rest/binary>>).
+-define(PARSE_BYTE_ORDER_MARK(Bytes, State),
+ parse_byte_order_mark(?STRING_EMPTY, State) ->
+ cf(?STRING_EMPTY, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_1, State) ->
+ cf(?BYTE_ORDER_MARK_1, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_2, State) ->
+ cf(?BYTE_ORDER_MARK_2, State, fun parse_byte_order_mark/2);
+ parse_byte_order_mark(?BYTE_ORDER_MARK_REST(Rest), State) ->
+ parse_xml_decl(Rest, State);
+ parse_byte_order_mark(Bytes, State) ->
+ parse_xml_decl(Bytes, State)).
+
+-define(PARSE_XML_DECL(Bytes, State),
+ parse_xml_decl(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, fun parse_xml_decl/2);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])));
+ _ ->
+ parse_prolog(Bytes, State)
+ end;
+ parse_xml_decl(Bytes, State) ->
+ parse_prolog(Bytes, State)).
+
+-define(WHITESPACE(Bytes, State, Acc),
+ whitespace(?STRING_UNBOUND_REST(_C, _) = Bytes, State, Acc) ->
+ {lists:reverse(Acc), Bytes, State};
+ whitespace(Bytes, #xmerl_sax_parser_state{encoding=Enc} = State, Acc) when is_binary(Bytes) ->
+ case unicode:characters_to_list(Bytes, Enc) of
+ {incomplete, _, _} ->
+ cf(Bytes, State, Acc, fun whitespace/3);
+ {error, _Encoded, _Rest} ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character, not in ~p\n", [Enc])))
+ end).
+-define(PARSE_EXTERNAL_ENTITY_BYTE_ORDER_MARK(Bytes, State),
+ parse_external_entity_byte_order_mark(?STRING_EMPTY, State) ->
+ cf(?STRING_EMPTY, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_1, State) ->
+ cf(?BYTE_ORDER_MARK_1, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_2, State) ->
+ cf(?BYTE_ORDER_MARK_2, State, fun parse_external_entity_byte_order_mark/2);
+ parse_external_entity_byte_order_mark(?BYTE_ORDER_MARK_REST(Rest), State) ->
+ parse_external_entity_1(Rest, State);
+ parse_external_entity_byte_order_mark(Bytes, State) ->
+ parse_external_entity_1(Bytes, State)).
diff --git a/lib/xmerl/src/xmerl_sax_simple_dom.erl b/lib/xmerl/src/xmerl_sax_simple_dom.erl
index 7eb3afd499..d842bd982b 100644
--- a/lib/xmerl/src/xmerl_sax_simple_dom.erl
+++ b/lib/xmerl/src/xmerl_sax_simple_dom.erl
@@ -129,8 +129,9 @@ build_dom(endDocument,
State#xmerl_sax_simple_dom_state{dom=[Decl, {Tag, Attributes,
lists:reverse(Content)}]};
_ ->
- ?dbg("~p\n", [D]),
- ?error("we're not at end the document when endDocument event is encountered.")
+ %% endDocument is also sent by the parser when a fault occur to tell
+ %% the event receiver that no more input will be sent
+ State
end;
%% Element
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index 2147a46a13..3dd9504f87 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -111,13 +111,16 @@
%% <dd>Set to 'true' if xmerl should add to elements missing attributes
%% with a defined default value (default 'false').</dd>
%% </dl>
+%% @type xmlElement() = #xmlElement{}.
+%% The record definition is found in xmerl.hrl.
+%% @type xmlDocument() = #xmlDocument{}.
+%% The record definition is found in xmerl.hrl.
%% @type document() = xmlElement() | xmlDocument(). <p>
%% The document returned by <tt>xmerl_scan:string/[1,2]</tt> and
%% <tt>xmerl_scan:file/[1,2]</tt>. The type of the returned record depends on
%% the value of the document option passed to the function.
%% </p>
-
-module(xmerl_scan).
-vsn('0.20').
-date('03-09-16').
@@ -2222,16 +2225,18 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook,
AllAttrs =
case S#xmerl_scanner.default_attrs of
true ->
- [ #xmlAttribute{name = AttName,
- parents = [{Name, Pos} | Parents],
- language = Lang,
- nsinfo = NSI,
- namespace = Namespace,
- value = AttValue,
- normalized = true} ||
- {AttName, AttValue} <- get_default_attrs(S, Name),
- AttValue =/= no_value,
- not lists:keymember(AttName, #xmlAttribute.name, Attrs) ];
+ DefaultAttrs =
+ [ #xmlAttribute{name = AttName,
+ parents = [{Name, Pos} | Parents],
+ language = Lang,
+ nsinfo = NSI,
+ namespace = Namespace,
+ value = AttValue,
+ normalized = true} ||
+ {AttName, AttValue} <- get_default_attrs(S, Name),
+ AttValue =/= no_value,
+ not lists:keymember(AttName, #xmlAttribute.name, Attrs) ],
+ lists:append(Attrs, DefaultAttrs);
false ->
Attrs
end,
@@ -2304,7 +2309,9 @@ expanded_name(Name, [], #xmlNamespace{default = URI}, S) ->
expanded_name(Name, N = {"xmlns", Local}, #xmlNamespace{nodes = Ns}, S) ->
{_, Value} = lists:keyfind(Local, 1, Ns),
case Name of
- 'xmlns:xml' when Value =/= 'http://www.w3.org/XML/1998/namespace' ->
+ 'xmlns:xml' when Value =:= 'http://www.w3.org/XML/1998/namespace' ->
+ N;
+ 'xmlns:xml' when Value =/= 'http://www.w3.org/XML/1998/namespace' ->
?fatal({xml_prefix_cannot_be_redeclared, Value}, S);
'xmlns:xmlns' ->
?fatal({xmlns_prefix_cannot_be_declared, Value}, S);
@@ -2318,6 +2325,8 @@ expanded_name(Name, N = {"xmlns", Local}, #xmlNamespace{nodes = Ns}, S) ->
N
end
end;
+expanded_name(_Name, {"xml", Local}, _NS, _S) ->
+ {'http://www.w3.org/XML/1998/namespace', list_to_atom(Local)};
expanded_name(_Name, {Prefix, Local}, #xmlNamespace{nodes = Ns}, S) ->
case lists:keysearch(Prefix, 1, Ns) of
{value, {_, URI}} ->
@@ -2328,9 +2337,6 @@ expanded_name(_Name, {Prefix, Local}, #xmlNamespace{nodes = Ns}, S) ->
?fatal({namespace_prefix_not_declared, Prefix}, S)
end.
-
-
-
keyreplaceadd(K, Pos, [H|T], Obj) when K == element(Pos, H) ->
[Obj|T];
keyreplaceadd(K, Pos, [H|T], Obj) ->
diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl
index bbebda1030..6146feba49 100644
--- a/lib/xmerl/src/xmerl_xpath.erl
+++ b/lib/xmerl/src/xmerl_xpath.erl
@@ -43,13 +43,27 @@
%% </pre>
%%
%% @type nodeEntity() =
-%% xmlElement()
-%% | xmlAttribute()
-%% | xmlText()
-%% | xmlPI()
-%% | xmlComment()
-%% | xmlNsNode()
-%% | xmlDocument()
+%% #xmlElement{}
+%% | #xmlAttribute{}
+%% | #xmlText{}
+%% | #xmlPI{}
+%% | #xmlComment{}
+%% | #xmlNsNode{}
+%% | #xmlDocument{}
+%%
+%% @type docNodes() = #xmlElement{}
+%% | #xmlAttribute{}
+%% | #xmlText{}
+%% | #xmlPI{}
+%% | #xmlComment{}
+%% | #xmlNsNode{}
+%%
+%% @type docEntity() = #xmlDocument{} | [docNodes()]
+%%
+%% @type xPathString() = string()
+%%
+%% @type parentList() = [{atom(), integer()}]
+%%
%% @type option_list(). <p>Options allows to customize the behaviour of the
%% XPath scanner.
%% </p>
@@ -115,7 +129,7 @@ string(Str, Doc, Options) ->
%% Parents = parentList()
%% Doc = nodeEntity()
%% Options = option_list()
-%% Scalar = xmlObj
+%% Scalar = #xmlObj{}
%% @doc Extracts the nodes from the parsed XML tree according to XPath.
%% xmlObj is a record with fields type and value,
%% where type is boolean | number | string
diff --git a/lib/xmerl/src/xmerl_xs.erl b/lib/xmerl/src/xmerl_xs.erl
index 3e9f6622b8..1ce76cfa41 100644
--- a/lib/xmerl/src/xmerl_xs.erl
+++ b/lib/xmerl/src/xmerl_xs.erl
@@ -45,7 +45,6 @@
% XSLT package which is written i C++.
% See also the <a href="xmerl_xs_examples.html">Tutorial</a>.
% </p>
-
-module(xmerl_xs).
-export([xslapply/2, value_of/1, select/2, built_in_rules/2 ]).
@@ -71,15 +70,13 @@
%% xslapply(fun template/1, E),
%% "&lt;/h1>"];
%% </pre>
-
xslapply(Fun, EList) when is_list(EList) ->
- lists:map( Fun, EList);
+ lists:map(Fun, EList);
xslapply(Fun, E = #xmlElement{})->
lists:map( Fun, E#xmlElement.content).
-
%% @spec value_of(E) -> List
-%% E = unknown()
+%% E = term()
%%
%% @doc Concatenates all text nodes within the tree.
%%
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index 4b5efae8dd..a89b3159ec 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -49,6 +49,7 @@
%% <dd>It is possible by this option to provide a state with process
%% information from an earlier validation.</dd>
%% </dl>
+%% @type filename() = string()
%% @end
%%%-------------------------------------------------------------------
-module(xmerl_xsd).
@@ -138,7 +139,7 @@ state2file(S=#xsd_state{schema_name=SN}) ->
%% @spec state2file(State,FileName) -> ok | {error,Reason}
%% State = global_state()
-%% FileName = filename()
+%% FileName = string()
%% @doc Saves the schema state with all information of the processed
%% schema in a file. You can provide the file name for the saved
%% state. FileName is saved with the <code>.xss</code> extension
@@ -153,7 +154,7 @@ state2file(S,FileName) when is_record(S,xsd_state) ->
%% @spec file2state(FileName) -> {ok,State} | {error,Reason}
%% State = global_state()
-%% FileName = filename()
+%% FileName = string()
%% @doc Reads the schema state with all information of the processed
%% schema from a file created with <code>state2file/[1,2]</code>. The
%% format of this file is internal. The state can then be used
@@ -202,7 +203,7 @@ xmerl_xsd_vsn_check(S=#xsd_state{vsn=MD5_VSN}) ->
process_validate(Schema,Xml) ->
process_validate(Schema,Xml,[]).
%% @spec process_validate(Schema,Element,Options) -> Result
-%% Schema = filename()
+%% Schema = string()
%% Element = XmlElement
%% Options = option_list()
%% Result = {ValidXmlElement,State} | {error,Reason}
@@ -282,7 +283,7 @@ validate3(_,_,S) ->
process_schema(Schema) ->
process_schema(Schema,[]).
%% @spec process_schema(Schema,Options) -> Result
-%% Schema = filename()
+%% Schema = string()
%% Result = {ok,State} | {error,Reason}
%% State = global_state()
%% Reason = [ErrorReason] | ErrorReason
@@ -324,7 +325,7 @@ process_schema2({SE,_},State,_Schema) ->
process_schemas(Schemas) ->
process_schemas(Schemas,[]).
%% @spec process_schemas(Schemas,Options) -> Result
-%% Schemas = [{NameSpace,filename()}|Schemas] | []
+%% Schemas = [{NameSpace,string()}|Schemas] | []
%% Result = {ok,State} | {error,Reason}
%% Reason = [ErrorReason] | ErrorReason
%% Options = option_list()
@@ -5426,7 +5427,7 @@ add_key_once(Key,N,El,L) ->
%% {filename:join([[io_lib:format("/~w(~w)",[X,Y])||{X,Y}<-Parents],Type]),Pos}.
%% @spec format_error(Errors) -> Result
-%% Errors = error_tuple() | [error_tuple()]
+%% Errors = tuple() | [tuple()]
%% Result = string() | [string()]
%% @doc Formats error descriptions to human readable strings.
format_error(L) when is_list(L) ->
diff --git a/lib/xmerl/test/Makefile b/lib/xmerl/test/Makefile
index 7a326e334f..3204f081ba 100644
--- a/lib/xmerl/test/Makefile
+++ b/lib/xmerl/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -55,7 +55,8 @@ SUITE_FILES= \
xmerl_xsd_SUITE.erl \
xmerl_xsd_MS2002-01-16_SUITE.erl \
xmerl_xsd_NIST2002-01-16_SUITE.erl \
- xmerl_xsd_Sun2002-01-16_SUITE.erl
+ xmerl_xsd_Sun2002-01-16_SUITE.erl \
+ xmerl_sax_stream_SUITE.erl
XML_FILES= \
testcases.dtd \
@@ -125,4 +126,6 @@ release_tests_spec: opt
@tar cfh - xmerl_xsd_MS2002-01-16_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
@tar cfh - xmerl_xsd_NIST2002-01-16_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
@tar cfh - xmerl_xsd_Sun2002-01-16_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_sax_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_sax_stream_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
chmod -R u+w "$(RELSYSDIR)"
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index e97b8c6a4b..e7e3b3c2b1 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -54,7 +54,8 @@ groups() ->
cpd_expl_provided_DTD]},
{misc, [],
[latin1_alias, syntax_bug1, syntax_bug2, syntax_bug3,
- pe_ref1, copyright, testXSEIF, export_simple1, export]},
+ pe_ref1, copyright, testXSEIF, export_simple1, export,
+ default_attrs_bug, xml_ns]},
{eventp_tests, [], [sax_parse_and_export]},
{ticket_tests, [],
[ticket_5998, ticket_7211, ticket_7214, ticket_7430,
@@ -223,6 +224,50 @@ syntax_bug3(Config) ->
Err -> Err
end.
+default_attrs_bug(Config) ->
+ file:set_cwd(datadir(Config)),
+ Doc = "<!DOCTYPE doc [<!ATTLIST doc b CDATA \"default\">]>\n"
+ "<doc a=\"explicit\"/>",
+ {#xmlElement{attributes = [#xmlAttribute{name = a, value = "explicit"},
+ #xmlAttribute{name = b, value = "default"}]},
+ []
+ } = xmerl_scan:string(Doc, [{default_attrs, true}]),
+ Doc2 = "<!DOCTYPE doc [<!ATTLIST doc b CDATA \"default\">]>\n"
+ "<doc b=\"also explicit\" a=\"explicit\"/>",
+ {#xmlElement{attributes = [#xmlAttribute{name = b, value = "also explicit"},
+ #xmlAttribute{name = a, value = "explicit"}]},
+ []
+ } = xmerl_scan:string(Doc2, [{default_attrs, true}]),
+ ok.
+
+
+xml_ns(Config) ->
+ Doc = "<?xml version='1.0'?>\n"
+ "<doc xml:attr1=\"implicit xml ns\"/>",
+ {#xmlElement{namespace=#xmlNamespace{default = [], nodes = []},
+ attributes = [#xmlAttribute{name = 'xml:attr1',
+ expanded_name = {'http://www.w3.org/XML/1998/namespace',attr1},
+ nsinfo = {"xml","attr1"},
+ namespace = #xmlNamespace{default = [], nodes = []}}]},
+ []
+ } = xmerl_scan:string(Doc, [{namespace_conformant, true}]),
+ Doc2 = "<?xml version='1.0'?>\n"
+ "<doc xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" xml:attr1=\"explicit xml ns\"/>",
+ {#xmlElement{namespace=#xmlNamespace{default = [], nodes = [{"xml",'http://www.w3.org/XML/1998/namespace'}]},
+ attributes = [#xmlAttribute{name = 'xmlns:xml',
+ expanded_name = {"xmlns","xml"},
+ nsinfo = {"xmlns","xml"},
+ namespace = #xmlNamespace{default = [],
+ nodes = [{"xml",'http://www.w3.org/XML/1998/namespace'}]}},
+ #xmlAttribute{name = 'xml:attr1',
+ expanded_name = {'http://www.w3.org/XML/1998/namespace',attr1},
+ nsinfo = {"xml","attr1"},
+ namespace = #xmlNamespace{default = [],
+ nodes = [{"xml",'http://www.w3.org/XML/1998/namespace'}]}}]},
+ []
+ } = xmerl_scan:string(Doc2, [{namespace_conformant, true}]),
+ ok.
+
pe_ref1(Config) ->
file:set_cwd(datadir(Config)),
{#xmlElement{},[]} = xmerl_scan:file(datadir_join(Config,[misc,"PE_ref1.xml"]),[{validation,true}]).
diff --git a/lib/xmerl/test/xmerl_sax_SUITE.erl b/lib/xmerl/test/xmerl_sax_SUITE.erl
index f5c0a783c4..68b9bcc4a2 100644
--- a/lib/xmerl/test/xmerl_sax_SUITE.erl
+++ b/lib/xmerl/test/xmerl_sax_SUITE.erl
@@ -2,7 +2,7 @@
%%----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@
%%======================================================================
%% External functions
%%======================================================================
-
%%----------------------------------------------------------------------
%% Initializations
%%----------------------------------------------------------------------
@@ -42,12 +41,15 @@ all() ->
[{group, bugs}].
groups() ->
- [{bugs, [], [ticket_8213, ticket_8214, ticket_11551]}].
+ [{bugs, [], [ticket_8213, ticket_8214, ticket_11551,
+ fragmented_xml_directive,
+ old_dom_event_fun_endDocument_bug,
+ event_fun_endDocument_error_test,
+ event_fun_startDocument_error_test]}].
-%%----------------------------------------------------------------------
+%%======================================================================
%% Tests
-%%----------------------------------------------------------------------
-
+%%======================================================================
%%----------------------------------------------------------------------
%% Test Case
%% ID: ticket_8213
@@ -56,7 +58,6 @@ ticket_8213(_Config) ->
{ok,ok,[]} = xmerl_sax_parser:stream("<elem/>", [{event_fun, fun (_E,_,_) -> ok end}]),
ok.
-
%%----------------------------------------------------------------------
%% Test Case
%% ID: ticket_8214
@@ -85,17 +86,80 @@ ticket_11551(_Config) ->
<a>hej</a>
<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<a>hej</a>">>,
- {ok, undefined, <<"<?xml", _/binary>>} = xmerl_sax_parser:stream(Stream1, []),
+ {ok, undefined, <<"\n<?xml", _/binary>>} = xmerl_sax_parser:stream(Stream1, []),
Stream2= <<"<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<a>hej</a>
<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<a>hej</a>">>,
- {ok, undefined, <<"<?xml", _/binary>>} = xmerl_sax_parser:stream(Stream2, []),
+ {ok, undefined, <<"\n\n\n<?xml", _/binary>>} = xmerl_sax_parser:stream(Stream2, []),
Stream3= <<"<a>hej</a>
<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<a>hej</a>">>,
- {ok, undefined, <<"<?xml", _/binary>>} = xmerl_sax_parser:stream(Stream3, []),
+ {ok, undefined, <<"\n\n<?xml", _/binary>>} = xmerl_sax_parser:stream(Stream3, []),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Test Case
+%% ID: fragmented_xml_directive
+%% Test of fragmented xml directive by reading one byte per continuation ca
+fragmented_xml_directive(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Name = filename:join(DataDir, "test_data_1.xml"),
+ {ok, Fd} = file:open(Name, [raw, read,binary]),
+ Cf = fun cf_fragmented_xml_directive/1,
+ {ok, undefined, _} = xmerl_sax_parser:stream(<<>>,
+ [{continuation_fun, Cf},
+ {continuation_state, Fd}]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Test Case
+%% ID: old_dom_event_fun_endDocument_bug
+%% The old_dom backend previous generateded an uncatched exception
+%% instead of the correct fatal_error from the parser.
+old_dom_event_fun_endDocument_bug(_Config) ->
+ %% Stream contains bad characters,
+ {fatal_error, _, _, _, _} =
+ xmerl_sax_parser:stream([60,63,120,109,108,32,118,101,114,115,105,111,110,61,39,49,46,48,39,32,101,110,99,111,100,105,110,103,61,39,117,116,102,45,56,39,63,62,60,
+ 99,111,109,109,97,110,100,62,60,104,101,97,100,101,114,62,60,116,114,97,110,115,97,99,116,105,111,110,73,100,62,49,60,47,116,114,97,110,
+ 115,97,99,116,105,111,110,73,100,62,60,47,104,101,97,100,101,114,62,60,98,111,100,121,62,95,226,130,172,59,60,60,47,98,111,100,121,62,60,
+ 47,99,111,109,109,97,110,100,62,60,47,120,49,95,49,62],
+ [{event_fun,fun xmerl_sax_old_dom:event/3},
+ {event_state,xmerl_sax_old_dom:initial_state()}]),
ok.
+
+%%----------------------------------------------------------------------
+%% Test Case
+%% ID: event_fun_endDocument_error_test
+event_fun_endDocument_error_test(_Config) ->
+ Stream = <<"<?xml version=\"1.0\" encoding=\"utf-8\"?><a>hej</a>">>,
+ Ef = fun(endDocument, _ , _) -> throw({event_error, "endDocument error"});
+ (_, _, S) -> S
+ end,
+ {event_error, _, _, _, _} = xmerl_sax_parser:stream(Stream, [{event_fun, Ef}]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Test Case
+%% ID: event_fun_startDocument_error_test
+event_fun_startDocument_error_test(_Config) ->
+ Stream = <<"<?xml version=\"1.0\" encoding=\"utf-8\"?><a>hej</a>">>,
+ Ef = fun(startDocument, _ , _) -> throw({event_error, "endDocument error"});
+ (_, _, S) -> S
+ end,
+ {event_error, _, _, _, _} = xmerl_sax_parser:stream(Stream, [{event_fun, Ef}]),
+ ok.
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+cf_fragmented_xml_directive(IoDevice) ->
+ case file:read(IoDevice, 1) of
+ eof ->
+ {<<>>, IoDevice};
+ {ok, FileBin} ->
+ {FileBin, IoDevice}
+ end.
diff --git a/lib/xmerl/test/xmerl_sax_SUITE_data/test_data_1.xml b/lib/xmerl/test/xmerl_sax_SUITE_data/test_data_1.xml
new file mode 100644
index 0000000000..efbaee6b81
--- /dev/null
+++ b/lib/xmerl/test/xmerl_sax_SUITE_data/test_data_1.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<a>
+Hej
+</a>
diff --git a/lib/xmerl/test/xmerl_sax_std_SUITE.erl b/lib/xmerl/test/xmerl_sax_std_SUITE.erl
index 525a3b175a..b8412206cc 100644
--- a/lib/xmerl/test/xmerl_sax_std_SUITE.erl
+++ b/lib/xmerl/test/xmerl_sax_std_SUITE.erl
@@ -2,7 +2,7 @@
%%----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -507,11 +507,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-036'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/036.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"Illegal data\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -522,11 +519,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-037'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/037.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"&#32;\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -561,11 +555,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-040'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/040.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"<doc></doc>\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -576,11 +567,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-041'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/041.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"<doc></doc>\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -603,11 +591,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-043'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/043.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"Illegal data\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -618,11 +603,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-044'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/044.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"<doc/>\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -669,11 +651,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-048'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/048.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"<![CDATA[]]>\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -1416,11 +1395,8 @@ end_per_testcase(_Func,_Config) ->
'not-wf-sa-110'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"xmltest","not-wf/sa/110.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"&e;\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -1914,9 +1890,9 @@ end_per_testcase(_Func,_Config) ->
%% Special case becase we returns everything after a legal document
%% as an rest instead of giving and error to let the user handle
%% multipple docs on a stream.
- {ok,_,<<"<?xml version=\"1.0\"?>\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- % R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
- % check_result(R, "not-wf").
+ %{ok,_,<<"<?xml version=\"1.0\"?>\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -7784,11 +7760,8 @@ end_per_testcase(_Func,_Config) ->
'o-p01fail3'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"oasis","p01fail3.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_, <<"<bad/>", _/binary>>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -11417,12 +11390,8 @@ end_per_testcase(_Func,_Config) ->
'ibm-not-wf-P01-ibm01n02'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"ibm","not-wf/P01/ibm01n02.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_, <<"<?xml version=\"1.0\"?>", _/binary>>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- % R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
- % check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Case
@@ -11433,11 +11402,8 @@ end_per_testcase(_Func,_Config) ->
'ibm-not-wf-P01-ibm01n03'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"ibm","not-wf/P01/ibm01n03.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_, <<"<title>Wrong combination!</title>", _/binary>>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Cases
@@ -13027,11 +12993,8 @@ end_per_testcase(_Func,_Config) ->
'ibm-not-wf-P27-ibm27n01'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"ibm","not-wf/P27/ibm27n01.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_, <<"<!ELEMENT cat EMPTY>">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Cases
@@ -13461,11 +13424,8 @@ end_per_testcase(_Func,_Config) ->
'ibm-not-wf-P39-ibm39n06'(Config) ->
file:set_cwd(xmerl_test_lib:get_data_dir(Config)),
Path = filename:join([xmerl_test_lib:get_data_dir(Config),"ibm","not-wf/P39/ibm39n06.xml"]),
- %% Special case becase we returns everything after a legal document
- %% as an rest instead of giving and error to let the user handle
- %% multipple docs on a stream.
- {ok,_,<<"content after end tag\r\n">>} = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]).
- %%check_result(R, "not-wf").
+ R = xmerl_sax_parser:file(Path, [{event_fun, fun(_,_,S) -> S end}]),
+ check_result(R, "not-wf").
%%----------------------------------------------------------------------
%% Test Cases
diff --git a/lib/xmerl/test/xmerl_sax_stream_SUITE.erl b/lib/xmerl/test/xmerl_sax_stream_SUITE.erl
new file mode 100644
index 0000000000..7315f67374
--- /dev/null
+++ b/lib/xmerl/test/xmerl_sax_stream_SUITE.erl
@@ -0,0 +1,260 @@
+%%-*-erlang-*-
+%%----------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%----------------------------------------------------------------------
+%% File : xmerl_sax_stream_SUITE.erl
+%%----------------------------------------------------------------------
+-module(xmerl_sax_stream_SUITE).
+-compile(export_all).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/file.hrl").
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Initializations
+%%----------------------------------------------------------------------
+all() ->
+ [
+ one_document,
+ two_documents,
+ one_document_and_junk,
+ end_of_stream
+ ].
+
+%%----------------------------------------------------------------------
+%% Initializations
+%%----------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_Func, _Config) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% Tests
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Send One doc over stream
+one_document(Config) ->
+ Port = 11111,
+
+ {ok, ListenSocket} = listen(Port),
+ Self = self(),
+
+ spawn(
+ fun() ->
+ case catch gen_tcp:accept(ListenSocket) of
+ {ok, S} ->
+ Result = xmerl_sax_parser:stream(<<>>,
+ [{continuation_state, S},
+ {continuation_fun,
+ fun(Sd) ->
+ io:format("Continuation called!!", []),
+ case gen_tcp:recv(Sd, 0) of
+ {ok, Packet} ->
+ io:format("Packet: ~p\n", [Packet]),
+ {Packet, Sd};
+ {error, Reason} ->
+ throw({error, Reason})
+ end
+ end}]),
+ Self ! {xmerl_sax, Result},
+ close(S);
+ Error ->
+ Self ! {xmerl_sax, {error, {accept, Error}}}
+ end
+ end),
+
+ {ok, SendSocket} = connect(localhost, Port),
+
+ {ok, Binary} = file:read_file(filename:join([datadir(Config), "xmerl_sax_stream_one.xml"])),
+
+ send_chunks(SendSocket, Binary),
+
+ receive
+ {xmerl_sax, {ok, undefined, Rest}} ->
+ <<"\n">> = Rest,
+ io:format("Ok Rest: ~p\n", [Rest])
+ after 5000 ->
+ ct:fail("Timeout")
+ end,
+ ok.
+
+%%----------------------------------------------------------------------
+%% Send Two doc over stream
+two_documents(Config) ->
+ Port = 11111,
+
+ {ok, ListenSocket} = listen(Port),
+ Self = self(),
+
+ spawn(
+ fun() ->
+ case catch gen_tcp:accept(ListenSocket) of
+ {ok, S} ->
+ Result = xmerl_sax_parser:stream(<<>>,
+ [{continuation_state, S},
+ {continuation_fun,
+ fun(Sd) ->
+ io:format("Continuation called!!", []),
+ case gen_tcp:recv(Sd, 0) of
+ {ok, Packet} ->
+ io:format("Packet: ~p\n", [Packet]),
+ {Packet, Sd};
+ {error, Reason} ->
+ throw({error, Reason})
+ end
+ end}]),
+ Self ! {xmerl_sax, Result},
+ close(S);
+ Error ->
+ Self ! {xmerl_sax, {error, {accept, Error}}}
+ end
+ end),
+
+ {ok, SendSocket} = connect(localhost, Port),
+
+ {ok, Binary} = file:read_file(filename:join([datadir(Config), "xmerl_sax_stream_two.xml"])),
+
+ send_chunks(SendSocket, Binary),
+
+ receive
+ {xmerl_sax, {ok, undefined, Rest}} ->
+ <<"\n<?x", _R/binary>> = Rest,
+ io:format("Ok Rest: ~p\n", [Rest])
+ after 5000 ->
+ ct:fail("Timeout")
+ end,
+ ok.
+
+%%----------------------------------------------------------------------
+%% Send one doc and then junk on stream
+one_document_and_junk(Config) ->
+ Port = 11111,
+
+ {ok, ListenSocket} = listen(Port),
+ Self = self(),
+
+ spawn(
+ fun() ->
+ case catch gen_tcp:accept(ListenSocket) of
+ {ok, S} ->
+ Result = xmerl_sax_parser:stream(<<>>,
+ [{continuation_state, S},
+ {continuation_fun,
+ fun(Sd) ->
+ io:format("Continuation called!!", []),
+ case gen_tcp:recv(Sd, 0) of
+ {ok, Packet} ->
+ io:format("Packet: ~p\n", [Packet]),
+ {Packet, Sd};
+ {error, Reason} ->
+ throw({error, Reason})
+ end
+ end}]),
+ Self ! {xmerl_sax, Result},
+ close(S);
+ Error ->
+ Self ! {xmerl_sax, {error, {accept, Error}}}
+ end
+ end),
+
+ {ok, SendSocket} = connect(localhost, Port),
+
+ {ok, Binary} = file:read_file(filename:join([datadir(Config), "xmerl_sax_stream_one_junk.xml"])),
+
+ send_chunks(SendSocket, Binary),
+
+ receive
+ {xmerl_sax, {ok, undefined, Rest}} ->
+ <<"\nth", _R/binary>> = Rest,
+ io:format("Ok Rest: ~p\n", [Rest])
+ after 10000 ->
+ ct:fail("Timeout")
+ end,
+ ok.
+
+%%----------------------------------------------------------------------
+%% Test of continuation when end of stream
+end_of_stream(Config) ->
+ Stream = <<"<?xml version=\"1.0\" encoding=\"utf-8\"?><a>hej</a>">>,
+ {ok, undefined, <<>>} = xmerl_sax_parser:stream(Stream, []),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Utility functions
+%%----------------------------------------------------------------------
+listen(Port) ->
+ case catch gen_tcp:listen(Port, [{active, false},
+ binary,
+ {keepalive, true},
+ {reuseaddr,true}]) of
+ {ok, ListenSocket} ->
+ {ok, ListenSocket};
+ {error, Reason} ->
+ {error, {listen, Reason}}
+ end.
+
+close(Socket) ->
+ (catch gen_tcp:close(Socket)).
+
+connect(Host, Port) ->
+ Timeout = 5000,
+ % Options1 = check_options(Options),
+ Options = [binary],
+ case catch gen_tcp:connect(Host, Port, Options, Timeout) of
+ {ok, Socket} ->
+ {ok, Socket};
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+send_chunks(Socket, Binary) ->
+ BSize = erlang:size(Binary),
+ if
+ BSize > 25 ->
+ <<Head:25/binary, Tail/binary>> = Binary,
+ case gen_tcp:send(Socket, Head) of
+ ok ->
+ timer:sleep(1000),
+ send_chunks(Socket, Tail);
+ {error,closed} ->
+ ok
+ end;
+ true ->
+ gen_tcp:send(Socket, Binary)
+ end.
+
+datadir(Config) ->
+ proplists:get_value(data_dir, Config).
diff --git a/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one.xml b/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one.xml
new file mode 100644
index 0000000000..30328bb188
--- /dev/null
+++ b/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<person>
+<name>
+Arne Andersson
+</name>
+<address>
+<street>
+ Old Road 456
+</street>
+<zip>
+12323
+</zip>
+<city>
+Small City
+</city>
+</address>
+</person>
diff --git a/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one_junk.xml b/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one_junk.xml
new file mode 100644
index 0000000000..f730a95865
--- /dev/null
+++ b/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_one_junk.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<person>
+<name>
+Arne Andersson
+</name>
+<address>
+<street>
+ Old Road 456
+</street>
+<zip>
+12323
+</zip>
+<city>
+Small City
+</city>
+</address>
+</person>
+this is junk ......
diff --git a/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_two.xml b/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_two.xml
new file mode 100644
index 0000000000..e241a02190
--- /dev/null
+++ b/lib/xmerl/test/xmerl_sax_stream_SUITE_data/xmerl_sax_stream_two.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<person>
+<name>
+Arne Andersson
+</name>
+<address>
+<street>
+ Old Road 456
+</street>
+<zip>
+12323
+</zip>
+<city>
+Small City
+</city>
+</address>
+</person>
+<?xml version="1.0"?>
+<person>
+<name>
+Bertil Bengtson
+</name>
+<address>
+<street>
+ New Road 4
+</street>
+<zip>
+12328
+</zip>
+<city>
+Small City
+</city>
+</address>
+</person>
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index a78a035a1f..4e741d59a8 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.11
+XMERL_VSN = 1.3.14